浏览代码

feat: new home page for textbook

MetaPunkGames 10 月之前
父节点
当前提交
455bd2343c
共有 32 个文件被更改,包括 1569 次插入116 次删除
  1. 49 104
      angular.json
  2. 6 0
      ionic.config.json
  3. 288 5
      package-lock.json
  4. 5 1
      package.json
  5. 二进制
      projects/textbook/public/favicon.ico
  6. 二进制
      projects/textbook/public/icon/left-arrow.png
  7. 二进制
      projects/textbook/public/icon/right-arrow.png
  8. 二进制
      projects/textbook/public/img/banner-lab.png
  9. 二进制
      projects/textbook/public/img/book.ico
  10. 二进制
      projects/textbook/public/img/book.png
  11. 1 0
      projects/textbook/public/img/book.svg
  12. 18 0
      projects/textbook/public/img/logo-authing.svg
  13. 8 0
      projects/textbook/src/app/app.component.ts
  14. 12 3
      projects/textbook/src/app/app.config.ts
  15. 1 1
      projects/textbook/src/app/app.routes.ts
  16. 1 1
      projects/textbook/src/index.html
  17. 10 0
      projects/textbook/src/modules/textbook/page-home/footer/footer.component.html
  18. 29 0
      projects/textbook/src/modules/textbook/page-home/footer/footer.component.scss
  19. 23 0
      projects/textbook/src/modules/textbook/page-home/footer/footer.component.spec.ts
  20. 11 0
      projects/textbook/src/modules/textbook/page-home/footer/footer.component.ts
  21. 66 0
      projects/textbook/src/modules/textbook/page-home/header/header.component.html
  22. 142 0
      projects/textbook/src/modules/textbook/page-home/header/header.component.scss
  23. 23 0
      projects/textbook/src/modules/textbook/page-home/header/header.component.spec.ts
  24. 231 0
      projects/textbook/src/modules/textbook/page-home/header/header.component.ts
  25. 242 0
      projects/textbook/src/modules/textbook/page-home/page-home.component.html
  26. 319 0
      projects/textbook/src/modules/textbook/page-home/page-home.component.scss
  27. 23 0
      projects/textbook/src/modules/textbook/page-home/page-home.component.spec.ts
  28. 18 0
      projects/textbook/src/modules/textbook/page-home/page-home.component.ts
  29. 11 0
      projects/textbook/src/modules/textbook/textbook-routing.module.ts
  30. 13 0
      projects/textbook/src/modules/textbook/textbook.module.ts
  31. 17 0
      projects/textbook/src/styles.scss
  32. 2 1
      src/app/app.config.ts

+ 49 - 104
angular.json

@@ -3,107 +3,6 @@
   "version": 1,
   "version": 1,
   "newProjectRoot": "projects",
   "newProjectRoot": "projects",
   "projects": {
   "projects": {
-    "edu-textbook": {
-      "projectType": "application",
-      "schematics": {
-        "@schematics/angular:component": {
-          "style": "scss"
-        }
-      },
-      "root": "",
-      "sourceRoot": "src",
-      "prefix": "app",
-      "architect": {
-        "build": {
-          "builder": "@angular-devkit/build-angular:application",
-          "options": {
-            "outputPath": "dist/edu-textbook",
-            "index": "src/index.html",
-            "browser": "src/main.ts",
-            "polyfills": [
-              "zone.js"
-            ],
-            "tsConfig": "tsconfig.app.json",
-            "inlineStyleLanguage": "scss",
-            "assets": [
-              {
-                "glob": "**/*",
-                "input": "public"
-              },
-              {
-                "glob": "**/*",
-                "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
-                "output": "/assets/"
-              }
-            ],
-            "styles": [
-              "src/theme.less",
-              "src/styles.scss"
-            ],
-            "scripts": []
-          },
-          "configurations": {
-            "production": {
-              "budgets": [
-                {
-                  "type": "initial",
-                  "maximumWarning": "500kB",
-                  "maximumError": "1MB"
-                },
-                {
-                  "type": "anyComponentStyle",
-                  "maximumWarning": "2kB",
-                  "maximumError": "4kB"
-                }
-              ],
-              "outputHashing": "all"
-            },
-            "development": {
-              "optimization": false,
-              "extractLicenses": false,
-              "sourceMap": true
-            }
-          },
-          "defaultConfiguration": "production"
-        },
-        "serve": {
-          "builder": "@angular-devkit/build-angular:dev-server",
-          "configurations": {
-            "production": {
-              "buildTarget": "edu-textbook:build:production"
-            },
-            "development": {
-              "buildTarget": "edu-textbook:build:development"
-            }
-          },
-          "defaultConfiguration": "development"
-        },
-        "extract-i18n": {
-          "builder": "@angular-devkit/build-angular:extract-i18n"
-        },
-        "test": {
-          "builder": "@angular-devkit/build-angular:karma",
-          "options": {
-            "polyfills": [
-              "zone.js",
-              "zone.js/testing"
-            ],
-            "tsConfig": "tsconfig.spec.json",
-            "inlineStyleLanguage": "scss",
-            "assets": [
-              {
-                "glob": "**/*",
-                "input": "public"
-              }
-            ],
-            "styles": [
-              "src/styles.scss"
-            ],
-            "scripts": []
-          }
-        }
-      }
-    },
     "textbook": {
     "textbook": {
       "projectType": "application",
       "projectType": "application",
       "schematics": {
       "schematics": {
@@ -130,11 +29,46 @@
               {
               {
                 "glob": "**/*",
                 "glob": "**/*",
                 "input": "projects/textbook/public"
                 "input": "projects/textbook/public"
+              },
+              {
+                "glob": "**/*",
+                "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
+                "output": "/assets/"
               }
               }
             ],
             ],
             "styles": [
             "styles": [
               "projects/textbook/src/styles.scss",
               "projects/textbook/src/styles.scss",
-              "node_modules/ng-zorro-antd/ng-zorro-antd.min.css"
+              "node_modules/ng-zorro-antd/ng-zorro-antd.min.css",
+              {
+                "input": "node_modules/@ionic/angular/css/core.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/normalize.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/structure.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/typography.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/display.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/padding.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/float-elements.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/text-alignment.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/text-transformation.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/flex-utils.css"
+              }
             ],
             ],
             "scripts": []
             "scripts": []
           },
           },
@@ -202,6 +136,17 @@
     }
     }
   },
   },
   "cli": {
   "cli": {
-    "analytics": "2bc1f0cc-3633-48b2-a456-d6ad82ce77e6"
+    "analytics": "2bc1f0cc-3633-48b2-a456-d6ad82ce77e6",
+    "schematicCollections": [
+      "@ionic/angular-toolkit"
+    ]
+  },
+  "schematics": {
+    "@ionic/angular-toolkit:component": {
+      "styleext": "scss"
+    },
+    "@ionic/angular-toolkit:page": {
+      "styleext": "scss"
+    }
   }
   }
-}
+}

+ 6 - 0
ionic.config.json

@@ -0,0 +1,6 @@
+{
+  "name": "ionic-app",
+  "app_id": "",
+  "type": "angular-standalone",
+  "integrations": {}
+}

+ 288 - 5
package-lock.json

@@ -16,7 +16,10 @@
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/router": "^18.0.0",
         "@angular/router": "^18.0.0",
+        "@ionic/angular": "^8.2.2",
+        "@types/parse": "^3.0.9",
         "ng-zorro-antd": "^18.0.0",
         "ng-zorro-antd": "^18.0.0",
+        "parse": "^5.1.0",
         "rxjs": "~7.8.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.14.3"
         "zone.js": "~0.14.3"
@@ -25,6 +28,7 @@
         "@angular-devkit/build-angular": "^18.0.4",
         "@angular-devkit/build-angular": "^18.0.4",
         "@angular/cli": "^18.0.4",
         "@angular/cli": "^18.0.4",
         "@angular/compiler-cli": "^18.0.0",
         "@angular/compiler-cli": "^18.0.0",
+        "@ionic/angular-toolkit": "latest",
         "@types/jasmine": "~5.1.0",
         "@types/jasmine": "~5.1.0",
         "jasmine-core": "~5.1.0",
         "jasmine-core": "~5.1.0",
         "karma": "~6.4.0",
         "karma": "~6.4.0",
@@ -2431,6 +2435,18 @@
         "node": ">=6.9.0"
         "node": ">=6.9.0"
       }
       }
     },
     },
+    "node_modules/@babel/runtime-corejs3": {
+      "version": "7.23.2",
+      "resolved": "https://registry.npmmirror.com/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz",
+      "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==",
+      "dependencies": {
+        "core-js-pure": "^3.30.2",
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/template": {
     "node_modules/@babel/template": {
       "version": "7.24.7",
       "version": "7.24.7",
       "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.24.7.tgz",
       "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.24.7.tgz",
@@ -2910,6 +2926,163 @@
         "node": ">=18"
         "node": ">=18"
       }
       }
     },
     },
+    "node_modules/@ionic/angular": {
+      "version": "8.2.2",
+      "resolved": "https://registry.npmmirror.com/@ionic/angular/-/angular-8.2.2.tgz",
+      "integrity": "sha512-c8siqeWN5iWvu7LlechiIYSWRAlvjL2dEKjB19xspAzZv+9aXrT9YWPz+DTeS2eTO6CnwvHJpG0tPlVxgjpr1g==",
+      "dependencies": {
+        "@ionic/core": "8.2.2",
+        "ionicons": "^7.0.0",
+        "jsonc-parser": "^3.0.0",
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/core": ">=16.0.0",
+        "@angular/forms": ">=16.0.0",
+        "@angular/router": ">=16.0.0",
+        "rxjs": ">=7.5.0",
+        "zone.js": ">=0.13.0"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmmirror.com/@ionic/angular-toolkit/-/angular-toolkit-11.0.1.tgz",
+      "integrity": "sha512-dxx2RDbxDYM2nWRPIirKMJySHtqJ1u02T25PGbNb99W2Wlcmu1cza3+2/PQ8ga18yMz/dQqaGyEmPDf3ZSVO0w==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "^17.0.0",
+        "@angular-devkit/schematics": "^17.0.0",
+        "@schematics/angular": "^17.0.0"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": {
+      "version": "17.3.8",
+      "resolved": "https://registry.npmmirror.com/@angular-devkit/core/-/core-17.3.8.tgz",
+      "integrity": "sha512-Q8q0voCGudbdCgJ7lXdnyaxKHbNQBARH68zPQV72WT8NWy+Gw/tys870i6L58NWbBaCJEUcIj/kb6KoakSRu+Q==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "8.12.0",
+        "ajv-formats": "2.1.1",
+        "jsonc-parser": "3.2.1",
+        "picomatch": "4.0.1",
+        "rxjs": "7.8.1",
+        "source-map": "0.7.4"
+      },
+      "engines": {
+        "node": "^18.13.0 || >=20.9.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "peerDependencies": {
+        "chokidar": "^3.5.2"
+      },
+      "peerDependenciesMeta": {
+        "chokidar": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": {
+      "version": "17.3.8",
+      "resolved": "https://registry.npmmirror.com/@angular-devkit/schematics/-/schematics-17.3.8.tgz",
+      "integrity": "sha512-QRVEYpIfgkprNHc916JlPuNbLzOgrm9DZalHasnLUz4P6g7pR21olb8YCyM2OTJjombNhya9ZpckcADU5Qyvlg==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "17.3.8",
+        "jsonc-parser": "3.2.1",
+        "magic-string": "0.30.8",
+        "ora": "5.4.1",
+        "rxjs": "7.8.1"
+      },
+      "engines": {
+        "node": "^18.13.0 || >=20.9.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": {
+      "version": "17.3.8",
+      "resolved": "https://registry.npmmirror.com/@schematics/angular/-/angular-17.3.8.tgz",
+      "integrity": "sha512-2g4OmSyE9YGq50Uj7fNI26P/TSAFJ7ZuirwTF2O7Xc4XRQ29/tYIIqhezpNlTb6rlYblcQuMcUZBrMfWJHcqJw==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "17.3.8",
+        "@angular-devkit/schematics": "17.3.8",
+        "jsonc-parser": "3.2.1"
+      },
+      "engines": {
+        "node": "^18.13.0 || >=20.9.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/ajv-formats": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz",
+      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/magic-string": {
+      "version": "0.30.8",
+      "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.8.tgz",
+      "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.4.15"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@ionic/angular-toolkit/node_modules/picomatch": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.1.tgz",
+      "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/@ionic/core": {
+      "version": "8.2.2",
+      "resolved": "https://registry.npmmirror.com/@ionic/core/-/core-8.2.2.tgz",
+      "integrity": "sha512-gpWemL5IJjGDJPz6dltHnFyqioRl0sugs2PUXrwPaYwMnTDoRZ6iojYFovCIr5YJN99rHZprOthdcsYR/viGyQ==",
+      "dependencies": {
+        "@stencil/core": "^4.17.2",
+        "ionicons": "^7.2.2",
+        "tslib": "^2.1.0"
+      }
+    },
     "node_modules/@isaacs/cliui": {
     "node_modules/@isaacs/cliui": {
       "version": "8.0.2",
       "version": "8.0.2",
       "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -3935,6 +4108,18 @@
       "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
       "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/@stencil/core": {
+      "version": "4.18.3",
+      "resolved": "https://registry.npmmirror.com/@stencil/core/-/core-4.18.3.tgz",
+      "integrity": "sha512-8yoG5AFQYEPocVtuoc5kvRS0Hku0MoDWDUpADRaXPVHsOFLmxR16LJENj25ucCz5GEfeTGQ/tCE8JAypPmr/fQ==",
+      "bin": {
+        "stencil": "bin/stencil"
+      },
+      "engines": {
+        "node": ">=16.0.0",
+        "npm": ">=7.10.0"
+      }
+    },
     "node_modules/@tufjs/canonical-json": {
     "node_modules/@tufjs/canonical-json": {
       "version": "2.0.0",
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
       "resolved": "https://registry.npmmirror.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
@@ -4121,7 +4306,6 @@
       "version": "20.14.6",
       "version": "20.14.6",
       "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.14.6.tgz",
       "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.14.6.tgz",
       "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==",
       "integrity": "sha512-JbA0XIJPL1IiNnU7PFxDXyfAwcwVVrOoqyzzyQTyMeVhBzkJVMSkC1LlVsRQ2lpqiY4n6Bb9oCS6lzDKVQxbZw==",
-      "dev": true,
       "dependencies": {
       "dependencies": {
         "undici-types": "~5.26.4"
         "undici-types": "~5.26.4"
       }
       }
@@ -4135,6 +4319,14 @@
         "@types/node": "*"
         "@types/node": "*"
       }
       }
     },
     },
+    "node_modules/@types/parse": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmmirror.com/@types/parse/-/parse-3.0.9.tgz",
+      "integrity": "sha512-DGTHygc7krgmNAK8h42giwmAofCd9uv2++RD+zw6OmWI7AEnlTYZwEuWsx22SA2CSMQrZW8P2INHLpQbnQFUng==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/qs": {
     "node_modules/@types/qs": {
       "version": "6.9.15",
       "version": "6.9.15",
       "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.15.tgz",
       "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.15.tgz",
@@ -5536,6 +5728,16 @@
         "url": "https://opencollective.com/core-js"
         "url": "https://opencollective.com/core-js"
       }
       }
     },
     },
+    "node_modules/core-js-pure": {
+      "version": "3.37.1",
+      "resolved": "https://registry.npmmirror.com/core-js-pure/-/core-js-pure-3.37.1.tgz",
+      "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==",
+      "hasInstallScript": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-util-is": {
     "node_modules/core-util-is": {
       "version": "1.0.3",
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
       "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -5713,6 +5915,12 @@
         "node": ">= 8"
         "node": ">= 8"
       }
       }
     },
     },
+    "node_modules/crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+      "optional": true
+    },
     "node_modules/css-loader": {
     "node_modules/css-loader": {
       "version": "7.1.1",
       "version": "7.1.1",
       "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-7.1.1.tgz",
       "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-7.1.1.tgz",
@@ -7275,6 +7483,11 @@
         "postcss": "^8.1.0"
         "postcss": "^8.1.0"
       }
       }
     },
     },
+    "node_modules/idb-keyval": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/idb-keyval/-/idb-keyval-6.2.1.tgz",
+      "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
+    },
     "node_modules/ieee754": {
     "node_modules/ieee754": {
       "version": "1.2.1",
       "version": "1.2.1",
       "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
       "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
@@ -7466,6 +7679,14 @@
         "url": "https://github.com/chalk/chalk?sponsor=1"
         "url": "https://github.com/chalk/chalk?sponsor=1"
       }
       }
     },
     },
+    "node_modules/ionicons": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmmirror.com/ionicons/-/ionicons-7.4.0.tgz",
+      "integrity": "sha512-ZK94MMqgzMCPPMhmk8Ouu6goyVHFIlw/ACP6oe3FrikcI0N7CX0xcwVaEbUc0G/v3W0shI93vo+9ve/KpvcNhQ==",
+      "dependencies": {
+        "@stencil/core": "^4.0.3"
+      }
+    },
     "node_modules/ip-address": {
     "node_modules/ip-address": {
       "version": "9.0.5",
       "version": "9.0.5",
       "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-9.0.5.tgz",
       "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-9.0.5.tgz",
@@ -7980,8 +8201,7 @@
     "node_modules/jsonc-parser": {
     "node_modules/jsonc-parser": {
       "version": "3.2.1",
       "version": "3.2.1",
       "resolved": "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
       "resolved": "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
-      "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
-      "dev": true
+      "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA=="
     },
     },
     "node_modules/jsonfile": {
     "node_modules/jsonfile": {
       "version": "4.0.0",
       "version": "4.0.0",
@@ -9745,6 +9965,25 @@
         "node": ">=6"
         "node": ">=6"
       }
       }
     },
     },
+    "node_modules/parse": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmmirror.com/parse/-/parse-5.1.0.tgz",
+      "integrity": "sha512-46gVRe1JHsh21Ht0/Ko6PeMDl6wELLMYxnZPFD6iZm2EWsWnzi2txNGE6PvnIv+G7yOufZIOD0BCZLYOFl3toA==",
+      "dependencies": {
+        "@babel/runtime-corejs3": "7.23.2",
+        "idb-keyval": "6.2.1",
+        "react-native-crypto-js": "1.0.0",
+        "uuid": "9.0.1",
+        "ws": "8.16.0",
+        "xmlhttprequest": "1.8.0"
+      },
+      "engines": {
+        "node": ">=18 <21"
+      },
+      "optionalDependencies": {
+        "crypto-js": "4.2.0"
+      }
+    },
     "node_modules/parse-json": {
     "node_modules/parse-json": {
       "version": "5.2.0",
       "version": "5.2.0",
       "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
       "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
@@ -9778,6 +10017,38 @@
         "node": ">= 0.10"
         "node": ">= 0.10"
       }
       }
     },
     },
+    "node_modules/parse/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/parse/node_modules/ws": {
+      "version": "8.16.0",
+      "resolved": "https://registry.npmmirror.com/ws/-/ws-8.16.0.tgz",
+      "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/parse5": {
     "node_modules/parse5": {
       "version": "7.1.2",
       "version": "7.1.2",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.1.2.tgz",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.1.2.tgz",
@@ -10312,6 +10583,11 @@
         "node": ">= 0.8"
         "node": ">= 0.8"
       }
       }
     },
     },
+    "node_modules/react-native-crypto-js": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/react-native-crypto-js/-/react-native-crypto-js-1.0.0.tgz",
+      "integrity": "sha512-FNbLuG/HAdapQoybeZSoes1PWdOj0w242gb+e1R0hicf3Gyj/Mf8M9NaED2AnXVOX01b2FXomwUiw1xP1K+8sA=="
+    },
     "node_modules/readable-stream": {
     "node_modules/readable-stream": {
       "version": "3.6.2",
       "version": "3.6.2",
       "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz",
       "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -11838,8 +12114,7 @@
     "node_modules/undici-types": {
     "node_modules/undici-types": {
       "version": "5.26.5",
       "version": "5.26.5",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
-      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
-      "dev": true
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
     },
     },
     "node_modules/unicode-canonical-property-names-ecmascript": {
     "node_modules/unicode-canonical-property-names-ecmascript": {
       "version": "2.0.0",
       "version": "2.0.0",
@@ -13055,6 +13330,14 @@
         }
         }
       }
       }
     },
     },
+    "node_modules/xmlhttprequest": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmmirror.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+      "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/y18n": {
     "node_modules/y18n": {
       "version": "5.0.8",
       "version": "5.0.8",
       "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
       "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

+ 5 - 1
package.json

@@ -18,7 +18,10 @@
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/router": "^18.0.0",
     "@angular/router": "^18.0.0",
+    "@ionic/angular": "^8.2.2",
+    "@types/parse": "^3.0.9",
     "ng-zorro-antd": "^18.0.0",
     "ng-zorro-antd": "^18.0.0",
+    "parse": "latest",
     "rxjs": "~7.8.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.14.3"
     "zone.js": "~0.14.3"
@@ -27,6 +30,7 @@
     "@angular-devkit/build-angular": "^18.0.4",
     "@angular-devkit/build-angular": "^18.0.4",
     "@angular/cli": "^18.0.4",
     "@angular/cli": "^18.0.4",
     "@angular/compiler-cli": "^18.0.0",
     "@angular/compiler-cli": "^18.0.0",
+    "@ionic/angular-toolkit": "latest",
     "@types/jasmine": "~5.1.0",
     "@types/jasmine": "~5.1.0",
     "jasmine-core": "~5.1.0",
     "jasmine-core": "~5.1.0",
     "karma": "~6.4.0",
     "karma": "~6.4.0",
@@ -36,4 +40,4 @@
     "karma-jasmine-html-reporter": "~2.1.0",
     "karma-jasmine-html-reporter": "~2.1.0",
     "typescript": "~5.4.2"
     "typescript": "~5.4.2"
   }
   }
-}
+}

二进制
projects/textbook/public/favicon.ico


二进制
projects/textbook/public/icon/left-arrow.png


二进制
projects/textbook/public/icon/right-arrow.png


二进制
projects/textbook/public/img/banner-lab.png


二进制
projects/textbook/public/img/book.ico


二进制
projects/textbook/public/img/book.png


+ 1 - 0
projects/textbook/public/img/book.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1718874967505" class="icon" viewBox="0 0 1316 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7097" xmlns:xlink="http://www.w3.org/1999/xlink" width="257.03125" height="200"><path d="M201.363749 0.219429h-0.073143a46.884571 46.884571 0 0 0-46.811429 47.104v706.486857c0 25.892571 21.065143 47.030857 47.104 47.104 109.714286 0.219429 293.376 23.113143 420.132572 155.721143V217.307429c0-8.777143-2.194286-17.042286-6.509715-23.844572C511.270034 25.965714 311.297463 0.438857 201.363749 0.219429zM1162.16832 753.810286V47.323429a46.884571 46.884571 0 0 0-46.811429-47.104h-0.146285c-109.933714 0.219429-309.833143 25.673143-413.842286 193.243428a45.129143 45.129143 0 0 0-6.509714 23.844572V956.708571c126.756571-132.608 310.491429-155.501714 420.132571-155.794285 26.038857 0 47.177143-21.211429 47.177143-47.030857z" fill="#4384F5" p-id="7098"></path><path d="M1269.468891 163.108571h-34.157714v590.701715c0 66.121143-53.906286 120.027429-120.173714 120.246857-92.964571 0.219429-246.345143 18.358857-354.962286 121.197714 187.830857-46.08 385.901714-16.091429 498.761143 9.581714a47.030857 47.030857 0 0 0 57.636571-45.860571V210.212571a47.177143 47.177143 0 0 0-47.104-47.104zM81.263177 753.810286V163.108571H47.105463A47.177143 47.177143 0 0 0 0.001463 210.212571v748.763429a46.957714 46.957714 0 0 0 57.636571 45.933714c112.859429-25.819429 310.857143-55.661714 498.761143-9.654857-108.617143-102.838857-261.997714-121.051429-354.962286-121.270857a120.539429 120.539429 0 0 1-120.173714-120.173714z" fill="#4384F5" p-id="7099"></path></svg>

+ 18 - 0
projects/textbook/public/img/logo-authing.svg

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="3483px" height="1935px" viewBox="0 0 3483 1935" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>svg横版</title>
+    <g id="svg横版" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="编组备份-4" transform="translate(742.000000, 708.500000)" fill="#396AFF">
+            <path d="M649.652831,286.751044 L689.540611,158.531551 L729.425777,286.751044 L649.652831,286.751044 Z M705.900271,105.937594 L673.178337,105.937594 L655.979786,105.937594 L555.310379,414.999284 L609.757211,414.999284 L634.427371,335.696744 L744.653851,335.696744 L769.321396,414.999284 L823.768228,414.999284 L723.098822,105.937594 L705.900271,105.937594 Z" id="Fill-1"></path>
+            <polygon id="Fill-2" points="1151.41355 129.498903 1102.46524 129.498903 1102.46524 177.529925 1067.36253 177.529925 1067.36253 226.478239 1102.46524 226.478239 1102.46524 412.839861 1151.41355 412.839861 1151.41355 226.478239 1186.51626 226.478239 1186.51626 177.529925 1151.41355 177.529925"></polygon>
+            <polygon id="Fill-3" points="1463.06639 412.838293 1512.01209 412.838293 1512.01209 183.557389 1463.06639 183.557389"></polygon>
+            <path d="M988.984336,313.684899 L988.984336,320.558047 C988.984336,349.237107 965.65222,372.569224 936.97316,372.569224 C908.2941,372.569224 884.961983,349.237107 884.961983,320.558047 L884.961983,313.684899 L885.225933,177.363977 L836.280233,177.363977 L836.544183,313.684899 L836.544183,320.558047 C836.544183,375.935237 881.59597,420.987025 936.97316,420.987025 C992.347736,420.987025 1037.39952,375.935237 1037.39952,320.558047 L1037.39952,313.684899 L1037.66609,177.363977 L988.717773,177.363977 L988.984336,313.684899 Z" id="Fill-4"></path>
+            <path d="M1894.52762,362.996732 C1864.70129,362.996732 1840.52244,335.783769 1840.52244,288.779799 C1840.52244,244.023322 1864.70129,214.562866 1894.52762,214.562866 C1924.35656,214.562866 1949.01365,243.87436 1949.01365,288.779799 C1949.01365,337.218506 1924.35656,362.996732 1894.52762,362.996732 L1894.52762,362.996732 Z M1997.95935,330.19117 L1997.95935,177.706589 L1949.01365,177.706589 L1949.01365,202.894194 C1931.55376,183.474284 1907.88191,172.485087 1882.00176,172.485087 C1829.03148,172.485087 1786.0939,218.650167 1786.0939,288.779799 C1786.0939,362.434859 1829.03148,405.074511 1882.00176,405.074511 C1907.88191,405.074511 1931.55376,395.405063 1949.01365,376.690761 L1949.01365,401.781672 L1949.05546,401.781672 L1949.05546,415.318899 C1949.05546,443.707875 1925.95593,466.807403 1897.56434,466.807403 C1869.17275,466.807403 1846.07584,443.707875 1846.07584,415.318899 L1796.61792,415.318899 C1796.61792,470.980945 1841.89968,516.265322 1897.56434,516.265322 C1953.229,516.265322 1998.51338,470.980945 1998.51338,415.318899 L1998.51338,330.19117 L1997.95935,330.19117 Z" id="Fill-6"></path>
+            <path d="M1487.53977,95.1984959 C1469.83422,95.1984959 1455.47901,109.553706 1455.47901,127.261863 C1455.47901,144.967406 1469.83422,159.322616 1487.53977,159.322616 C1505.24792,159.322616 1519.60313,144.967406 1519.60313,127.261863 C1519.60313,109.553706 1505.24792,95.1984959 1487.53977,95.1984959" id="Fill-8"></path>
+            <path d="M1679.51986,169.563084 L1668.45749,169.563084 C1642.3343,169.563084 1603.15213,188.387147 1603.15213,224.454188 L1603.15213,188.083997 L1554.20643,188.083997 L1554.20643,412.161693 L1603.15213,412.161693 L1603.15213,271.850163 C1603.15213,240.983717 1628.17771,215.960754 1659.04415,215.960754 C1686.71968,215.960754 1709.15541,238.396487 1709.15541,266.072015 L1709.15541,412.838555 L1763.31216,412.838555 L1763.31216,253.355384 C1763.31216,207.077929 1725.7947,169.563084 1679.51986,169.563084" id="Fill-10"></path>
+            <path d="M1341.18875,169.563084 L1330.12638,169.563084 C1306.38658,169.563084 1275.95395,181.111541 1267.72447,207.757404 L1267.72447,88.9982891 L1218.77615,88.9982891 L1218.77615,411.111121 L1267.72447,411.111121 L1267.72447,254.16814 C1275.12813,231.975451 1296.03243,215.960754 1320.71043,215.960754 C1348.38857,215.960754 1370.8243,238.396487 1370.8243,266.072015 L1370.8243,412.838555 L1424.98105,412.838555 L1424.98105,253.355384 C1424.98105,207.077929 1387.46359,169.563084 1341.18875,169.563084" id="Fill-12"></path>
+            <path d="M222.727626,464.784136 C117.100667,409.132543 45.0763467,298.284082 45.0763467,170.595102 C45.0763467,167.367597 45.1547476,164.158385 45.2462153,160.954401 L222.756373,52.7088509 L400.21165,160.954401 C400.300504,164.158385 400.381519,167.367597 400.381519,170.595102 C400.381519,298.284082 328.354585,409.132543 222.727626,464.784136 M445.208557,136.1588 L445.208557,136.1588 L222.756373,0.47031162 L0.246695214,136.1588 C0.131707184,140.178154 0.0350127044,144.200122 0.0350127044,148.24561 C0.0350127044,308.308948 90.3189097,447.258915 222.727626,517.022675 C355.136342,447.258915 445.420239,308.308948 445.420239,148.24561 C445.420239,144.200122 445.323545,140.178154 445.208557,136.1588" id="Fill-14"></path>
+            <path d="M262.461478,116.791941 L223.078078,189.929555 L268.487896,272.728776 L223.057171,344.324505 L177.629059,272.728776 L223.038878,189.929555 L184.483914,116.38687 L85.6961295,181.454414 L85.6961295,189.148159 C85.6961295,288.814034 141.755407,375.285032 224.196598,418.523145 C306.640402,374.919161 362.69968,288.448163 362.69968,189.148159 C362.69968,186.587062 362.69968,184.020738 362.69968,181.454414 L262.461478,116.791941 Z" id="Fill-16"></path>
+        </g>
+    </g>
+</svg>

+ 8 - 0
projects/textbook/src/app/app.component.ts

@@ -1,5 +1,6 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
 import { RouterOutlet } from '@angular/router';
 import { RouterOutlet } from '@angular/router';
+import Parse from "parse";
 
 
 @Component({
 @Component({
   selector: 'app-root',
   selector: 'app-root',
@@ -10,4 +11,11 @@ import { RouterOutlet } from '@angular/router';
 })
 })
 export class AppComponent {
 export class AppComponent {
   title = 'textbook';
   title = 'textbook';
+  constructor(){
+    this.initParseService();
+  }
+  initParseService(){
+    Parse.initialize("edu-textbook");
+    (Parse as any).serverURL = ("http://localhost:61337/parse");
+  }
 }
 }

+ 12 - 3
projects/textbook/src/app/app.config.ts

@@ -1,8 +1,17 @@
-import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
+
+import { ApplicationConfig, provideZoneChangeDetection, importProvidersFrom } from '@angular/core';
 import { provideRouter } from '@angular/router';
 import { provideRouter } from '@angular/router';
 
 
 import { routes } from './app.routes';
 import { routes } from './app.routes';
+import { zh_CN, provideNzI18n } from 'ng-zorro-antd/i18n';
+import { registerLocaleData } from '@angular/common';
+import zh from '@angular/common/locales/zh';
+import { FormsModule } from '@angular/forms';
+import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
+import { provideHttpClient } from '@angular/common/http';
+import { provideIonicAngular } from '@ionic/angular/standalone';
 
 
+registerLocaleData(zh);
 export const appConfig: ApplicationConfig = {
 export const appConfig: ApplicationConfig = {
-  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)]
-};
+  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideNzI18n(zh_CN), importProvidersFrom(FormsModule), provideAnimationsAsync(), provideHttpClient(), provideIonicAngular({})]
+};

+ 1 - 1
projects/textbook/src/app/app.routes.ts

@@ -3,7 +3,7 @@ import { Routes } from '@angular/router';
 import { CompUserComponent } from './comp-user/comp-user.component';
 import { CompUserComponent } from './comp-user/comp-user.component';
 
 
 export const routes: Routes = [
 export const routes: Routes = [
-  { path: '', redirectTo: '/user/login', pathMatch: 'full' }, // 默认跳转到 '/home'
+  { path: '',loadComponent:()=>import('../modules/textbook/page-home/page-home.component').then(m=>m.PageHomeComponent) }, // 默认跳转到 '/home'
   {
   {
     path: 'user', // 用户登录/注册
     path: 'user', // 用户登录/注册
     component: CompUserComponent,
     component: CompUserComponent,

+ 1 - 1
projects/textbook/src/index.html

@@ -2,7 +2,7 @@
 <html lang="en">
 <html lang="en">
 <head>
 <head>
   <meta charset="utf-8">
   <meta charset="utf-8">
-  <title>Textbook</title>
+  <title>国家级规划教材遴选系统 - 本科</title>
   <base href="/">
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="icon" type="image/x-icon" href="favicon.ico">

+ 10 - 0
projects/textbook/src/modules/textbook/page-home/footer/footer.component.html

@@ -0,0 +1,10 @@
+<!--页面底部内容-->
+<div class="footer">
+    <div class="link-box">
+        <div class="link-item"><a href="https://www.chsi.com.cn/">学信网</a></div>
+        <div class="link-item"><a href="#">帮助中心</a></div>
+        <div class="link-item"><a href="#">联系我们</a></div>
+        <!--版权所有-->
+        <div class="link-item">Copyright © 2024 蒸汽记忆 Rights Reserved</div>
+    </div>
+</div>

+ 29 - 0
projects/textbook/src/modules/textbook/page-home/footer/footer.component.scss

@@ -0,0 +1,29 @@
+//页面底部内容样式
+.footer{
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 70px;
+    min-width: 1100px;
+
+    .link-box{
+        display: flex;
+        flex-direction: row;
+        justify-content: space-evenly;
+
+    .link-item{
+        padding: 10px;
+        color: grey;
+    }
+
+    .link-item a{
+        text-decoration: none;
+        color: grey;
+    }
+
+    .link-item a:hover{
+        text-decoration: underline;
+        color: grey;
+    }
+    }
+}

+ 23 - 0
projects/textbook/src/modules/textbook/page-home/footer/footer.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FooterComponent } from './footer.component';
+
+describe('FooterComponent', () => {
+  let component: FooterComponent;
+  let fixture: ComponentFixture<FooterComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ FooterComponent ]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(FooterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 11 - 0
projects/textbook/src/modules/textbook/page-home/footer/footer.component.ts

@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-footer',
+  templateUrl: './footer.component.html',
+  styleUrls: ['./footer.component.scss'],
+  standalone:true,
+})
+export class FooterComponent {
+
+}

+ 66 - 0
projects/textbook/src/modules/textbook/page-home/header/header.component.html

@@ -0,0 +1,66 @@
+<!-- <fm-modal-user-login #loginModal></fm-modal-user-login> -->
+
+<!--页面顶部内容-->
+<div class="header">
+
+    <!--logo标识-->
+    <div class="logo-box">
+        <div class="logo-content" routerLink="/startup/home">
+            <img class="logo-img" src="/img/book.png" alt="feima-contest-logo">
+            <div class="logo-font">国家级规划教材遴选系统 - 本科</div>
+          </div>
+    </div>
+
+    <!--首页内容快速切换选项-->
+    <div class="quick-jump-box">
+
+        <div class="quick-jump-item" href="#submit">教材填报</div>
+        <div class="quick-jump-item" href="#review">遴选计划</div>
+        <div class="quick-jump-item" href="#contact">联系我们</div>
+        <!-- <div class="quick-jump-item">单项奖设置</div> -->
+        <!-- (click)="showModalSet()" -->
+        <!-- <nz-modal [(nzVisible)]="isVisibleSet" nzTitle="注意事项" nzOkText="确认"
+        nzCancelText="取消" (nzOnCancel)="handleCancelSet()" (nzOnOk)="handleOkSet()">
+            <ng-container *nzModalContent>
+              <p>请检查是否在个人页面的设置中完善个人信息,如未完善请先点击“<strong>取消</strong>”按钮退出弹框完善个人信息。已完善信息可直接点击“<strong>确认</strong>”按钮开始填写参赛信息。</p>
+            </ng-container>
+        </nz-modal> -->
+        <!-- routerLink="/startup/login"   routerLink="/startup/projectCreate"-->
+    </div>
+
+    <!-- <ng-template #rightAvatar> -->
+    <!--未登录-->
+    <!--管理及登录入口-->
+    <div *ngIf="!user?.id" class="login-manage-box"> 
+        <!--管理入口按钮-->
+        <div class="manage-box">
+            <button class="manage-button" routerLink="/user/login">管理入口</button>
+        </div>
+        <!--登录按钮-->
+        <div class="login-box">
+            <!-- <button class="login-button" (click)="loginModal.authServ.isModalShow = true">登录</button> -->
+            <button class="login-button" routerLink="/user/login">登录</button>
+        </div>
+    </div>
+    <!-- 已登录 -->
+    <!-- 展开列表 -->
+    <!-- <a nz-button nzType="default" style="margin-left: 5%; color:none; display: flex; flex-direction: row; align-items: center; cursor: pointer;" 
+    nz-dropdown [nzDropdownMenu]="menu" [nzPlacement]="'bottomRight'"
+    *ngIf="user?.id" class="login-box" [title]="user?.get('mobile')" > -->
+        <!-- 直接显示  -->
+        <!-- <app-comp-user-avatar *ngIf="user?.id" [user]="user" (click)="openUserMenu()" routerLink="/startup/userhome"></app-comp-user-avatar> -->
+
+        <!-- <div class="login-content" style="margin-left: 10px; display: flex; flex-direction: column; " routerLink="/startup/userhome">
+            <div class="login-item" style="display: flex; justify-content: center;">{{user?.get('mobile')}}</div>
+            <div class="login-item" style="display: flex; justify-content: center;">个人中心</div>
+        </div>
+
+        <div class="quit-box">
+            <button class="quit-button" (click)="logout()">退出</button>
+        </div> -->
+    <!-- </a> -->
+    <!-- </ng-template> -->
+
+    
+</div>
+

+ 142 - 0
projects/textbook/src/modules/textbook/page-home/header/header.component.scss

@@ -0,0 +1,142 @@
+//页面顶部内容样式
+.header{
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    position: relative;
+    top: 0;
+    height: 90px;
+    width: 100%;
+    min-width: 1100px;
+    border-bottom: 1px solid #f5f5f5;
+
+    //logo标识样式
+    .logo-box{
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+        width: 35%;
+
+        .logo-content{
+            display: flex;
+            cursor: pointer;
+        
+            .logo-img{
+                padding-right: 5px;
+                width: 50px;
+                object-fit: contain;
+            }
+    
+            .logo-font{
+                display: flex;
+                align-items: center;
+                font-size: 25px;
+                font-weight: bold;
+                font-style: italic;
+                color: #143383;
+            }
+        }
+    }
+
+    //首页内容快速切换选项样式
+    .quick-jump-box{
+        display: flex;
+        flex-direction: row;
+        justify-content: space-evenly;
+        width: 35%;
+    
+    .quick-jump-item{
+        font-size: 18px;
+        font-weight: bold;
+        border-bottom: 2px solid #fff;
+        box-sizing: border-box;
+        cursor: pointer;
+    }
+
+    .quick-jump-item:hover{
+        color: #143383;
+        border-bottom: 2px solid rgb(30, 93, 253);
+        box-sizing: border-box;
+    }
+
+    }
+
+    //管理及登录入口样式
+    .login-manage-box{
+        display: flex;
+        flex-direction: row;
+        width: 30%;
+
+    //管理入口按钮
+    .manage-box{
+        margin-left: 30%;
+        display: flex;
+
+        .manage-button{
+            border: none;
+            letter-spacing: 1px;
+            font-size: 16px;
+            color: #645bff;
+            background-color: white;
+            cursor: pointer;
+        }
+
+        .manage-button:hover{
+            border: none;
+            font-size: 16px;
+            color: #000;
+            background-color: white;
+        }
+    }
+    //登录按钮
+    .login-box{
+        margin-left: 5%;
+        display: flex;
+
+        .login-button {
+            padding: 10px;
+            letter-spacing: 1px;
+            border-radius: 10px;
+            border: none;
+            font-size: 16px;
+            color: #fff;
+            background-color: #143383;
+            transition: 0.5s;
+            cursor: pointer;
+           }
+           
+        .login-button:hover {
+            color: #fff;
+            background-color: #645bff;
+            transition: 0.5s;
+           }
+    }
+    
+}
+//退出按钮
+.quit-box{
+    margin-left: 5%;
+    display: flex;
+
+    .quit-button {
+        margin-left: 10%;
+        padding: 10px;
+        letter-spacing: 1px;
+        border-radius: 10px;
+        border: none;
+        min-width: 100px;
+        font-size: 16px;
+        color: #fff;
+        background-color: #143383;
+        transition: 0.5s;
+        cursor: pointer;
+       }
+       
+    .quit-button:hover {
+        color: #fff;
+        background-color: #645bff;
+        transition: 0.5s;
+       }
+}
+}

+ 23 - 0
projects/textbook/src/modules/textbook/page-home/header/header.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { HeaderComponent } from './header.component';
+
+describe('HeaderComponent', () => {
+  let component: HeaderComponent;
+  let fixture: ComponentFixture<HeaderComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ HeaderComponent ]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(HeaderComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 231 - 0
projects/textbook/src/modules/textbook/page-home/header/header.component.ts

@@ -0,0 +1,231 @@
+import { Component, HostListener, ViewChild, ElementRef } from '@angular/core';
+import { IonMenu, IonNav, NavController, Platform } from '@ionic/angular';
+import { NzModalModule } from 'ng-zorro-antd/modal';
+import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
+// import { AuthService } from 'ng-fmode-admin';
+// import { FormGroup, FormBuilder, Validators, AbstractControl } from '@angular/forms';
+import Parse from "parse";
+// import { AccountService } from '../../modules/account/account.service';
+import { HttpClient } from '@angular/common/http';
+import { NzMessageService } from "ng-zorro-antd/message";
+import { Router, RouterModule } from '@angular/router';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { CommonModule } from '@angular/common';
+@Component({
+  selector: 'app-header',
+  templateUrl: './header.component.html',
+  styleUrls: ['./header.component.scss'],
+  imports:[
+    CommonModule,RouterModule,
+    NzButtonModule,NzModalModule,NzDropDownModule,
+  ],
+  standalone:true,
+})
+export class HeaderComponent {
+  @ViewChild(IonMenu) menu:IonMenu|undefined=undefined
+  @ViewChild(IonMenu) userMenu:IonMenu|undefined=undefined
+  @ViewChild("canvas") canvas: ElementRef|undefined=undefined; //本地校验码绘画
+
+  //点击登录弹框设置
+  isLoginShow = false;
+
+  isVisible:boolean = false //分享弹窗
+  imgUrl:string = ""
+
+  openUserMenu(){
+    console.log("openUserMenu")
+    if(this.navMenuType=="mobile"){
+      console.log("mobile");
+      this.userMenu?.toggle();
+    }
+  }
+  user:Parse.User|undefined|null
+  mobileWidth = 915;
+  get leftMenuMode():string{
+    let clientWidth = document.body.clientWidth;
+    if(clientWidth>=915){
+      return "horizontal";
+    }else{
+
+      return "inline";
+    }
+  }
+  get navMenuType():string{
+    let clientWidth = document.body.clientWidth;
+    if(clientWidth>=915){
+      return "pc";
+    }else{
+
+      return "mobile";
+    }
+  }
+  get clientWidth():number {
+    let clientWidth = document.body.clientWidth;
+    return clientWidth
+  }
+  goFeima(){
+    window.open("https://www.fmode.cn","_blank")
+  }
+  isCapacitor:boolean = false
+  constructor(
+    // public authServ:AuthService,
+    // public accServ:AccountService,
+    private navCtrl:NavController,
+    private platform:Platform,
+    private http : HttpClient,
+    private message: NzMessageService,
+    public router:Router,
+    ){
+    // this.accServ.getBilling();
+    this.isCapacitor = this.platform.is("capacitor")
+    this.getCode()
+  }
+  setRoot(path:string){
+    if(this.menu?.close){
+      this.menu?.close();
+    }
+    this.navCtrl.navigateRoot(path);
+  }
+  async ngOnInit() {
+    this.user = await Parse.User.currentAsync()
+  }
+  logout(){
+    // this.authServ.logout(null,"../")
+  }
+
+  //海报
+  bannerUrl:string = 'https://file-cloud.fmode.cn/UP2cStyjuk/20231113/r1r7em033605088.jpg@3000w_1l_0o_100sh'
+  codeUrl:string|undefined = undefined
+  async getCode(){
+    let uid = (await Parse.User.currentAsync())?.id
+    let qrCodeUrl = `https://ai.fmode.cn/?invite=${uid}`;
+    let params = {
+      qrCode: qrCodeUrl,
+      darkColor: "#ffffff",
+      lightColor: "#000000"
+    }
+    this.http.get('https://server.fmode.cn/api/common/qrcode',{params})
+    .subscribe((res:any)=>{
+      // console.log(res);
+      this.codeUrl = res.data
+    })
+  }
+  
+  onShowModal(){
+    this.isVisible = true
+    this.drawPoster()
+  }
+  handleOk(){
+    this.onClose()
+  }
+  onClose(){
+    this.isVisible = false
+  }
+  //绘画海报
+  async drawPoster(){
+    let canvas:any = document.createElement('canvas')
+    canvas.height = '360'
+    canvas.width = '200'
+    // if(!canvas){
+    //   setTimeout(() => {
+    //     this.drawPoster()
+    //   }, 500);
+    //   return
+    // }
+    let ctx = canvas.getContext('2d');
+    //定义图片
+    ctx.drawImage(await this.compileImage(this.bannerUrl), 0, 0, 340, 540);
+    //绘制二维码
+    ctx.drawImage(await this.compileImage(this.codeUrl), 60 ,180, 80, 80);
+    let tempSrc = canvas.toDataURL("image/png");
+    this.imgUrl = tempSrc;
+    document.body.removeChild(canvas);
+  }
+  compileImage(url?:string): Promise<any>{
+    return new Promise((res)=>{
+      if(!url) {res(false);return}
+      let img = new Image();
+      img.src = url;
+      img.setAttribute('crossOrigin', 'anonymous');
+      img.onload = function() {
+        res (img)
+      }
+    })
+  }
+
+  /**
+   * 返回当前元素的文本内容
+  */
+  copyText(){
+    let uid = Parse.User.current()?.id
+    let text = `https://ai.fmode.cn/?invite=${uid}`;
+    let textareaC = document.createElement('textarea');
+    textareaC.setAttribute('readonly', 'readonly'); //设置只读属性防止手机上弹出软键盘
+    textareaC.value = text;
+    // textareaC.style.display = 'none'
+    document.body.appendChild(textareaC); //将textarea添加为body子元素
+    textareaC.select();
+    const res = document.execCommand('copy');
+    document.body.removeChild(textareaC);//移除DOM元素
+    console.log("复制成功");
+    this.message.success("复制成功");
+    window.location.href = 'weixin://';
+    return res;
+  }
+  /* 下载海报 */
+  downImg(){
+    let dlLink:any = document.createElement('a');
+    if ('download' in dlLink) {
+      dlLink.style.visibility = 'hidden';
+      dlLink.href = this.imgUrl;
+      dlLink.download = '分享海报';
+      document.body.appendChild(dlLink);
+      dlLink.click();
+      document.body.removeChild(dlLink);
+    } else {
+      location.href = this.imgUrl;
+    }
+  }
+
+  //登录逻辑引用
+  /**是否展示登录组件 */
+  isLoading:boolean=false
+
+  async goLogin(){
+    // let data:any
+    if(!Parse.User.current()?.getSessionToken()){
+      this.router.navigate(['startup/login'])
+      this.isLoading = true
+      setTimeout(() => {
+        this.goLogin()
+      }, 500);
+      return
+    }
+    this.isLoading = false
+   
+  }
+
+  // createBasicMessage(): void {
+  //   this.message.info('请先进行登录');
+  // }
+
+  //报名参赛提示框:提示完善个人信息
+  // isVisibleSet = false;
+
+
+  // showModalSet(): void {
+  //   this.goLogin();
+  //   this.isVisibleSet = true;
+  // }
+
+  // handleOkSet(): void {
+  //   // console.log('Button ok clicked!');
+  //   this.router.navigate(['startup/projectCreate'])
+  //   this.isVisibleSet = false;
+  // }
+
+  // handleCancelSet(): void {
+  //   // console.log('Button cancel clicked!');
+  //   this.isVisibleSet = false;
+  // }
+}

+ 242 - 0
projects/textbook/src/modules/textbook/page-home/page-home.component.html

@@ -0,0 +1,242 @@
+<ng-container>
+    <app-header></app-header>
+</ng-container>
+<div class="content">
+
+<!--图片盒子-->
+<div class="landscape-box">
+    <!-- Created by ai.fmode.cn imagine -->
+    <img class="landscape" src="/img/banner-lab.png" alt="feima-contest-background">
+
+    <div class="landscape-text">
+        <div class="landscape-title">《“十四五”普通高等教育本科国家级规划教材建设实施方案》</div>
+        <div class="landscape-desc">到2025年,教育部“十四五”本科规划教材重点立项建设1000种左右,遴选5000种左右,加快自主知识体系与教材体系建设,着力打造中国特色、世界水平的高质量教材体系,为高等教育强国建设提供坚实支撑。
+            <br>(一)深入推进新时代党的创新理论进教材
+            <br>(二)重点建设一批关键领域核心教材
+            <br>(三)培育和打造一批经典传承教材
+            <br>(四)探索建设一批示范性新形态教材
+            <br>“十四五”规划教材建设实行国家、省、校三级联动,有效衔接,全面建成国家、省、校三级本科规划教材体系。教育部采取重点立项与统一推荐遴选相结合方式,对“十四五”期间完成的新编或修订教材,开展“十四五”国家级规划教材认定工作。教材编写工作强化科教协同、产学合作,鼓励和支持打破部门、校际、学科专业和校内校外壁垒。
+    
+        </div>
+    </div>
+</div>
+
+<!--角色入口-->
+<div class="track-box" id="submit">
+
+    <div class="track-card">
+        <div class="button-card">
+        <button>
+            <span>教材创建</span>
+        </button>
+        </div>
+        
+        <div class="track-one-explain">作者、教师、主编</div>
+    </div>
+
+    <div class="track-card">
+        <div class="button-card">
+        <button>
+            <span>教材查看</span>
+        </button>
+        </div>
+        
+        <div class="track-one-explain">省属高校联系人</div>
+    </div>
+
+    <div class="track-card">
+        <div class="button-card">
+        <button>
+            <span>教材报送</span>
+        </button>
+        </div>
+        
+        <div class="track-one-explain">省级教育行政部门、出版单位联系人</div>
+    </div>
+
+
+    <div class="track-card">
+        <div class="button-card">
+        <button>
+            <span>教材公示</span>
+        </button>
+        </div>
+        
+        <div class="track-one-explain">省级教育行政部门报送人</div>
+    </div>
+</div>
+
+<!--模块标题:遴选计划-->
+<div class="module-title" id="review">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <div class="module-font">遴选计划</div>
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+</div>
+
+<!--遴选计划时间轴-->
+<div class="contest-plan-box">
+    <!-- <img class="contest-plan" src="https://file-cloud.fmode.cn/E4KpGvTEto/20231103/81nvch031047190.png" alt="contest-plan"> -->
+    <div class="box">
+        <div class="firstLine">
+            <ion-row>
+                <ion-col size='1.7'></ion-col>
+                <ion-col size='1.7'>
+                    <p class="text">提交</p>
+                    <div class="crossLine"></div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="date" style="margin-bottom: -2em;">2024.3.16 - 3.31</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="text">评审</p>
+                    <div class="crossLine"></div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="date" style="margin-bottom: -2em;">2024.05</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="text">公示</p>
+                    <div class="crossLine"></div>
+                </ion-col>
+                <ion-col size='1.7'></ion-col>
+            </ion-row>
+        </div>
+        <div class="seconfLine">
+            <ion-row>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer" style="background-color: unset;"></div>
+                            <div class="inner" style="background-color: unset;"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div></div>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer"></div>
+                            <div class="inner"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer"></div>
+                            <div class="inner"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer"></div>
+                            <div class="inner"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer"></div>
+                            <div class="inner"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer"></div>
+                            <div class="inner"></div>
+                        </div>
+                    </div>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="wrap">
+                        <div class="line"></div>
+                        <div class="ball">
+                            <div class="outer" style="background-color: unset;"></div>
+                            <div class="inner" style="background-color: unset;"></div>
+                        </div>
+                    </div>
+                </ion-col>
+            </ion-row>
+        </div>
+        <div class="thirdLine">
+            <ion-row>
+                <ion-col size='1.7'></ion-col>
+                <ion-col size='1.7'>
+                    <p class="date" style="margin-bottom: 2em;">2024.2.27 - 3.15</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="crossLine"></div>
+                    <p class="text" style="margin-bottom: unset;margin-top: 1em;">初审</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="date" style="margin-bottom: 2em;">2024.04</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <div class="crossLine"></div>
+                    <p class="text" style="margin-bottom: unset;margin-top: 1em;">报送</p>
+                </ion-col>
+                <ion-col size='1.7'>
+                    <p class="date" style="margin-bottom: 2em;">2024.06</p>
+                </ion-col>
+                <ion-col size='1.7'></ion-col>
+            </ion-row>
+        </div>
+    </div>
+</div>
+
+<!--模块标题:技术支持单位-->
+<div class="module-title">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <div class="module-font">技术支持</div>
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+</div>
+
+<!--技术支持单位展示盒子-->
+<div class="support-company-box">
+    <img class="company-icon" src="/img/logo-authing.svg" alt="contest-plan">
+</div>
+
+<!--模块标题:联系我们-->
+<div class="module-title" id="contact">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <img class="left-arrow" src="/icon/left-arrow.png" alt="left-arrow">
+    <div class="module-font">联系我们</div>
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+    <img class="right-arrow" src="/icon/right-arrow.png" alt="right-arrow">
+</div>
+
+<!--联系详情页-->
+<div class="contact-box">
+    <div class="contact-content">
+        <div class="contact-item">咨询: 教育部高等教育司教学条件处 刘某 010-66096925 gaojs_jxtj&#64;moe.edu.cn</div>
+        <div class="contact-item">咨询: 中国高等教育学会秘书处 赵某 010-59893293 gjxhjc&#64;hie.edu.cn</div>
+        <div class="contact-item">工作时间: 周一至周五 9:00-18:00</div>
+    </div>
+
+    <div class="erweima-box">
+        <img class="contact-erweima" src="https://files.authing.co/authing-website/wechat-code.jpg" alt="wx-erweima">
+    </div>
+</div>
+
+</div>

+ 319 - 0
projects/textbook/src/modules/textbook/page-home/page-home.component.scss

@@ -0,0 +1,319 @@
+.content{
+    margin: 0;
+    padding: 0;
+    width: auto;
+    min-width: 1100px;
+    height:calc(100% - 90px);
+    overflow-y: scroll;
+
+//图片盒子样式
+.landscape-box {
+    position: relative;
+    width: 100%;
+    height: 600px;
+    }
+
+    .landscape {
+        width: 100%;
+        height: 100%;
+        object-fit: cover;
+    }
+    .landscape-text{
+        position: absolute;
+        padding: 10px;
+        top: 12%;
+        left: 10%;
+        width:80%;
+        display: flex;
+        flex-direction: column;
+        text-align: left;
+        background-color: rgba(0, 0, 0, 0.4);
+        .landscape-title {
+            color: #fff;
+            font-size: 2rem;
+            font-family: FZZongYi-M05S;
+            font-weight: 600;
+        }
+        
+        .landscape-desc {
+            margin-top:20px;
+            margin-left:20px;
+            width: 60%;
+            font-size: 1rem;
+            color: #fff;
+            font-family: FZZhengHeiS-EB-GB;
+            font-style: italic;
+        }
+        
+}
+    //屏幕大小比例校准
+    @media (max-width: 1300px) {
+        .landscape-desc {
+            width: 50%;
+        }
+    }
+    
+    @media (min-width: 1500px) {
+        .landscape-desc {
+            width: 40%;
+        }
+    }
+
+
+//赛道盒子样式
+.track-box{
+    margin: 2% 5%;
+    display: flex;
+    flex-wrap:wrap;
+    flex-direction: row;
+    justify-content: space-evenly;
+
+    //码争赛道盒子样式
+    .track-card{
+        display: flex;
+        flex-direction: column;
+        justify-content: space-evenly;
+        position: relative;
+        width: 45%;
+        height: 180px;
+        margin-bottom: 10px;
+        background: #fff;
+        border: 1px solid var(--color-secondary-blue);
+        border-radius: 5px;
+        box-shadow: 4px 4px 4px rgba(78,120,203,0.75);
+
+    .button-card{
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+
+        //参考链接:https://uiverse.io/abrahamcalsin/sour-donkey-65
+        button {
+            position: relative;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            border-radius: 20px;
+            background: var(--color-primary-purple);
+            font-family: "Montserrat", sans-serif;
+            overflow: hidden;
+            border: none;
+            cursor: pointer;
+           }
+           
+           button:after {
+            content: " ";
+            width: 0%;
+            height: 100%;
+            background: #FFD401;
+            position: absolute;
+            transition: all 0.4s ease-in-out;
+            right: 0;
+           }
+           
+           button:hover::after {
+            right: auto;
+            left: 0;
+            width: 100%;
+           }
+           
+           button span {
+            text-align: center;
+            text-decoration: none;
+            width: 100%;
+            padding: 12px 19px;
+            color: #fff;
+            font-size: 18px;
+            font-weight: bold;
+            font-style: italic;
+            letter-spacing: 2px;
+            z-index: 20;
+            transition: all 0.3s ease-in-out;
+           }
+           
+           button:hover span {
+            color: var(--color-primary-purple);
+            animation: scaleUp 0.3s ease-in-out;
+           }
+           
+           @keyframes scaleUp {
+            0% {
+             transform: scale(1);
+            }
+           
+            50% {
+             transform: scale(0.95);
+            }
+           
+            100% {
+             transform: scale(1);
+            }
+           }
+    }
+
+    .track-one-explain{
+        display: flex;
+        justify-content: center;
+        font-size: 15px;
+        font-weight: bold;
+    }
+    }
+
+}
+
+//模块标题统一样式
+.module-title{
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 10%;
+    background-color: #f2f6fa;
+
+    .right-arrow{
+        width: 14px;
+        object-fit: contain;
+    }
+
+    .module-font{
+        padding: 1%;
+        font-size: 30px;
+        font-weight: bold;
+        font-style: italic;
+        color: #000;
+    }
+
+    .left-arrow{
+        width: 14px;
+        object-fit: contain;
+    }
+}
+
+//比赛计划详情样式
+.contest-plan-box{
+    display: flex;
+    justify-content: center;
+    .box{
+        width: 80%;
+        .crossLine{
+            height: 2px;
+            width: 25%;
+            background-color: var(--color-primary-purple);
+            margin-top: 5px;
+            transform: rotate(90deg);
+        }
+        .text{
+            font-size: x-large;
+            font-weight: bold;
+            color: var(--color-primary-purple);
+        }
+        .date{
+            font-size: medium;
+            font-weight: bold;
+        }
+        ion-row{
+            ion-col{
+                display: flex;
+                justify-content: center;
+                flex-direction: column;
+                align-items: center;
+            }
+        }
+        .firstLine{
+            width: 100%;
+        }
+        .seconfLine{
+            width: 100%;
+            margin: 1rem 0;
+            .wrap{
+                position: relative;
+                width: 100%;
+                display: flex;
+                justify-content: center;
+                .line{
+                    height: 2px;
+                    width: 100%;
+                    background-color: var(--color-primary-purple);
+                    position: absolute;
+                    margin-top: 3px;
+                }
+                .ball{
+                    align-items: center;
+                    display: flex;
+                    justify-content: center;
+                    position: relative;
+                    width: 17px;
+                    .outer{
+                        border-radius: 50%;
+                        height: 17px;
+                        left: 0;
+                        opacity: .2;
+                        position: absolute;
+                        width: 17px;
+                        background-color: rgba(255, 0, 0, 0.486);
+                      
+                        transition: background-color 0.3s, width 0.3s, height 0.3s , margin-left 0.3s;
+                      }
+                      
+                      .outer:hover {
+                        background-color: rgba(255, 0, 0, 0.486);
+                        margin-left: -0.5rem;
+                        width: 34px;
+                        height: 34px;
+                    }
+                    .inner{
+                        border-radius: 50%;
+                        height: 9px;
+                        width: 9px;
+                        background-color: red;
+                    }
+                }
+            }
+        }
+    }
+}
+
+//技术支持单位展示样式
+.support-company-box{
+    display: flex;
+    justify-content: center;
+
+    .company-icon{
+        width: 160px;
+        object-fit: contain;
+    }
+}
+
+//联系详情页样式
+.contact-box{
+    padding: 1% 0;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+
+    .contact-content{
+        display: flex;
+        flex-direction: column;
+
+        .contact-item{
+            padding: 1% 0;
+            font-size: 16px;
+            font-weight: 600;
+        }
+    }
+
+    .erweima-box{
+        padding-left: 5%;
+        display: flex;
+        align-items: center;
+
+        .contact-erweima{
+            width: 100px;
+            object-fit: contain;
+        }
+    }
+}
+
+}

+ 23 - 0
projects/textbook/src/modules/textbook/page-home/page-home.component.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PageHomeComponent } from './page-home.component';
+
+describe('PageHomeComponent', () => {
+  let component: PageHomeComponent;
+  let fixture: ComponentFixture<PageHomeComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ PageHomeComponent ]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(PageHomeComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 18 - 0
projects/textbook/src/modules/textbook/page-home/page-home.component.ts

@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
+import { FooterComponent } from './footer/footer.component';
+import { HeaderComponent } from './header/header.component';
+
+@Component({
+  selector: 'app-page-home',
+  templateUrl: './page-home.component.html',
+  styleUrls: ['./page-home.component.scss'],
+  standalone:true,
+  imports:[
+    HeaderComponent,FooterComponent,
+    IonicModule
+  ]
+})
+export class PageHomeComponent {
+  constructor(){}
+}

+ 11 - 0
projects/textbook/src/modules/textbook/textbook-routing.module.ts

@@ -0,0 +1,11 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class TextbookRoutingModule { }

+ 13 - 0
projects/textbook/src/modules/textbook/textbook.module.ts

@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { TextbookRoutingModule } from './textbook-routing.module';
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    TextbookRoutingModule
+  ]
+})
+export class TextbookModule { }

+ 17 - 0
projects/textbook/src/styles.scss

@@ -1 +1,18 @@
 /* You can add global styles to this file, and also import other style files */
 /* You can add global styles to this file, and also import other style files */
+:root{
+    --color-primary-blue:#143383;
+    --color-secondary-blue:#645bff;
+    --color-primary-purple:#143383;
+}
+// --color-primary-purle:#7F30C5;
+/**
+ * Ionic Dark Theme
+ * -----------------------------------------------------
+ * For more info, please see:
+ * https://ionicframework.com/docs/theming/dark-mode
+ */
+
+//  @import "@ionic/angular/css/palettes/dark.always.css";
+ /* @import "@ionic/angular/css/palettes/dark.class.css"; */
+ /* @import "@ionic/angular/css/palettes/dark.system.css"; */
+ 

+ 2 - 1
src/app/app.config.ts

@@ -8,9 +8,10 @@ import zh from '@angular/common/locales/zh';
 import { FormsModule } from '@angular/forms';
 import { FormsModule } from '@angular/forms';
 import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
 import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
 import { provideHttpClient } from '@angular/common/http';
 import { provideHttpClient } from '@angular/common/http';
+import { provideIonicAngular } from '@ionic/angular/standalone';
 
 
 registerLocaleData(zh);
 registerLocaleData(zh);
 
 
 export const appConfig: ApplicationConfig = {
 export const appConfig: ApplicationConfig = {
-  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideNzI18n(zh_CN), importProvidersFrom(FormsModule), provideAnimationsAsync(), provideHttpClient()]
+  providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideNzI18n(zh_CN), importProvidersFrom(FormsModule), provideAnimationsAsync(), provideHttpClient(), provideIonicAngular({})]
 };
 };