Browse Source

feat: update

0225172 7 months ago
parent
commit
00925189d1
53 changed files with 1259 additions and 900 deletions
  1. 0 42
      server/case/promise.js
  2. 0 106
      server/import/BoleMbti.js
  3. 0 1
      server/import/libai/.gitignore
  4. 0 56
      server/import/libai/README.md
  5. 0 297
      server/import/libai/href.js
  6. 0 60
      server/import/libai/import.js
  7. 0 197
      server/import/libai/package-lock.json
  8. 0 14
      server/import/libai/package.json
  9. 25 5
      server/rest.js
  10. 27 3
      src/app/app-routing.module.ts
  11. 9 32
      src/app/tab1/tab1.page.html
  12. 45 44
      src/app/tab1/tab1.page.scss
  13. 6 1
      src/app/tab1/tab1.page.ts
  14. 39 41
      src/app/tab2/tab2.page.html
  15. 62 0
      src/app/tab2/tab2.page.scss
  16. 21 1
      src/app/tab2/tab2.page.ts
  17. 12 0
      src/modules/aigc/aigc-routing.module.ts
  18. 14 0
      src/modules/aigc/aigc.module.ts
  19. 17 0
      src/modules/aigc/chat/chat-routing.module.ts
  20. 20 0
      src/modules/aigc/chat/chat.module.ts
  21. 24 0
      src/modules/aigc/chat/chat.page.html
  22. 0 0
      src/modules/aigc/chat/chat.page.scss
  23. 17 0
      src/modules/aigc/chat/chat.page.spec.ts
  24. 31 0
      src/modules/aigc/chat/chat.page.ts
  25. 99 0
      src/modules/aigc/chat/class-chat-completion.ts
  26. 163 0
      src/modules/study/case-js-module/case-parse-petmarket/README.md
  27. 17 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket-routing.module.ts
  28. 20 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.module.ts
  29. 32 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.html
  30. 10 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.scss
  31. 17 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.spec.ts
  32. 36 0
      src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.ts
  33. 27 0
      src/modules/study/case-js-module/case-parse-petmarket/pet.service.ts
  34. 49 0
      src/modules/study/case-js-module/case-parse/README.md
  35. 17 0
      src/modules/study/case-js-module/case-parse/case-parse-routing.module.ts
  36. 20 0
      src/modules/study/case-js-module/case-parse/case-parse.module.ts
  37. 18 0
      src/modules/study/case-js-module/case-parse/case-parse.page.html
  38. 5 0
      src/modules/study/case-js-module/case-parse/case-parse.page.scss
  39. 17 0
      src/modules/study/case-js-module/case-parse/case-parse.page.spec.ts
  40. 28 0
      src/modules/study/case-js-module/case-parse/case-parse.page.ts
  41. 71 0
      src/modules/study/case-js-module/case-pet-detail/README.md
  42. 17 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail-routing.module.ts
  43. 20 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail.module.ts
  44. 18 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.html
  45. 0 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.scss
  46. 17 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.spec.ts
  47. 32 0
      src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.ts
  48. 17 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit-routing.module.ts
  49. 20 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit.module.ts
  50. 26 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.html
  51. 0 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.scss
  52. 17 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.spec.ts
  53. 60 0
      src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.ts

+ 0 - 42
server/case/promise.js

@@ -1,42 +0,0 @@
-
-async function main(){
-    // setTimeout(() => {
-    //     console.log(1)
-    // }, 500);
-    // setTimeout(() => {
-    //     console.log(2)
-    // }, 200);
-    // setTimeout(() => {
-    //     console.log(3)
-    // }, 100);
-    // setTimeout(() => {
-    //     console.log(4)
-    // }, 1000);
-    // return
-
-    // waitSeconds(500,()=>{console.log(1)}) // 500
-    // waitSeconds(200,()=>{console.log(2)}) // 700
-    // waitSeconds(100,()=>{console.log(3)}) // 800
-    // waitSeconds(1000,()=>{console.log(4)}) // 1800
-    // return
-    
-    let res1 = await waitSeconds(500,()=>{console.log(1)}) // 500
-    console.log(res1)
-    let res2 = await waitSeconds(200,()=>{console.log(2)}) // 700
-    console.log(res2)
-    let res3 = await waitSeconds(100,()=>{console.log(3)}) // 800
-    console.log(res3)
-    let res4 = await waitSeconds(1000,()=>{console.log(4)}) // 1800
-    console.log(res4)
-}
-
-function waitSeconds(duration,handle) {
-    return new Promise((resolve, reject) => {
-        setTimeout(() => {
-            handle()
-            resolve(`等待了${duration}ms`);
-        }, duration);
-    });
-}
-
-main()

+ 0 - 106
server/import/BoleMbti.js

@@ -1,106 +0,0 @@
-// 导入BoleMbti脚本
-
-// 引用Parse JS SDK
-const Parse = require("parse/node");
-Parse.initialize("dev"); // 设置applicationId
-Parse.serverURL = "http://web2023.fmode.cn:9999/parse"; // 设置serverURL
-
-let mbtiData = {
-    "ISTJ": {
-        "personality": "ISTJ - 守护者",
-        "suitable_jobs": ["会计师", "行政助理", "工程师"]
-    },
-    "ISFJ": {
-        "personality": "ISFJ - 慈爱者",
-        "suitable_jobs": ["护士", "社会工作者", "图书管理员"]
-    },
-    "INFJ": {
-        "personality": "INFJ - 门徒",
-        "suitable_jobs": ["心理学家", "作家", "艺术家"]
-    },
-    "INTJ": {
-        "personality": "INTJ - 学者",
-        "suitable_jobs": ["科学家", "律师", "企业家"]
-    },
-    "ISTP": {
-        "personality": "ISTP - 冒险家",
-        "suitable_jobs": ["机械师", "飞行员", "摄影师"]
-    },
-    "ISFP": {
-        "personality": "ISFP - 艺术家",
-        "suitable_jobs": ["插画师", "音乐家", "花艺设计师"]
-    },
-    "INFP": {
-        "personality": "INFP - 梦想家",
-        "suitable_jobs": ["心理咨询师", "作家", "教师"]
-    },
-    "INTP": {
-        "personality": "INTP - 学者",
-        "suitable_jobs": ["程序员", "研究员", "工程师"]
-    },
-    "ESTP": {
-        "personality": "ESTP - 实干家",
-        "suitable_jobs": ["销售员", "运动员", "警察"]
-    },
-    "ESFP": {
-        "personality": "ESFP - 表演者",
-        "suitable_jobs": ["演员", "主持人", "舞蹈编导"]
-    },
-    "ENFP": {
-        "personality": "ENFP - 公关者",
-        "suitable_jobs": ["市场营销专员", "活动策划师", "公关顾问"]
-    },
-    "ENTP": {
-        "personality": "ENTP - 挑战者",
-        "suitable_jobs": ["企业顾问", "律师", "投资者"]
-    },
-    "ESTJ": {
-        "personality": "ESTJ - 主管",
-        "suitable_jobs": ["项目经理", "军官", "警察"]
-    },
-    "ESFJ": {
-        "personality": "ESFJ - 供应者",
-        "suitable_jobs": ["教育工作者", "医生", "社会工作者"]
-    },
-    "ENFJ": {
-        "personality": "ENFJ - 慈善家",
-        "suitable_jobs": ["心理咨询师", "教育家", "公益组织工作者"]
-    },
-    "ENTJ": {
-        "personality": "ENTJ - 指挥官",
-        "suitable_jobs": ["CEO", "政治家", "项目经理"]
-    }
-}
-
-function importAll(){
-    let MbtiList = []
-    Object.keys(mbtiData).forEach(key=>{
-        MbtiList.push({
-            result:key,
-            personality:mbtiData[key]?.personality,
-            suitableJobs:mbtiData[key]?.suitable_jobs,
-        })
-    })
-
-    console.log(MbtiList)
-    MbtiList.forEach(async mbti => {
-        // 查重
-        let exists = await checkExists(mbti)
-        if(exists?.id) return;
-        // 新增
-        let BoleMbti = Parse.Object.extend("BoleMbti");
-        let bm = new BoleMbti();
-        bm.set(mbti);
-        bm.save();
-    });
-}
-
-async function checkExists(mbti){
-    let query = new Parse.Query("BoleMbti");
-    query.equalTo("result",mbti?.result);
-    query.equalTo("personality",mbti?.personality);
-    await query.first();
-    return await query.first();
-}
-
-importAll()

+ 0 - 1
server/import/libai/.gitignore

@@ -1 +0,0 @@
-node_modules/

+ 0 - 56
server/import/libai/README.md

@@ -1,56 +0,0 @@
-# 示例:古诗文资料获取并转存数据库
-
-# 资料站点
-- 资料:https://www.gushicimingju.com/
-- 数据范式:Shige
-
-# 数据范式 Shige
-- title:String 题目
-- author:String 作者
-- dyansty:String 朝代
-- content:Stirng 内容
-- intro:String 简介
-- yiwen:String 译文(古译今)
-- note:String 注释
-- review:String 赏析
-
-# 任务1:爬取数据集,并形成Shige数组
-- 目标:唐诗三百首全集 https://www.gushicimingju.com/gushi/tangshisanbaishou/
-
-## 纯前端DOM批量分析
-- 右键,分析目标站点,同类DOM值的selector特点
-    - 选择器特征:.main-content内容区域所有的 a标签
-    - 字符串特征:href="/gushi/shi/586.html"
-``` js
-
-let ElArray = document.querySelectorAll(".main-content a")
-let list = []
-for(let i=0;i<ElArray.length;i++){
-    list[i] = ElArray[i]
-}
-// HTMLElement 转换成 href字符串 "https://www.gushicimingju.com/gushi/shi/113.html"
-console.log("DOM选择后,数量:",list.length)
-list = list.map(el=>el.href)
-// 过滤符合特征的链接地址
-list = list.filter(item=>(item?.indexOf("/gushi/shi/")>-1))
-console.log("字符过滤后,数量:",list.length)
-// 将list数据保存至href.js
-
-```
-
-## 后端的页面分析
-
-### 依赖环境
-https://www.npmjs.com/package/cheerio
-
-``` bash
-npm i cheerio -S
-```
-
-# 任务2:将数组批量导入系统
-- 参考代码:import.js
-    - 实现href链接html数据获取
-    - 通过cheerio进行DOM分析
-    - 通过css selector标记准确字段
-    - Parse.Query查重
-    - Parse.Object保存

+ 0 - 297
server/import/libai/href.js

@@ -1,297 +0,0 @@
-module.exports.GushiHrefList = [
-    "https://www.gushicimingju.com/gushi/shi/188017.html",
-    "https://www.gushicimingju.com/gushi/shi/52.html",
-    "https://www.gushicimingju.com/gushi/shi/102.html",
-    "https://www.gushicimingju.com/gushi/shi/5.html",
-    "https://www.gushicimingju.com/gushi/shi/57.html",
-    "https://www.gushicimingju.com/gushi/shi/103.html",
-    "https://www.gushicimingju.com/gushi/shi/279.html",
-    "https://www.gushicimingju.com/gushi/shi/109.html",
-    "https://www.gushicimingju.com/gushi/shi/100.html",
-    "https://www.gushicimingju.com/gushi/shi/101.html",
-    "https://www.gushicimingju.com/gushi/shi/110.html",
-    "https://www.gushicimingju.com/gushi/shi/111.html",
-    "https://www.gushicimingju.com/gushi/shi/118.html",
-    "https://www.gushicimingju.com/gushi/shi/113.html",
-    "https://www.gushicimingju.com/gushi/shi/119.html",
-    "https://www.gushicimingju.com/gushi/shi/481.html",
-    "https://www.gushicimingju.com/gushi/shi/114.html",
-    "https://www.gushicimingju.com/gushi/shi/539.html",
-    "https://www.gushicimingju.com/gushi/shi/540.html",
-    "https://www.gushicimingju.com/gushi/shi/121.html",
-    "https://www.gushicimingju.com/gushi/shi/541.html",
-    "https://www.gushicimingju.com/gushi/shi/542.html",
-    "https://www.gushicimingju.com/gushi/shi/544.html",
-    "https://www.gushicimingju.com/gushi/shi/545.html",
-    "https://www.gushicimingju.com/gushi/shi/546.html",
-    "https://www.gushicimingju.com/gushi/shi/547.html",
-    "https://www.gushicimingju.com/gushi/shi/548.html",
-    "https://www.gushicimingju.com/gushi/shi/549.html",
-    "https://www.gushicimingju.com/gushi/shi/550.html",
-    "https://www.gushicimingju.com/gushi/shi/551.html",
-    "https://www.gushicimingju.com/gushi/shi/552.html",
-    "https://www.gushicimingju.com/gushi/shi/553.html",
-    "https://www.gushicimingju.com/gushi/shi/117.html",
-    "https://www.gushicimingju.com/gushi/shi/149.html",
-    "https://www.gushicimingju.com/gushi/shi/556.html",
-    "https://www.gushicimingju.com/gushi/shi/394.html",
-    "https://www.gushicimingju.com/gushi/shi/554.html",
-    "https://www.gushicimingju.com/gushi/shi/555.html",
-    "https://www.gushicimingju.com/gushi/shi/557.html",
-    "https://www.gushicimingju.com/gushi/shi/95.html",
-    "https://www.gushicimingju.com/gushi/shi/563.html",
-    "https://www.gushicimingju.com/gushi/shi/448.html",
-    "https://www.gushicimingju.com/gushi/shi/564.html",
-    "https://www.gushicimingju.com/gushi/shi/449.html",
-    "https://www.gushicimingju.com/gushi/shi/227.html",
-    "https://www.gushicimingju.com/gushi/shi/558.html",
-    "https://www.gushicimingju.com/gushi/shi/559.html",
-    "https://www.gushicimingju.com/gushi/shi/560.html",
-    "https://www.gushicimingju.com/gushi/shi/561.html",
-    "https://www.gushicimingju.com/gushi/shi/562.html",
-    "https://www.gushicimingju.com/gushi/shi/483.html",
-    "https://www.gushicimingju.com/gushi/shi/207.html",
-    "https://www.gushicimingju.com/gushi/shi/208.html",
-    "https://www.gushicimingju.com/gushi/shi/204.html",
-    "https://www.gushicimingju.com/gushi/shi/565.html",
-    "https://www.gushicimingju.com/gushi/shi/566.html",
-    "https://www.gushicimingju.com/gushi/shi/567.html",
-    "https://www.gushicimingju.com/gushi/shi/280.html",
-    "https://www.gushicimingju.com/gushi/shi/568.html",
-    "https://www.gushicimingju.com/gushi/shi/569.html",
-    "https://www.gushicimingju.com/gushi/shi/570.html",
-    "https://www.gushicimingju.com/gushi/shi/571.html",
-    "https://www.gushicimingju.com/gushi/shi/572.html",
-    "https://www.gushicimingju.com/gushi/shi/573.html",
-    "https://www.gushicimingju.com/gushi/shi/173.html",
-    "https://www.gushicimingju.com/gushi/shi/14.html",
-    "https://www.gushicimingju.com/gushi/shi/139.html",
-    "https://www.gushicimingju.com/gushi/shi/574.html",
-    "https://www.gushicimingju.com/gushi/shi/105.html",
-    "https://www.gushicimingju.com/gushi/shi/575.html",
-    "https://www.gushicimingju.com/gushi/shi/576.html",
-    "https://www.gushicimingju.com/gushi/shi/473.html",
-    "https://www.gushicimingju.com/gushi/shi/120.html",
-    "https://www.gushicimingju.com/gushi/shi/21.html",
-    "https://www.gushicimingju.com/gushi/shi/150.html",
-    "https://www.gushicimingju.com/gushi/shi/25.html",
-    "https://www.gushicimingju.com/gushi/shi/7.html",
-    "https://www.gushicimingju.com/gushi/shi/375.html",
-    "https://www.gushicimingju.com/gushi/shi/386.html",
-    "https://www.gushicimingju.com/gushi/shi/459.html",
-    "https://www.gushicimingju.com/gushi/shi/577.html",
-    "https://www.gushicimingju.com/gushi/shi/578.html",
-    "https://www.gushicimingju.com/gushi/shi/259.html",
-    "https://www.gushicimingju.com/gushi/shi/30.html",
-    "https://www.gushicimingju.com/gushi/shi/83.html",
-    "https://www.gushicimingju.com/gushi/shi/579.html",
-    "https://www.gushicimingju.com/gushi/shi/580.html",
-    "https://www.gushicimingju.com/gushi/shi/581.html",
-    "https://www.gushicimingju.com/gushi/shi/583.html",
-    "https://www.gushicimingju.com/gushi/shi/543.html",
-    "https://www.gushicimingju.com/gushi/shi/584.html",
-    "https://www.gushicimingju.com/gushi/shi/585.html",
-    "https://www.gushicimingju.com/gushi/shi/451.html",
-    "https://www.gushicimingju.com/gushi/shi/65.html",
-    "https://www.gushicimingju.com/gushi/shi/586.html",
-    "https://www.gushicimingju.com/gushi/shi/587.html",
-    "https://www.gushicimingju.com/gushi/shi/10.html",
-    "https://www.gushicimingju.com/gushi/shi/376.html",
-    "https://www.gushicimingju.com/gushi/shi/588.html",
-    "https://www.gushicimingju.com/gushi/shi/589.html",
-    "https://www.gushicimingju.com/gushi/shi/384.html",
-    "https://www.gushicimingju.com/gushi/shi/590.html",
-    "https://www.gushicimingju.com/gushi/shi/591.html",
-    "https://www.gushicimingju.com/gushi/shi/592.html",
-    "https://www.gushicimingju.com/gushi/shi/383.html",
-    "https://www.gushicimingju.com/gushi/shi/75.html",
-    "https://www.gushicimingju.com/gushi/shi/593.html",
-    "https://www.gushicimingju.com/gushi/shi/16.html",
-    "https://www.gushicimingju.com/gushi/shi/594.html",
-    "https://www.gushicimingju.com/gushi/shi/476.html",
-    "https://www.gushicimingju.com/gushi/shi/595.html",
-    "https://www.gushicimingju.com/gushi/shi/596.html",
-    "https://www.gushicimingju.com/gushi/shi/597.html",
-    "https://www.gushicimingju.com/gushi/shi/477.html",
-    "https://www.gushicimingju.com/gushi/shi/467.html",
-    "https://www.gushicimingju.com/gushi/shi/598.html",
-    "https://www.gushicimingju.com/gushi/shi/485.html",
-    "https://www.gushicimingju.com/gushi/shi/599.html",
-    "https://www.gushicimingju.com/gushi/shi/484.html",
-    "https://www.gushicimingju.com/gushi/shi/115.html",
-    "https://www.gushicimingju.com/gushi/shi/600.html",
-    "https://www.gushicimingju.com/gushi/shi/601.html",
-    "https://www.gushicimingju.com/gushi/shi/602.html",
-    "https://www.gushicimingju.com/gushi/shi/480.html",
-    "https://www.gushicimingju.com/gushi/shi/603.html",
-    "https://www.gushicimingju.com/gushi/shi/604.html",
-    "https://www.gushicimingju.com/gushi/shi/605.html",
-    "https://www.gushicimingju.com/gushi/shi/606.html",
-    "https://www.gushicimingju.com/gushi/shi/607.html",
-    "https://www.gushicimingju.com/gushi/shi/608.html",
-    "https://www.gushicimingju.com/gushi/shi/609.html",
-    "https://www.gushicimingju.com/gushi/shi/610.html",
-    "https://www.gushicimingju.com/gushi/shi/611.html",
-    "https://www.gushicimingju.com/gushi/shi/612.html",
-    "https://www.gushicimingju.com/gushi/shi/614.html",
-    "https://www.gushicimingju.com/gushi/shi/615.html",
-    "https://www.gushicimingju.com/gushi/shi/616.html",
-    "https://www.gushicimingju.com/gushi/shi/617.html",
-    "https://www.gushicimingju.com/gushi/shi/618.html",
-    "https://www.gushicimingju.com/gushi/shi/619.html",
-    "https://www.gushicimingju.com/gushi/shi/620.html",
-    "https://www.gushicimingju.com/gushi/shi/621.html",
-    "https://www.gushicimingju.com/gushi/shi/144.html",
-    "https://www.gushicimingju.com/gushi/shi/622.html",
-    "https://www.gushicimingju.com/gushi/shi/623.html",
-    "https://www.gushicimingju.com/gushi/shi/624.html",
-    "https://www.gushicimingju.com/gushi/shi/129.html",
-    "https://www.gushicimingju.com/gushi/shi/625.html",
-    "https://www.gushicimingju.com/gushi/shi/169.html",
-    "https://www.gushicimingju.com/gushi/shi/626.html",
-    "https://www.gushicimingju.com/gushi/shi/130.html",
-    "https://www.gushicimingju.com/gushi/shi/627.html",
-    "https://www.gushicimingju.com/gushi/shi/628.html",
-    "https://www.gushicimingju.com/gushi/shi/629.html",
-    "https://www.gushicimingju.com/gushi/shi/630.html",
-    "https://www.gushicimingju.com/gushi/shi/631.html",
-    "https://www.gushicimingju.com/gushi/shi/632.html",
-    "https://www.gushicimingju.com/gushi/shi/633.html",
-    "https://www.gushicimingju.com/gushi/shi/634.html",
-    "https://www.gushicimingju.com/gushi/shi/635.html",
-    "https://www.gushicimingju.com/gushi/shi/465.html",
-    "https://www.gushicimingju.com/gushi/shi/636.html",
-    "https://www.gushicimingju.com/gushi/shi/638.html",
-    "https://www.gushicimingju.com/gushi/shi/639.html",
-    "https://www.gushicimingju.com/gushi/shi/640.html",
-    "https://www.gushicimingju.com/gushi/shi/69.html",
-    "https://www.gushicimingju.com/gushi/shi/641.html",
-    "https://www.gushicimingju.com/gushi/shi/642.html",
-    "https://www.gushicimingju.com/gushi/shi/643.html",
-    "https://www.gushicimingju.com/gushi/shi/644.html",
-    "https://www.gushicimingju.com/gushi/shi/645.html",
-    "https://www.gushicimingju.com/gushi/shi/646.html",
-    "https://www.gushicimingju.com/gushi/shi/457.html",
-    "https://www.gushicimingju.com/gushi/shi/385.html",
-    "https://www.gushicimingju.com/gushi/shi/647.html",
-    "https://www.gushicimingju.com/gushi/shi/648.html",
-    "https://www.gushicimingju.com/gushi/shi/458.html",
-    "https://www.gushicimingju.com/gushi/shi/378.html",
-    "https://www.gushicimingju.com/gushi/shi/649.html",
-    "https://www.gushicimingju.com/gushi/shi/650.html",
-    "https://www.gushicimingju.com/gushi/shi/651.html",
-    "https://www.gushicimingju.com/gushi/shi/652.html",
-    "https://www.gushicimingju.com/gushi/shi/653.html",
-    "https://www.gushicimingju.com/gushi/shi/654.html",
-    "https://www.gushicimingju.com/gushi/shi/655.html",
-    "https://www.gushicimingju.com/gushi/shi/656.html",
-    "https://www.gushicimingju.com/gushi/shi/657.html",
-    "https://www.gushicimingju.com/gushi/shi/658.html",
-    "https://www.gushicimingju.com/gushi/shi/659.html",
-    "https://www.gushicimingju.com/gushi/shi/660.html",
-    "https://www.gushicimingju.com/gushi/shi/661.html",
-    "https://www.gushicimingju.com/gushi/shi/662.html",
-    "https://www.gushicimingju.com/gushi/shi/428.html",
-    "https://www.gushicimingju.com/gushi/shi/663.html",
-    "https://www.gushicimingju.com/gushi/shi/664.html",
-    "https://www.gushicimingju.com/gushi/shi/497.html",
-    "https://www.gushicimingju.com/gushi/shi/665.html",
-    "https://www.gushicimingju.com/gushi/shi/123.html",
-    "https://www.gushicimingju.com/gushi/shi/122.html",
-    "https://www.gushicimingju.com/gushi/shi/666.html",
-    "https://www.gushicimingju.com/gushi/shi/308.html",
-    "https://www.gushicimingju.com/gushi/shi/667.html",
-    "https://www.gushicimingju.com/gushi/shi/125.html",
-    "https://www.gushicimingju.com/gushi/shi/668.html",
-    "https://www.gushicimingju.com/gushi/shi/407.html",
-    "https://www.gushicimingju.com/gushi/shi/669.html",
-    "https://www.gushicimingju.com/gushi/shi/670.html",
-    "https://www.gushicimingju.com/gushi/shi/671.html",
-    "https://www.gushicimingju.com/gushi/shi/468.html",
-    "https://www.gushicimingju.com/gushi/shi/469.html",
-    "https://www.gushicimingju.com/gushi/shi/111.html",
-    "https://www.gushicimingju.com/gushi/shi/15.html",
-    "https://www.gushicimingju.com/gushi/shi/672.html",
-    "https://www.gushicimingju.com/gushi/shi/673.html",
-    "https://www.gushicimingju.com/gushi/shi/674.html",
-    "https://www.gushicimingju.com/gushi/shi/482.html",
-    "https://www.gushicimingju.com/gushi/shi/479.html",
-    "https://www.gushicimingju.com/gushi/shi/22.html",
-    "https://www.gushicimingju.com/gushi/shi/388.html",
-    "https://www.gushicimingju.com/gushi/shi/276.html",
-    "https://www.gushicimingju.com/gushi/shi/486.html",
-    "https://www.gushicimingju.com/gushi/shi/675.html",
-    "https://www.gushicimingju.com/gushi/shi/676.html",
-    "https://www.gushicimingju.com/gushi/shi/677.html",
-    "https://www.gushicimingju.com/gushi/shi/678.html",
-    "https://www.gushicimingju.com/gushi/shi/432.html",
-    "https://www.gushicimingju.com/gushi/shi/679.html",
-    "https://www.gushicimingju.com/gushi/shi/680.html",
-    "https://www.gushicimingju.com/gushi/shi/116.html",
-    "https://www.gushicimingju.com/gushi/shi/681.html",
-    "https://www.gushicimingju.com/gushi/shi/682.html",
-    "https://www.gushicimingju.com/gushi/shi/683.html",
-    "https://www.gushicimingju.com/gushi/shi/307.html",
-    "https://www.gushicimingju.com/gushi/shi/684.html",
-    "https://www.gushicimingju.com/gushi/shi/685.html",
-    "https://www.gushicimingju.com/gushi/shi/686.html",
-    "https://www.gushicimingju.com/gushi/shi/687.html",
-    "https://www.gushicimingju.com/gushi/shi/688.html",
-    "https://www.gushicimingju.com/gushi/shi/689.html",
-    "https://www.gushicimingju.com/gushi/shi/427.html",
-    "https://www.gushicimingju.com/gushi/shi/690.html",
-    "https://www.gushicimingju.com/gushi/shi/29.html",
-    "https://www.gushicimingju.com/gushi/shi/691.html",
-    "https://www.gushicimingju.com/gushi/shi/32.html",
-    "https://www.gushicimingju.com/gushi/shi/692.html",
-    "https://www.gushicimingju.com/gushi/shi/693.html",
-    "https://www.gushicimingju.com/gushi/shi/694.html",
-    "https://www.gushicimingju.com/gushi/shi/297.html",
-    "https://www.gushicimingju.com/gushi/shi/8.html",
-    "https://www.gushicimingju.com/gushi/shi/23.html",
-    "https://www.gushicimingju.com/gushi/shi/695.html",
-    "https://www.gushicimingju.com/gushi/shi/24.html",
-    "https://www.gushicimingju.com/gushi/shi/696.html",
-    "https://www.gushicimingju.com/gushi/shi/697.html",
-    "https://www.gushicimingju.com/gushi/shi/613.html",
-    "https://www.gushicimingju.com/gushi/shi/698.html",
-    "https://www.gushicimingju.com/gushi/shi/699.html",
-    "https://www.gushicimingju.com/gushi/shi/700.html",
-    "https://www.gushicimingju.com/gushi/shi/701.html",
-    "https://www.gushicimingju.com/gushi/shi/35.html",
-    "https://www.gushicimingju.com/gushi/shi/184.html",
-    "https://www.gushicimingju.com/gushi/shi/462.html",
-    "https://www.gushicimingju.com/gushi/shi/702.html",
-    "https://www.gushicimingju.com/gushi/shi/703.html",
-    "https://www.gushicimingju.com/gushi/shi/704.html",
-    "https://www.gushicimingju.com/gushi/shi/705.html",
-    "https://www.gushicimingju.com/gushi/shi/707.html",
-    "https://www.gushicimingju.com/gushi/shi/164.html",
-    "https://www.gushicimingju.com/gushi/shi/708.html",
-    "https://www.gushicimingju.com/gushi/shi/709.html",
-    "https://www.gushicimingju.com/gushi/shi/710.html",
-    "https://www.gushicimingju.com/gushi/shi/167.html",
-    "https://www.gushicimingju.com/gushi/shi/711.html",
-    "https://www.gushicimingju.com/gushi/shi/712.html",
-    "https://www.gushicimingju.com/gushi/shi/713.html",
-    "https://www.gushicimingju.com/gushi/shi/127.html",
-    "https://www.gushicimingju.com/gushi/shi/715.html",
-    "https://www.gushicimingju.com/gushi/shi/714.html",
-    "https://www.gushicimingju.com/gushi/shi/716.html",
-    "https://www.gushicimingju.com/gushi/shi/124.html",
-    "https://www.gushicimingju.com/gushi/shi/717.html",
-    "https://www.gushicimingju.com/gushi/shi/718.html",
-    "https://www.gushicimingju.com/gushi/shi/719.html",
-    "https://www.gushicimingju.com/gushi/shi/720.html",
-    "https://www.gushicimingju.com/gushi/shi/721.html",
-    "https://www.gushicimingju.com/gushi/shi/471.html",
-    "https://www.gushicimingju.com/gushi/shi/723.html",
-    "https://www.gushicimingju.com/gushi/shi/724.html",
-    "https://www.gushicimingju.com/gushi/shi/470.html",
-    "https://www.gushicimingju.com/gushi/shi/725.html",
-    "https://www.gushicimingju.com/gushi/shi/726.html",
-    "https://www.gushicimingju.com/gushi/shi/196.html",
-    "https://www.gushicimingju.com/gushi/shi/396.html",
-    "https://www.gushicimingju.com/gushi/shi/487.html",
-    "https://www.gushicimingju.com/gushi/shi/426.html"
-]

+ 0 - 60
server/import/libai/import.js

@@ -1,60 +0,0 @@
-const cheerio = require('cheerio');
-const { GushiHrefList } = require("./href")
-
-// 引用Parse JS SDK
-const Parse = require("parse/node");
-Parse.initialize("dev"); // 设置applicationId
-Parse.serverURL = "http://web2023.fmode.cn:9999/parse"; // 设置serverURL
-
-
-// 实现分页抓取数据,并保存
-main()
-async function main(){
-    // let list = [GushiHrefList[0]]
-    let list = GushiHrefList
-    list.forEach(async href=>{
-        let gushi = await getGushiDataFromHref(href);
-        if(!gushi?.title || !gushi?.author) return;
-        // 查重
-        let exists = await checkExists(gushi);
-        if(exists?.id) return
-        // 新增
-        let Shige = Parse.Object.extend("Shige");
-        let sg = new Shige();
-        sg.set(gushi);
-        sg.save();
-    })
-}
-async function checkExists(gushi){
-    let query = new Parse.Query("Shige");
-    query.equalTo("title",gushi?.title);
-    query.equalTo("author",gushi?.author);
-    query.equalTo("dynasty",gushi?.dynasty);
-    await query.first();
-    return await query.first();
-}
-
-async function getGushiDataFromHref(href){
-    let gushi = {}
-
-    let response
-    try{
-        response = await fetch(href);
-    }catch(err){
-        console.log("失败:",href)
-        return {}
-    }
-    let html = await response.text()
-    const $ = cheerio.load(html);
-
-    gushi.title = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(1) > h1').text();
-    gushi.author = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(1) > div.author-simple-info > span:nth-child(3) > a').text();
-    gushi.dynasty = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(1) > div.author-simple-info > span:nth-child(1) > a').text();
-    gushi.content = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(1) > div.shici-content.check-more').html();
-    gushi.intro = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(5) > div:nth-child(2)').html();
-    gushi.yiwen = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(5) > div:nth-child(4)').html();
-    gushi.note = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(5) > div:nth-child(6)').html()
-    gushi.review = $('body > div.container.basic-page > div > div.more-container.col-md-8 > div:nth-child(5) > div:nth-child(8)').html()
-    console.log(href,gushi)
-    return gushi
-}

+ 0 - 197
server/import/libai/package-lock.json

@@ -1,197 +0,0 @@
-{
-  "name": "libai",
-  "version": "1.0.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "libai",
-      "version": "1.0.0",
-      "license": "ISC",
-      "dependencies": {
-        "cheerio": "^1.0.0-rc.12"
-      }
-    },
-    "node_modules/boolbase": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
-    },
-    "node_modules/cheerio": {
-      "version": "1.0.0-rc.12",
-      "resolved": "https://registry.npmmirror.com/cheerio/-/cheerio-1.0.0-rc.12.tgz",
-      "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==",
-      "dependencies": {
-        "cheerio-select": "^2.1.0",
-        "dom-serializer": "^2.0.0",
-        "domhandler": "^5.0.3",
-        "domutils": "^3.0.1",
-        "htmlparser2": "^8.0.1",
-        "parse5": "^7.0.0",
-        "parse5-htmlparser2-tree-adapter": "^7.0.0"
-      },
-      "engines": {
-        "node": ">= 6"
-      },
-      "funding": {
-        "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
-      }
-    },
-    "node_modules/cheerio-select": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmmirror.com/cheerio-select/-/cheerio-select-2.1.0.tgz",
-      "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
-      "dependencies": {
-        "boolbase": "^1.0.0",
-        "css-select": "^5.1.0",
-        "css-what": "^6.1.0",
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.3",
-        "domutils": "^3.0.1"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/fb55"
-      }
-    },
-    "node_modules/css-select": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmmirror.com/css-select/-/css-select-5.1.0.tgz",
-      "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
-      "dependencies": {
-        "boolbase": "^1.0.0",
-        "css-what": "^6.1.0",
-        "domhandler": "^5.0.2",
-        "domutils": "^3.0.1",
-        "nth-check": "^2.0.1"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/fb55"
-      }
-    },
-    "node_modules/css-what": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz",
-      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
-      "engines": {
-        "node": ">= 6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/fb55"
-      }
-    },
-    "node_modules/dom-serializer": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-2.0.0.tgz",
-      "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
-      "dependencies": {
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.2",
-        "entities": "^4.2.0"
-      },
-      "funding": {
-        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
-      }
-    },
-    "node_modules/domelementtype": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz",
-      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/fb55"
-        }
-      ]
-    },
-    "node_modules/domhandler": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmmirror.com/domhandler/-/domhandler-5.0.3.tgz",
-      "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
-      "dependencies": {
-        "domelementtype": "^2.3.0"
-      },
-      "engines": {
-        "node": ">= 4"
-      },
-      "funding": {
-        "url": "https://github.com/fb55/domhandler?sponsor=1"
-      }
-    },
-    "node_modules/domutils": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmmirror.com/domutils/-/domutils-3.1.0.tgz",
-      "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
-      "dependencies": {
-        "dom-serializer": "^2.0.0",
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.3"
-      },
-      "funding": {
-        "url": "https://github.com/fb55/domutils?sponsor=1"
-      }
-    },
-    "node_modules/entities": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz",
-      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-      "engines": {
-        "node": ">=0.12"
-      },
-      "funding": {
-        "url": "https://github.com/fb55/entities?sponsor=1"
-      }
-    },
-    "node_modules/htmlparser2": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-8.0.2.tgz",
-      "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
-      "funding": [
-        "https://github.com/fb55/htmlparser2?sponsor=1",
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/fb55"
-        }
-      ],
-      "dependencies": {
-        "domelementtype": "^2.3.0",
-        "domhandler": "^5.0.3",
-        "domutils": "^3.0.1",
-        "entities": "^4.4.0"
-      }
-    },
-    "node_modules/nth-check": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz",
-      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
-      "dependencies": {
-        "boolbase": "^1.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/fb55/nth-check?sponsor=1"
-      }
-    },
-    "node_modules/parse5": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.1.2.tgz",
-      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
-      "dependencies": {
-        "entities": "^4.4.0"
-      },
-      "funding": {
-        "url": "https://github.com/inikulin/parse5?sponsor=1"
-      }
-    },
-    "node_modules/parse5-htmlparser2-tree-adapter": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
-      "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
-      "dependencies": {
-        "domhandler": "^5.0.2",
-        "parse5": "^7.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/inikulin/parse5?sponsor=1"
-      }
-    }
-  }
-}

+ 0 - 14
server/import/libai/package.json

@@ -1,14 +0,0 @@
-{
-  "name": "libai",
-  "version": "1.0.0",
-  "description": "- 资料:https://www.gushicimingju.com/\r - 数据范式:Shige",
-  "main": "href.js",
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "author": "",
-  "license": "ISC",
-  "dependencies": {
-    "cheerio": "^1.0.0-rc.12"
-  }
-}

+ 25 - 5
server/rest.js

@@ -1,11 +1,32 @@
+//Foodcourt GET获取全部美食街
+async function getFood(){
+  let response = await fetch("http://web2023.fmode.cn:9999/parse/classes/Delicacy?", {
+    "headers": {
+      "accept": "*/*",
+      "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+      "x-parse-application-id": "dev"
+    },
+    "referrer": "http://127.0.0.1:4040/",
+    "referrerPolicy": "strict-origin-when-cross-origin",
+    "body": null,
+    "method": "GET",
+    "mode": "cors",
+    "credentials": "omit"
+  });
+  if(response?.status=="200"){
+    let json = await response.json()
+    return json?.results || []
+  }else{
+    return []
+  }
+}
 
-// Pet GET 获取全部宠物
 async function getPet(){
-  let response = await fetch("http://web2023.fmode.cn:9999/parse/classes/Pet?", {
+  let response = await fetch("http://web2023.fmode.cn:9999/parse/classes/Foodcourt?", {
     "headers": {
       "accept": "*/*",
       "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
-      "if-none-match": "W/\"19f-gvNjdCzTNrgDv/sckM9+BRABBVY\"",
+      "if-none-match": "W/\"a32-BlWXqWcse27iw72NLr5IFuxLE7g\"",
       "x-parse-application-id": "dev"
     },
     "referrer": "http://127.0.0.1:4040/",
@@ -15,8 +36,6 @@ async function getPet(){
     "mode": "cors",
     "credentials": "omit"
   });
-  // console.log(response)
-  // return []
   if(response?.status=="200"){
     let json = await response.json()
     // console.log(json)
@@ -25,6 +44,7 @@ async function getPet(){
     return []
   }
 }
+ 
 
 async function main(){
   // let petList = await getPet()

+ 27 - 3
src/app/app-routing.module.ts

@@ -37,9 +37,33 @@ const routes: Routes = [
   {
     path: 'user',
     loadChildren: () => import('../modules/user/user.module').then(m => m.UserModule)
-  }
-
-
+  },
+  {
+    path:"study",
+    children:[
+      {
+        path: 'parse',
+        loadChildren: () => import('../modules/study/case-js-module/case-parse/case-parse.module').then( m => m.CaseParsePageModule)
+      },
+      {
+        path: 'case-petmarket',
+        loadChildren: () => import('../modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.module').then( m => m.CaseParsePetmarketPageModule)
+      },
+      {
+        path: 'Delicacy/:id',
+        loadChildren: () => import('../modules/study/case-js-module/case-pet-detail/case-pet-detail.module').then( m => m.CasePetDetailPageModule)
+      },
+      {
+        path: 'Foodcourt/edit/:id', // 编辑宠物
+        loadChildren: () => import('../modules/study/case-js-module/case-pet-edit/case-pet-edit.module').then( m => m.CasePetEditPageModule)
+      },
+    
+    ]
+  },
+  {
+    path: 'aigc',
+    loadChildren: () => import('../modules/aigc/aigc.module').then(m => m.AigcModule)
+  },
 ];
 @NgModule({
   imports: [

+ 9 - 32
src/app/tab1/tab1.page.html

@@ -34,37 +34,14 @@
         </ng-container>
       </div>
 
-  <!-- 推荐内容展示 -->
-  <ion-card (click)="navigateToShouyeViewPage()">
-    <ion-card-header>
-      推荐内容
-    </ion-card-header>
-    <ion-card-content>
-      【桂林+阳朔】船在水中走 人在画中游 | 三天旅行攻略 去看小砂糖橘
-    </ion-card-content>
-    <ion-img src="https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7"></ion-img>
-  </ion-card>
-
-  <!-- 热门目的地导航 -->
-  <ion-card>
-    <ion-card-header>
-      热门目的地
-    </ion-card-header>
-    <ion-card-content>
-      九寨沟
-    </ion-card-content>
-    <ion-img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.4sCrXFdufaW6NLTTeTJFdQHaEq?w=229&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7"></ion-img>
-  </ion-card>
-
-  <!-- 热门活动展示 -->
-  <ion-card>
-    <ion-card-header>
-      热门活动
-    </ion-card-header>
-    <ion-card-content>
-      至我们逝去的青春 | 毕业旅游之环游宝岛台湾13天
-    </ion-card-content>
-    <ion-img src="https://ts1.cn.mm.bing.net/th/id/R-C.90139666f8943b728df6af35d9e0f82a?rik=V2B9Csf%2be9hAdA&riu=http%3a%2f%2fi.52desktop.cn%3a81%2fupimg%2fallimg%2f20141231%2f2014123116175167177807.jpg&ehk=AryhWxX8LTLpPs4rb31XISqXKyw0zFPNtxRenGZli8M%3d&risl=&pid=ImgRaw&r=0"></ion-img>
-  </ion-card>
+      <ion-card *ngFor="let item of items" (click)="navigateToShouyeViewPage()">
+        <ion-card-header>
+          {{ item.title }}
+        </ion-card-header>
+        <ion-card-content>
+          {{ item.description }}
+        </ion-card-content>
+        <ion-img [src]="item.image"></ion-img>
+      </ion-card>
 
 </ion-content>

+ 45 - 44
src/app/tab1/tab1.page.scss

@@ -1,58 +1,59 @@
 .middle-section {
-  display: flex;
-  flex-direction: column;
-  justify-content: space-around;
-  overflow-x: auto;
-  white-space: nowrap;
-  margin-top: 4px; /* 添加顶部间距 */
-  .row{
-      display: flex;
-      flex-direction: row;
-      justify-content: space-around;
-  }
-    .order-card {
-      width: 60px;
-      height: 60px;
-      margin: 4px;
-      text-align: center; 
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      align-items: center;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+    overflow-x: auto;
+    white-space: nowrap;
+    margin-top: 4px; /* 添加顶部间距 */
+    .row{
+        display: flex;
+        flex-direction: row;
+        justify-content: space-around;
     }
-      .centered-header {
+      .order-card {
+        width: 60px;
+        height: 60px;
+        margin: 4px;
+        text-align: center; 
         display: flex;
+        flex-direction: column;
         justify-content: center;
         align-items: center;
-        flex-direction: column; /* 设置为垂直方向布局 */
-        // height: 100%; /* 设置容器高度为100% */  
-      }
-      .large-icon {
-        font-size: 30px; /* 设置图标大小为30像素 */
-        margin-bottom: 5px; /* 调整图标与文字之间的间距 */  
-      } 
-      .ion-card-subtitle {
-        font-size: 12px;
       }
-        
+        .centered-header {
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          flex-direction: column; /* 设置为垂直方向布局 */
+          // height: 100%; /* 设置容器高度为100% */  
+        }
+}  
+      
+.large-icon {
+  font-size: 30px; /* 设置图标大小为30像素 */
+  margin-bottom: 5px; /* 调整图标与文字之间的间距 */  
+} 
+.ion-card-subtitle {
+  font-size: 12px;
 }
-  
 
 
 .swiper-container {
-width: 100%;
-height: 160px;
+  width: 100%;
+  height: 160px;
 
-.swiper-wrapper {
-  height: 140px; // 调整swiper-wrapper的高度
+  .swiper-wrapper {
+    height: 140px; // 调整swiper-wrapper的高度
 
-  .swiper-slide {
-    text-align: center;
-    height: 100%; // 调整swiper-slide的高度
+    .swiper-slide {
+      text-align: center;
+      height: 100%; // 调整swiper-slide的高度
+    }
+  }  
+  .swiper-button-next,
+  .swiper-button-prev {
+    display: none; // 隐藏轮播箭头
   }
-}  
-.swiper-button-next,
-.swiper-button-prev {
-  display: none; // 隐藏轮播箭头
-}
 }
+
+

+ 6 - 1
src/app/tab1/tab1.page.ts

@@ -31,7 +31,12 @@ export class Tab1Page {
     { icon: 'airplane-outline', title: '海外游' },
     { icon: 'compass-outline', title: '周边游' }
   ];
-
+  
+  items = [
+    { title: '推荐内容', description: '【桂林+阳朔】船在水中走 人在画中游 | 三天旅行攻略 去看小砂糖橘', image: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7' },
+    { title: '热门目的地', description: '九寨沟', image: 'https://tse1-mm.cn.bing.net/th/id/OIP-C.4sCrXFdufaW6NLTTeTJFdQHaEq?w=229&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7' },
+    { title: '热门活动', description: '至我们逝去的青春 | 毕业旅游之环游宝岛台湾13天', image: 'https://ts1.cn.mm.bing.net/th/id/R-C.90139666f8943b728df6af35d9e0f82a?rik=V2B9Csf%2be9hAdA&riu=http%3a%2f%2fi.52desktop.cn%3a81%2fupimg%2fallimg%2f20141231%2f2014123116175167177807.jpg&ehk=AryhWxX8LTLpPs4rb31XISqXKyw0zFPNtxRenGZli8M%3d&risl=&pid=ImgRaw&r=0' }
+  ];
   chunkedCards: any[] = [];
 
   

+ 39 - 41
src/app/tab2/tab2.page.html

@@ -4,48 +4,46 @@
   </ion-toolbar>
 </ion-header>
 
-<ion-content>
-  <!-- 国内景点 -->
-  <ion-card>
-    <ion-card-header>
-      国内景点
-    </ion-card-header>
-    <ion-card-content>
-      <ion-list>
-        <ion-item>
-          <ion-thumbnail slot="start">
-            <ion-img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.Ltwg5DrGKW0f3Yv9F4EdXQHaEi?w=295&h=181&c=7&r=0&o=5&dpr=1.3&pid=1.7"></ion-img>
-          </ion-thumbnail>
-          <ion-label>
-            <h2>杭州西湖</h2>
-            <p>西湖周围风景秀丽,湖水清澈,绿树成荫,有着许多著名的景点和建筑,如雷峰塔、岳飞庙、苏堤、断桥等。西湖的景色因四季不同而各具特色,春季樱花盛开、夏季翠绿如玉、秋季层林尽染、冬季冰雪皑皑,每个季节都有独特的美景。</p>
-          </ion-label>
-        </ion-item>
-        <!-- 这里可以添加更多国内景点的示例数据 -->
-      </ion-list>
-    </ion-card-content>
-  </ion-card>
 
-  <!-- 国际景点 -->
-  <ion-card>
-    <ion-card-header>
-      国际景点
-    </ion-card-header>
-    <ion-card-content>
-      <ion-list>
-        <ion-item>
-          <ion-thumbnail slot="start">
-            <ion-img src="https://ts2.cn.mm.bing.net/th?id=OIP-C.g7gy6ppOPiH05QZ7mOUxoQHaFj&w=288&h=216&c=8&rs=1&qlt=90&o=6&dpr=1.3&pid=3.1&rm=2"></ion-img>
-          </ion-thumbnail>
-          <ion-label>
-            <h2>夏威夷</h2>
-            <p>夏威夷的自然景观多样,有壮丽的火山景观、郁郁葱葱的热带雨林、蔚蓝的海洋和金黄色的沙滩。夏威夷火山国家公园是夏威夷最著名的景点之一,游客可以看到活火山、熔岩流、热带雨林等壮观景观。</p>
-          </ion-label>
-        </ion-item>
-        <!-- 这里可以添加更多国际景点的示例数据 -->
-      </ion-list>
-    </ion-card-content>
-  </ion-card>
 
+ <ion-content>
+
+  <!-- <ion-card > -->
+    <!-- <ion-card-content class="button">
+      <ion-button expand="block" routerLink="/aigc/chat">AI趣答</ion-button>
+    </ion-card-content> -->
+  <!-- </ion-card> -->
+
+  <div class="category">
+    <ion-grid>
+        <ion-col size="6" expand="block" routerLink="/study/case-petmarket">
+            <ion-card-header>{{category.title}}</ion-card-header>
+            <ion-card-content>
+              <img [src]="category.image">
+            </ion-card-content>
+        </ion-col>
+    </ion-grid>
+  </div>
   
+  <ion-card-content class="button">
+    <ion-button expand="block" routerLink="/aigc/chat">AI趣答</ion-button>
+  </ion-card-content>
+
+<div class="item">
+  <ion-grid>
+    <ion-card-header>热门精选</ion-card-header>
+    <ion-row>
+      <ion-col size="6" *ngFor="let item of selectedItems">
+        <ion-card>
+          <ion-card-content class="card-content" expand="block" routerLink="/study/parse">
+            <img [src]="item.image" style="width: 150%;height: 150%;">
+            <ion-card-header>{{item.title}}</ion-card-header>
+          </ion-card-content>
+        </ion-card>
+      </ion-col>
+    </ion-row>
+  </ion-grid>
+</div>
+  
+
 </ion-content>

+ 62 - 0
src/app/tab2/tab2.page.scss

@@ -0,0 +1,62 @@
+.button{
+    ion-button {
+        --background: linear-gradient(to right, #71b6ff, #71f182); // 设置渐变色背景
+    
+        &:hover {
+          --background: linear-gradient(to right, #71f182, #71b6ff); // 鼠标悬停时渐变色反转
+        }
+      }
+}
+.category{
+    ion-grid {
+          ion-col {
+            ion-card {
+              width: 100%; // 设置卡片宽度为100%
+    
+              ion-card-header {
+                font-size: 1.5rem; // 调整字体大小,根据需要调整
+                padding: 0%;
+              }
+    
+              ion-card-content {
+                padding: 0 0;
+                img {
+                  width: 100%; // 图片宽度填充满父容器
+                  height: 200px; // 自动调整高度
+                }
+              }
+            }
+        }
+      }
+}
+
+.item{
+    ion-card {
+        position: relative;
+        overflow: hidden;
+
+        .card-content {
+          position: relative;
+          padding: 0;
+
+          img {
+            width: 100%;
+            height: 100%;
+            object-fit: cover;
+          }
+
+          ion-card-header {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            background: rgba(0, 0, 0, 0.5); // 添加半透明背景色
+            color: white;
+            padding: 10px;
+            text-align: center;
+            width: 80%; // 文字框宽度
+            height:40%;
+          }
+        }
+      }
+    }

+ 21 - 1
src/app/tab2/tab2.page.ts

@@ -1,4 +1,6 @@
 import { Component } from '@angular/core';
+import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
+import { NavController } from '@ionic/angular'
 
 @Component({
   selector: 'app-tab2',
@@ -7,6 +9,24 @@ import { Component } from '@angular/core';
 })
 export class Tab2Page {
 
-  constructor() {}
+  selectedItems = [
+    { title: '南昌美食攻略', image: "https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7" },
+    { title: '南昌经典必游', image: "https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7" },
+    { title: '南昌美食攻略', image: "https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7" },
+    { title: '南昌经典必游', image: "https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7" }
+  ];
 
+  category = { title: '景点分类', image: "https://tse3-mm.cn.bing.net/th/id/OIP-C.5HjektOIikSBU1vw0JVKwgHaE8?w=305&h=180&c=7&r=0&o=5&dpr=1.3&pid=1.7" };
+
+
+
+  currentTab:string = "static"
+  safeHTML: SafeResourceUrl|undefined
+  constructor(private domSan:DomSanitizer,private navCtrl: NavController) {
+    this.safeHTML = domSan.bypassSecurityTrustHtml(``)
+  }
+  
+  openGit(){
+    window.open(`http://git.fmode.cn:3000/nkkj/study-ng-contact`,"_blank")
+  }
 }

+ 12 - 0
src/modules/aigc/aigc-routing.module.ts

@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+  {path: 'chat', loadChildren: () => import('./chat/chat.module').then(mod => mod.ChatPageModule)},
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class AigcRoutingModule { }

+ 14 - 0
src/modules/aigc/aigc.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { AigcRoutingModule } from './aigc-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    AigcRoutingModule
+  ]
+})
+export class AigcModule { }

+ 17 - 0
src/modules/aigc/chat/chat-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { ChatPage } from './chat.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: ChatPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class ChatPageRoutingModule {}

+ 20 - 0
src/modules/aigc/chat/chat.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { ChatPageRoutingModule } from './chat-routing.module';
+
+import { ChatPage } from './chat.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    ChatPageRoutingModule
+  ],
+  declarations: [ChatPage]
+})
+export class ChatPageModule {}

+ 24 - 0
src/modules/aigc/chat/chat.page.html

@@ -0,0 +1,24 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>
+      AIGC 消息发送
+    </ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-item>
+    <ion-input placeholder="输入消息" [(ngModel)]="userInput"></ion-input>
+  </ion-item>
+
+  <ion-button expand="block" (click)="sendMessage()">发送</ion-button>
+
+  <ion-card *ngFor="let message of messageList">
+    <ion-card-header>
+      {{message?.role}}
+    </ion-card-header>
+    <ion-card-content>
+      {{ message?.content }}
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 0 - 0
src/modules/aigc/chat/chat.page.scss


+ 17 - 0
src/modules/aigc/chat/chat.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChatPage } from './chat.page';
+
+describe('ChatPage', () => {
+  let component: ChatPage;
+  let fixture: ComponentFixture<ChatPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ChatPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 31 - 0
src/modules/aigc/chat/chat.page.ts

@@ -0,0 +1,31 @@
+import { Component, OnInit } from '@angular/core';
+// 引用FmodeChatCompletion类
+import { TestChatCompletion, TestChatMessage } from './class-chat-completion';
+
+@Component({
+  selector: 'app-chat',
+  templateUrl: './chat.page.html',
+  styleUrls: ['./chat.page.scss'],
+})
+export class ChatPage implements OnInit {
+  messageList:Array<TestChatMessage> = []
+  userInput:string = ""
+
+  completion:TestChatCompletion
+  constructor() { 
+    this.completion = new TestChatCompletion(this.messageList)
+  }
+
+  ngOnInit() {
+  }
+  sendMessage(){
+    this.messageList.push({
+      role:"user",
+      content: this.userInput
+    })
+    this.userInput = ""
+    this.completion.createCompletionByStream()
+
+  }
+
+}

+ 99 - 0
src/modules/aigc/chat/class-chat-completion.ts

@@ -0,0 +1,99 @@
+export interface TestChatMessage{
+    role:string
+    content:string
+}
+export class TestChatCompletion{
+messageList:Array<TestChatMessage>
+constructor(messageList:Array<TestChatMessage>){
+    this.messageList = messageList
+}
+async createCompletionByStream() {
+
+let token = localStorage.getItem("token");
+let bodyJson = {
+  "token": `Bearer ${token}`,
+  "messages": this.messageList,
+  "model": "gpt-3.5-turbo",
+  "temperature": 0.5,
+  "presence_penalty": 0,
+  "frequency_penalty": 0,
+  "top_p": 1,
+  "stream":true
+};
+
+let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+  "headers": {
+    "accept": "text/event-stream",
+    "sec-fetch-dest": "empty",
+    "sec-fetch-mode": "cors",
+    "sec-fetch-site": "same-site"
+  },
+  "referrer": "https://ai.fmode.cn/",
+  "referrerPolicy": "strict-origin-when-cross-origin",
+  "body": JSON.stringify(bodyJson),
+  "method": "POST",
+  "mode": "cors",
+  "credentials": "omit"
+});
+
+let messageAiReply = ""
+let messageIndex = this.messageList.length
+let reader = response.body?.getReader();
+if (!reader) {
+  throw new Error("Failed to get the response reader.");
+}
+
+let decoder = new TextDecoder();
+let buffer = "";
+
+while (true) {
+  let { done, value } = await reader.read();
+  if (done) {
+    break;
+  }
+
+  buffer += decoder.decode(value);
+
+  // Split the buffer by newlines to get individual messages
+  let messages = buffer.split("\n");
+
+  // Process each message
+  for (let i = 0; i < messages.length - 1; i++) {
+    let message = messages[i];
+
+    // Process the message as needed
+    /**
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
+     * data: [DONE]
+     */
+    let dataText = message.replace("data:\ ","")
+    if(dataText.startsWith("{")){
+      try{
+        let dataJson = JSON.parse(dataText)
+        console.log(dataJson)
+        messageAiReply += dataJson?.choices?.[0]?.delta?.content || ""
+        this.messageList[messageIndex] = {
+          role:"assistant",
+          content:messageAiReply
+        }
+      }catch(err){}
+    }
+    if(dataText.startsWith("[")){
+      console.log(message)
+      console.log("完成")
+      this.messageList[messageIndex] = {
+        role:"assistant",
+        content:messageAiReply
+      }
+      messageAiReply = ""
+    }
+    // Parse the message as JSON
+    // let data = JSON.parse(message);
+
+    // Clear the processed message from the buffer
+    buffer = buffer.slice(message.length + 1);
+  }
+}
+}
+}

+ 163 - 0
src/modules/study/case-js-module/case-parse-petmarket/README.md

@@ -0,0 +1,163 @@
+
+# 示例:AI编写列表页
+> 我在编写一个宠物市场的页面,前端框架使用ionic7的angular版本,数据请求使用Parse JS SDK。
+> 其中宠物的Schema名称为Pet,字段name:String名称、type:String类型,price:Number价格。
+> 请帮我实现该页面,通过卡片列表展示宠物,需要支持搜索条、宠物类型(Pet的type字段)标签切换、价格(Pet的price字段)点击排序等功能。
+
+好的,我可以帮你实现这个宠物市场页面。我们将使用Ionic 7和Angular来构建前端,并通过Parse JS SDK来处理数据请求。以下是实现这个页面的详细步骤:
+
+1. **初始化项目**
+   首先,确保你已经安装了Ionic CLI。如果没有,使用以下命令安装:
+   ```bash
+   npm install -g @ionic/cli
+   ```
+
+   然后,创建一个新的Ionic Angular项目:
+   ```bash
+   ionic start pet-market blank --type=angular
+   cd pet-market
+   ```
+
+2. **安装Parse JS SDK**
+   在项目目录下安装Parse JS SDK:
+   ```bash
+   npm install parse
+   ```
+
+3. **配置Parse**
+   在`src/environments/environment.ts`中添加Parse配置:
+   ```typescript
+   export const environment = {
+     production: false,
+     parseAppId: 'YOUR_PARSE_APP_ID',
+     parseServerUrl: 'YOUR_PARSE_SERVER_URL'
+   };
+   ```
+
+   在`src/main.ts`中初始化Parse:
+   ```typescript
+   import { environment } from './environments/environment';
+   import { Parse } from 'parse';
+
+   Parse.initialize(environment.parseAppId);
+   Parse.serverURL = environment.parseServerUrl;
+   ```
+
+4. **创建服务来处理Parse请求**
+   创建一个新的服务来处理与Parse的交互。在`src/app`目录下创建一个`services`文件夹,并在其中创建`pet.service.ts`:
+   ```typescript
+   import { Injectable } from '@angular/core';
+   import { Parse } from 'parse';
+
+   @Injectable({
+     providedIn: 'root'
+   })
+   export class PetService {
+     private Pet = Parse.Object.extend('Pet');
+
+     constructor() {}
+
+     async getPets(queryParams: any): Promise<Parse.Object[]> {
+       const query = new Parse.Query(this.Pet);
+       if (queryParams.name) {
+         query.contains('name', queryParams.name);
+       }
+       if (queryParams.type) {
+         query.equalTo('type', queryParams.type);
+       }
+       if (queryParams.sortByPrice) {
+         query.ascending('price');
+       } else {
+         query.descending('price');
+       }
+       return await query.find();
+     }
+   }
+   ```
+
+5. **创建页面组件**
+   生成页面组件:
+   ```bash
+   ionic generate page PetMarket
+   ```
+
+6. **实现页面布局和逻辑**
+   在`pet-market.page.html`中,创建搜索条、类型标签和卡片列表:
+   ```html
+   <ion-header>
+     <ion-toolbar>
+       <ion-title>Pet Market</ion-title>
+     </ion-toolbar>
+   </ion-header>
+
+   <ion-content>
+     <ion-searchbar [(ngModel)]="searchQuery" (ionInput)="fetchPets()"></ion-searchbar>
+     <ion-segment [(ngModel)]="selectedType" (ionChange)="fetchPets()">
+       <ion-segment-button *ngFor="let type of petTypes" [value]="type">
+         {{ type }}
+       </ion-segment-button>
+     </ion-segment>
+     <ion-button (click)="toggleSort()">Sort by Price</ion-button>
+     <ion-list>
+       <ion-card *ngFor="let pet of pets">
+         <ion-card-header>
+           <ion-card-title>{{ pet.get('name') }}</ion-card-title>
+         </ion-card-header>
+         <ion-card-content>
+           Type: {{ pet.get('type') }}<br>
+           Price: {{ pet.get('price') | currency }}
+         </ion-card-content>
+       </ion-card>
+     </ion-list>
+   </ion-content>
+   ```
+
+   在`pet-market.page.ts`中,添加逻辑来处理数据请求和状态管理:
+   ```typescript
+   import { Component, OnInit } from '@angular/core';
+   import { PetService } from '../services/pet.service';
+
+   @Component({
+     selector: 'app-pet-market',
+     templateUrl: './pet-market.page.html',
+     styleUrls: ['./pet-market.page.scss'],
+   })
+   export class PetMarketPage implements OnInit {
+     pets: any[] = [];
+     searchQuery: string = '';
+     selectedType: string = '';
+     petTypes: string[] = ['Dog', 'Cat', 'Bird', 'Other'];
+     sortByPrice: boolean = false;
+
+     constructor(private petService: PetService) {}
+
+     ngOnInit() {
+       this.fetchPets();
+     }
+
+     async fetchPets() {
+       const queryParams = {
+         name: this.searchQuery,
+         type: this.selectedType,
+         sortByPrice: this.sortByPrice
+       };
+       this.pets = await this.petService.getPets(queryParams);
+     }
+
+     toggleSort() {
+       this.sortByPrice = !this.sortByPrice;
+       this.fetchPets();
+     }
+   }
+   ```
+
+7. **添加样式**
+   根据需要添加样式以美化页面。在`pet-market.page.scss`中编写CSS样式。
+
+8. **运行项目**
+   最后,运行项目并查看效果:
+   ```bash
+   ionic serve
+   ```
+
+这样,你就可以在Ionic Angular项目中创建一个宠物市场页面,并通过Parse JS SDK来获取和展示宠物数据。页面支持搜索、类型标签切换和价格排序功能。

+ 17 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CaseParsePetmarketPage } from './case-parse-petmarket.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CaseParsePetmarketPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CaseParsePetmarketPageRoutingModule {}

+ 20 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CaseParsePetmarketPageRoutingModule } from './case-parse-petmarket-routing.module';
+
+import { CaseParsePetmarketPage } from './case-parse-petmarket.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CaseParsePetmarketPageRoutingModule
+  ],
+  declarations: [CaseParsePetmarketPage]
+})
+export class CaseParsePetmarketPageModule {}

+ 32 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.html

@@ -0,0 +1,32 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>Scenic Spot</ion-title>
+    <ion-buttons slot="end">
+      <ion-button routerLink="/study/Foodcourt/edit/new" >发布</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-searchbar [(ngModel)]="searchQuery" (ionInput)="fetchFoodcourts()"></ion-searchbar>
+  <ion-segment [(ngModel)]="selectedType" (ionChange)="fetchFoodcourts()">
+    <ion-segment-button *ngFor="let type of FoodcourtTypes" [value]="type">
+      {{ type }}
+    </ion-segment-button>
+  </ion-segment>
+  <ion-button (click)="toggleSort()" style="margin-top: 10px;">Sort by name</ion-button>
+  <ion-list>
+
+    <ion-card *ngFor="let Foodcourt of Foodcourts">
+      <img [src]="Foodcourt.get('image')" alt="Foodcourt Image">
+    <!-- <ion-card-header> -->
+      <ion-card-title>{{ Foodcourt.get('name') }}</ion-card-title>
+      <ion-card-subtitle>{{ Foodcourt.get('type') }}
+
+        <ion-button *ngIf="Foodcourt?.get('user')?.id == user?.id" class="custom-button" fisll="clear" routerLink="/study/Foodcourt/edit/{{Foodcourt.id}}" >编辑</ion-button>
+      </ion-card-subtitle>
+  
+    </ion-card>
+
+  </ion-list>
+</ion-content>

+ 10 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.scss

@@ -0,0 +1,10 @@
+img {
+    width: 100%;
+    height: 120px;
+    object-fit: cover; /* 保持图片比例并填充整个容器 */
+}
+.custom-button {
+    width: 80px; /* 设置按钮的宽度 */
+    height: 30px; /* 设置按钮的高度 */
+    font-size: 14px; /* 设置按钮文字的字体大小 */
+  }

+ 17 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CaseParsePetmarketPage } from './case-parse-petmarket.page';
+
+describe('CaseParsePetmarketPage', () => {
+  let component: CaseParsePetmarketPage;
+  let fixture: ComponentFixture<CaseParsePetmarketPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CaseParsePetmarketPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 36 - 0
src/modules/study/case-js-module/case-parse-petmarket/case-parse-petmarket.page.ts

@@ -0,0 +1,36 @@
+import { Component, OnInit } from '@angular/core';
+import { PetService } from './pet.service';
+import Parse from "parse";
+@Component({
+  selector: 'app-case-parse-petmarket',
+  templateUrl: './case-parse-petmarket.page.html',
+  styleUrls: ['./case-parse-petmarket.page.scss'],
+})
+export class CaseParsePetmarketPage implements OnInit {
+  Foodcourts: any[] = [];
+  searchQuery: string = '';
+  selectedType: string = '';
+  FoodcourtTypes: string[] = ['购物', '特色美食', '历史文化', '自然风光'];
+  sortByName: boolean = false;
+ 
+  constructor(private FoodcourtService: PetService) {}
+  user:Parse.User|undefined
+  ngOnInit() {
+    this.user = Parse.User.current();
+    this.fetchFoodcourts();
+  }
+
+  async fetchFoodcourts() {
+    const queryParams = {
+      name: this.searchQuery,
+      type: this.selectedType,
+      sortByName: this.sortByName
+    };
+    this.Foodcourts = await this.FoodcourtService.getFoodcourts(queryParams);
+  }
+
+  toggleSort() {
+    this.sortByName = !this.sortByName;
+    this.fetchFoodcourts();
+  }
+}

+ 27 - 0
src/modules/study/case-js-module/case-parse-petmarket/pet.service.ts

@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+import Parse from 'parse';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class PetService {
+  private Foodcourt = Parse.Object.extend('Foodcourt');
+
+  constructor() {}
+
+  async getFoodcourts(queryParams: any): Promise<Parse.Object[]> {
+    const query = new Parse.Query(this.Foodcourt);
+    if (queryParams.name) {
+      query.contains('name', queryParams.name);
+    }
+    if (queryParams.type) {
+      query.equalTo('type', queryParams.type);
+    }
+    if (queryParams.sortByName) {
+      query.ascending('name');
+    } else {
+      query.descending('name');
+    }
+    return await query.find();
+  }
+}

+ 49 - 0
src/modules/study/case-js-module/case-parse/README.md

@@ -0,0 +1,49 @@
+# Parse JS SDK 使用示例
+
+- 使用文档:https://docs.parseplatform.org/js/guide/
+- API手册:https://parseplatform.org/Parse-SDK-JS/api/5.2.0/
+
+# 安装依赖
+``` bash
+npm i -S parse
+npm i -D @types/parse
+```
+配置 tsconfig.json
+``` json
+  "compilerOptions": {
+    "allowSyntheticDefaultImports": true,
+  }
+```
+
+# 设置微服务地址+参数
+
+``` ts
+// 引用Parse JS SDK
+import Parse from "parse";
+Parse.initialize("dev"); // 设置applicationId
+Parse.serverURL = "http://web2023.fmode.cn:9999/parse"; // 设置serverURL
+
+```
+
+# 示例:最简单的列表加载
+
+- pet.page.html
+``` html
+<ion-card *ngFor="let pet of petList">
+    {{pet.get("name")}}
+</ion-card>
+```
+
+- pet.page.ts
+``` ts
+ngOnInit() {
+    this.loadPets()
+  }
+  
+  petList:Array<Parse.Object> = []
+  async loadPets(){
+    let query = new Parse.Query("Pet");
+    let list = await query.find();
+    this.petList = list
+  }
+```

+ 17 - 0
src/modules/study/case-js-module/case-parse/case-parse-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CaseParsePage } from './case-parse.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CaseParsePage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CaseParsePageRoutingModule {}

+ 20 - 0
src/modules/study/case-js-module/case-parse/case-parse.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CaseParsePageRoutingModule } from './case-parse-routing.module';
+
+import { CaseParsePage } from './case-parse.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CaseParsePageRoutingModule
+  ],
+  declarations: [CaseParsePage]
+})
+export class CaseParsePageModule {}

+ 18 - 0
src/modules/study/case-js-module/case-parse/case-parse.page.html

@@ -0,0 +1,18 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>热门精选</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">南昌美食攻略</ion-title>
+    </ion-toolbar>
+  </ion-header>
+
+  <ion-card *ngFor="let Delicacy of DelicacyList" routerLink="/study/Delicacy/{{Delicacy.id}}">
+   <h2> {{Delicacy.get("name")}}</h2>
+    <img [src]="Delicacy.get('locationimage')" alt="Location Image">
+  </ion-card>
+</ion-content>

+ 5 - 0
src/modules/study/case-js-module/case-parse/case-parse.page.scss

@@ -0,0 +1,5 @@
+img {
+    width: 100%;
+    height: 120px;
+    object-fit: cover; /* 保持图片比例并填充整个容器 */
+}

+ 17 - 0
src/modules/study/case-js-module/case-parse/case-parse.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CaseParsePage } from './case-parse.page';
+
+describe('CaseParsePage', () => {
+  let component: CaseParsePage;
+  let fixture: ComponentFixture<CaseParsePage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CaseParsePage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 28 - 0
src/modules/study/case-js-module/case-parse/case-parse.page.ts

@@ -0,0 +1,28 @@
+import { Component, OnInit } from '@angular/core';
+
+// 引用Parse JS SDK
+import Parse from "parse";
+Parse.initialize("dev"); // 设置applicationId
+Parse.serverURL = "http://web2023.fmode.cn:9999/parse"; // 设置serverURL
+
+@Component({
+  selector: 'app-case-parse',
+  templateUrl: './case-parse.page.html',
+  styleUrls: ['./case-parse.page.scss'],
+})
+export class CaseParsePage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+    this.loadDelicacys()
+  }
+  
+  DelicacyList:Array<Parse.Object> = []
+  async loadDelicacys(){
+    let query = new Parse.Query("Delicacy");
+    let list = await query.find();
+    this.DelicacyList = list
+  }
+
+}

+ 71 - 0
src/modules/study/case-js-module/case-pet-detail/README.md

@@ -0,0 +1,71 @@
+
+# 详情页制作 + 路由跳转 + 路由传参 + 根据ID加载
+
+# 页面创建和路由配置
+
+``` bash
+ionic g page case-pet-detail
+```
+
+- 修改app-routing.module.ts
+``` ts
+  {
+        path: 'pet/:id',
+        loadChildren: () => import('../modules/study/case-js-module/case-pet-detail/case-pet-detail.module').then( m => m.CasePetDetailPageModule)
+      },
+```
+
+# 路由参数id的获取
+
+- case-pet-detail.page.ts
+``` ts
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import Parse from "parse";
+
+@Component({
+  selector: 'app-case-pet-detail',
+  templateUrl: './case-pet-detail.page.html',
+  styleUrls: ['./case-pet-detail.page.scss'],
+})
+export class CasePetDetailPage implements OnInit {
+
+  constructor(private route:ActivatedRoute) { }
+
+  ngOnInit() {
+    this.loadPetById()
+  }
+
+  pet:Parse.Object|undefined
+  async loadPetById(){
+    // let id = location.pathname.split("/").pop();
+    let id = this.route.snapshot.params["id"]
+
+    if(id){
+      let query = new Parse.Query("Pet");
+      this.pet = await query.get(id);
+    }
+  }
+
+}
+```
+
+# 根据ID获取数据的渲染
+> 注意:Parse.Object类型的数据,需要用.get获取内部属性,?.get避免空对象的情况
+- case-pet-detail.page.html
+``` html
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>{{pet?.get("name")}}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+
+  <ion-card>
+    {{pet?.get("type")}}
+    {{pet?.get("price")}}
+  </ion-card>
+</ion-content>
+
+```

+ 17 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CasePetDetailPage } from './case-pet-detail.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CasePetDetailPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CasePetDetailPageRoutingModule {}

+ 20 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CasePetDetailPageRoutingModule } from './case-pet-detail-routing.module';
+
+import { CasePetDetailPage } from './case-pet-detail.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CasePetDetailPageRoutingModule
+  ],
+  declarations: [CasePetDetailPage]
+})
+export class CasePetDetailPageModule {}

+ 18 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.html

@@ -0,0 +1,18 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>{{Delicacy?.get("name")}}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+
+  <ion-card>
+    <div *ngIf="Delicacy">
+      <!-- <h2>{{ Delicacy.get('name') }}</h2> -->
+      <img [src]="Delicacy.get('locationimage')" alt="Location Image">
+      <img [src]="Delicacy.get('foodimage')" alt="Food Image">
+      <h2>{{ Delicacy?.get('introduce') }}</h2>
+    </div>
+  </ion-card>
+
+</ion-content>

+ 0 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.scss


+ 17 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CasePetDetailPage } from './case-pet-detail.page';
+
+describe('CasePetDetailPage', () => {
+  let component: CasePetDetailPage;
+  let fixture: ComponentFixture<CasePetDetailPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CasePetDetailPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 32 - 0
src/modules/study/case-js-module/case-pet-detail/case-pet-detail.page.ts

@@ -0,0 +1,32 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import Parse from "parse";
+
+@Component({
+  selector: 'app-case-pet-detail',
+  templateUrl: './case-pet-detail.page.html',
+  styleUrls: ['./case-pet-detail.page.scss'],
+})
+export class CasePetDetailPage implements OnInit {
+
+  constructor(private route:ActivatedRoute) { }
+
+  ngOnInit() {
+    this.loadDelicacyById()
+  }
+
+  Delicacy:Parse.Object|undefined
+
+  async loadDelicacyById(){
+    // let id = location.pathname.split("/").pop();
+    let id = this.route.snapshot.params["id"]
+
+    if(id){
+      let query = new Parse.Query("Delicacy");
+      query.include("locationimage"); // 包含 locationimage 字段
+      query.include("foodimage"); // 包含 foodimage 字段
+      this.Delicacy = await query.get(id);
+    }
+  }
+
+}

+ 17 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CasePetEditPage } from './case-pet-edit.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CasePetEditPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CasePetEditPageRoutingModule {}

+ 20 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CasePetEditPageRoutingModule } from './case-pet-edit-routing.module';
+
+import { CasePetEditPage } from './case-pet-edit.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CasePetEditPageRoutingModule
+  ],
+  declarations: [CasePetEditPage]
+})
+export class CasePetEditPageModule {}

+ 26 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.html

@@ -0,0 +1,26 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>分享景点</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-list>
+    <ion-item>
+      <ion-input label="地点" type="text" [(ngModel)]="FoodcourtInfo.name"></ion-input>
+    </ion-item>
+    <ion-item>
+      <!-- <ion-label>种类</ion-label> -->
+      <ion-input label="类型" type="text" [(ngModel)]="FoodcourtInfo.type"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input label="介绍" type="string" [(ngModel)]="FoodcourtInfo.introduce"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-input label="图片" type="string" [(ngModel)]="FoodcourtInfo.image"></ion-input>
+    </ion-item>
+  </ion-list>
+
+  <ion-button expand="block" (click)="save()">保存</ion-button>
+  <ion-button expand="block" color="light" (click)="cancel()">取消</ion-button>
+</ion-content>

+ 0 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.scss


+ 17 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CasePetEditPage } from './case-pet-edit.page';
+
+describe('CasePetEditPage', () => {
+  let component: CasePetEditPage;
+  let fixture: ComponentFixture<CasePetEditPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CasePetEditPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 60 - 0
src/modules/study/case-js-module/case-pet-edit/case-pet-edit.page.ts

@@ -0,0 +1,60 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { NavController } from '@ionic/angular';
+import Parse from "parse";
+@Component({
+  selector: 'app-case-pet-edit',
+  templateUrl: './case-pet-edit.page.html',
+  styleUrls: ['./case-pet-edit.page.scss'],
+})
+export class CasePetEditPage implements OnInit {
+
+  constructor(
+    private route:ActivatedRoute,
+    private navCtrl:NavController
+  ) { 
+
+  }
+
+  // 宠物相关可编辑字段
+  FoodcourtInfo:any = {
+
+  }
+  async save(){
+    // 将petInfo当前编辑元素,逐个set到this.pet的Parse.Object里面去
+    console.log(this.FoodcourtInfo)
+    console.log(this.Foodcourt)
+    Object.keys(this.FoodcourtInfo).forEach(key=>{
+      this.Foodcourt?.set(key,this.FoodcourtInfo[key])
+    })
+    // 判断,当创建宠物无创建者,则将Parse.User的.toPointer()指针,赋值给user字段
+    if(!this.Foodcourt?.get("user")?.id) this.Foodcourt?.set("user",this.user?.toPointer())
+    await this.Foodcourt?.save()
+    this.navCtrl.back();
+  }
+  cancel(){
+    this.navCtrl.back();
+  }
+
+  user:Parse.User|undefined
+  ngOnInit() {
+    this.user = Parse.User.current();
+    this.loadFoodcourtById()
+  }
+
+  Foodcourt:Parse.Object|undefined
+  async loadFoodcourtById(){
+    // let id = location.pathname.split("/").pop();
+    let id = this.route.snapshot.params["id"]
+
+    if(id&&id!="new"){
+      let query = new Parse.Query("Foodcourt");
+      this.Foodcourt = await query.get(id);
+    }else{
+      let Foodcourt = Parse.Object.extend("Foodcourt");
+      this.Foodcourt = new Foodcourt();
+    }
+    this.FoodcourtInfo = this.Foodcourt?.toJSON()
+  }
+
+}