fangmingyue 1 年之前
當前提交
d2c21193e3

+ 4
- 0
.env 查看文件

@@ -0,0 +1,4 @@
1
+
2
+BASE_SERVER=http://192.168.89.25:9906/api/web
3
+IMG_SERVER=http://192.168.89.25:7777/
4
+PUBLIC_SERVER=http://192.168.89.76:3001/api/web

+ 2
- 0
.env.production 查看文件

@@ -0,0 +1,2 @@
1
+
2
+DATA_SERVER=http://192.168.89.25:9906/api/web

+ 18
- 0
.gitignore 查看文件

@@ -0,0 +1,18 @@
1
+# build output
2
+dist/
3
+
4
+# generated types
5
+.astro/
6
+
7
+# dependencies
8
+node_modules/
9
+
10
+# logs
11
+npm-debug.log*
12
+yarn-debug.log*
13
+yarn-error.log*
14
+pnpm-debug.log*
15
+
16
+
17
+# macOS-specific files
18
+.DS_Store

+ 4
- 0
.vscode/extensions.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+  "recommendations": ["astro-build.astro-vscode"],
3
+  "unwantedRecommendations": []
4
+}

+ 11
- 0
.vscode/launch.json 查看文件

@@ -0,0 +1,11 @@
1
+{
2
+  "version": "0.2.0",
3
+  "configurations": [
4
+    {
5
+      "command": "./node_modules/.bin/astro dev",
6
+      "name": "Development server",
7
+      "request": "launch",
8
+      "type": "node-terminal"
9
+    }
10
+  ]
11
+}

+ 54
- 0
README.md 查看文件

@@ -0,0 +1,54 @@
1
+# Astro Starter Kit: Basics
2
+
3
+```sh
4
+npm create astro@latest -- --template basics
5
+```
6
+
7
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
8
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
9
+[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
10
+
11
+> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
12
+
13
+![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
14
+
15
+## 🚀 Project Structure
16
+
17
+Inside of your Astro project, you'll see the following folders and files:
18
+
19
+```text
20
+/
21
+├── public/
22
+│   └── favicon.svg
23
+├── src/
24
+│   ├── components/
25
+│   │   └── Card.astro
26
+│   ├── layouts/
27
+│   │   └── Layout.astro
28
+│   └── pages/
29
+│       └── index.astro
30
+└── package.json
31
+```
32
+
33
+Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
34
+
35
+There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
36
+
37
+Any static assets, like images, can be placed in the `public/` directory.
38
+
39
+## 🧞 Commands
40
+
41
+All commands are run from the root of the project, from a terminal:
42
+
43
+| Command                   | Action                                           |
44
+| :------------------------ | :----------------------------------------------- |
45
+| `npm install`             | Installs dependencies                            |
46
+| `npm run dev`             | Starts local dev server at `localhost:4321`      |
47
+| `npm run build`           | Build your production site to `./dist/`          |
48
+| `npm run preview`         | Preview your build locally, before deploying     |
49
+| `npm run astro ...`       | Run CLI commands like `astro add`, `astro check` |
50
+| `npm run astro -- --help` | Get help using the Astro CLI                     |
51
+
52
+## 👀 Want to learn more?
53
+
54
+Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

+ 26
- 0
astro.config.mjs 查看文件

@@ -0,0 +1,26 @@
1
+import { defineConfig } from 'astro/config';
2
+// import { defineConfig } from "vite";
3
+import node from '@astrojs/node';
4
+import sitemap from '@astrojs/sitemap';
5
+import react from "@astrojs/react";
6
+
7
+// https://astro.build/config
8
+export default defineConfig({
9
+  output: 'server',
10
+  adapter: node({
11
+    mode: 'standalone',
12
+  }),
13
+  // vite: {
14
+  //   server: {
15
+  //     host: true,
16
+  //     port: 8080,
17
+  //     proxy: {
18
+  //       '/api/web/taConcatUs': {
19
+  //         target: 'http://192.168.89.25:9906/api/web/taConcatUs',
20
+  //         changeOrigin: true
21
+  //       },
22
+  //     }
23
+  //   },
24
+  // },
25
+  integrations: [react(), sitemap()]
26
+});

+ 14
- 0
jsconfig.json 查看文件

@@ -0,0 +1,14 @@
1
+{
2
+  "extends": "astro/tsconfigs/base",
3
+  "compilerOptions": {
4
+    "jsx": "react-jsx",
5
+    "jsxImportSource": "react",
6
+    "baseUrl": ".",
7
+    "paths": {
8
+      "@/components/*": ["src/components/*"],
9
+      "@/layouts/*": ["src/layouts/*"],
10
+      "@/services/*": ["src/services/*"],
11
+      "@/utils/*": ["src/utils/*"]
12
+    }
13
+  }
14
+}

+ 5799
- 0
package-lock.json
文件差異過大導致無法顯示
查看文件


+ 23
- 0
package.json 查看文件

@@ -0,0 +1,23 @@
1
+{
2
+  "name": "academe",
3
+  "type": "module",
4
+  "version": "0.0.1",
5
+  "scripts": {
6
+    "dev": "astro dev",
7
+    "start": "astro dev",
8
+    "build": "astro build",
9
+    "preview": "astro preview",
10
+    "astro": "astro"
11
+  },
12
+  "dependencies": {
13
+    "@astrojs/node": "^7.0.4",
14
+    "@astrojs/react": "^3.0.9",
15
+    "@astrojs/sitemap": "^3.0.4",
16
+    "@types/react": "^18.2.48",
17
+    "@types/react-dom": "^18.2.18",
18
+    "astro": "^4.1.3",
19
+    "axios": "^1.6.5",
20
+    "react": "^18.2.0",
21
+    "react-dom": "^18.2.0"
22
+  }
23
+}

+ 9
- 0
public/favicon.svg 查看文件

@@ -0,0 +1,9 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
2
+    <path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
3
+    <style>
4
+        path { fill: #000; }
5
+        @media (prefers-color-scheme: dark) {
6
+            path { fill: #FFF; }
7
+        }
8
+    </style>
9
+</svg>

二進制
public/image/girl.png 查看文件


二進制
public/image/nightsky.png 查看文件


二進制
public/image/otter.png 查看文件


二進制
public/image/wolf.png 查看文件


二進制
public/logo.png 查看文件


+ 9
- 0
src/components/BigImg.astro 查看文件

@@ -0,0 +1,9 @@
1
+---
2
+import Img from '@/components/children/Img.astro'
3
+---
4
+
5
+<!-- 一张大图 -->
6
+<Img
7
+  url="//e.huawei.com/-/mediae/images/home/secondbanner/secondbanner-pc.jpg"
8
+  ratio="3 / 1"
9
+/>

+ 61
- 0
src/components/Card.astro 查看文件

@@ -0,0 +1,61 @@
1
+---
2
+interface Props {
3
+	title: string;
4
+	body: string;
5
+	href: string;
6
+}
7
+
8
+const { href, title, body } = Astro.props;
9
+---
10
+
11
+<li class="link-card">
12
+	<a href={href}>
13
+		<h2>
14
+			{title}
15
+			<span>&rarr;</span>
16
+		</h2>
17
+		<p>
18
+			{body}
19
+		</p>
20
+	</a>
21
+</li>
22
+<style>
23
+	.link-card {
24
+		list-style: none;
25
+		display: flex;
26
+		padding: 1px;
27
+		background-color: #23262d;
28
+		background-image: none;
29
+		background-size: 400%;
30
+		border-radius: 7px;
31
+		background-position: 100%;
32
+		transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
33
+		box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
34
+	}
35
+	.link-card > a {
36
+		width: 100%;
37
+		text-decoration: none;
38
+		line-height: 1.4;
39
+		padding: calc(1.5rem - 1px);
40
+		border-radius: 8px;
41
+		color: white;
42
+		background-color: #23262d;
43
+		opacity: 0.8;
44
+	}
45
+	h2 {
46
+		margin: 0;
47
+		font-size: 1.25rem;
48
+		transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
49
+	}
50
+	p {
51
+		margin-top: 0.5rem;
52
+		margin-bottom: 0;
53
+	}
54
+	.link-card:is(:hover, :focus-within) {
55
+		background-position: 0;
56
+		background-image: var(--accent-gradient);
57
+	}
58
+	.link-card:is(:hover, :focus-within) h2 {
59
+		color: rgb(var(--accent-light));
60
+	}
61
+</style>

+ 9
- 0
src/components/FirstScreen.astro 查看文件

@@ -0,0 +1,9 @@
1
+---
2
+import Img from '@/components/children/Img.astro'
3
+---
4
+
5
+<!-- 首屏图 -->
6
+<Img
7
+  url="//e.huawei.com/-/mediae/images/home/banner/jiasu-banner-pc1.jpg"
8
+  ratio="16 / 9"
9
+/>

+ 60
- 0
src/components/Footer.astro 查看文件

@@ -0,0 +1,60 @@
1
+---
2
+import { arr2Tree } from '@/utils/array'
3
+
4
+const [menus] = arr2Tree(Astro.locals._menus || [])
5
+
6
+const { lang } = Astro.props
7
+
8
+const home = lang == 'zh' ? '首页' : 'Home'
9
+function getName(item = {}) {
10
+  return (
11
+    item[`categaryName${lang.charAt(0).toUpperCase() + lang.slice(1)}`] ||
12
+    item.categaryNameEn ||
13
+    item.categaryNameZh
14
+  )
15
+}
16
+
17
+const colNum = Math.ceil(12 / (menus?.length + 1))
18
+---
19
+
20
+<div class="bg-l">
21
+  <div class="container">
22
+    <footer class="row py-5 my-5">
23
+      <div class={`col-md-4 col-sm-12 mb-3`}>
24
+        <a
25
+          href="/"
26
+          class="d-flex align-items-center mb-3 link-body-emphasis text-decoration-none"
27
+        >
28
+          <img class="bi me-2" width="120" src="../logo.png" />
29
+        </a>
30
+        <p class="text-body-secondary">© 2024</p>
31
+      </div>
32
+
33
+      <div class={`col-md-1 col-sm-12 mb-3`}></div>
34
+
35
+      <div class={`col-md-7 col-sm-12 mb-3 row justify-content-between`}>
36
+        {
37
+          menus?.map((item) => {
38
+            return (
39
+              <div class={`col-md-${colNum} col-sm-12 mb-3`}>
40
+                <h5>{getName(item)}</h5>
41
+                <ul class="nav flex-column">
42
+                  {item?.children?.map((child) => (
43
+                    <li class="nav-item mb-2">
44
+                      <a
45
+                        href={`/${lang}/${child.categaryId}`}
46
+                        class="nav-link p-0 text-body-secondary"
47
+                      >
48
+                        {getName(child)}
49
+                      </a>
50
+                    </li>
51
+                  ))}
52
+                </ul>
53
+              </div>
54
+            )
55
+          })
56
+        }
57
+      </div>
58
+    </footer>
59
+  </div>
60
+</div>

+ 9
- 0
src/components/LeftMiddleRightImgText.astro 查看文件

@@ -0,0 +1,9 @@
1
+---
2
+import Img from '@/components/children/Img.astro'
3
+---
4
+
5
+<!-- 左中右图文 -->
6
+<Img
7
+  url="//e.huawei.com/-/mediae/images/home/secondbanner/secondbanner-pc.jpg"
8
+  ratio="3 / 1"
9
+/>

+ 81
- 0
src/components/LeftOneMiddleRightFour.astro 查看文件

@@ -0,0 +1,81 @@
1
+---
2
+const { json, lang } = Astro.props
3
+
4
+const list = [
5
+  {
6
+    src: '//e.huawei.com/-/mediae/images/home/whatsnew/whatsnew-high-quality-cloudcampus-cn-0315-v3.png',
7
+    title: '标题',
8
+    desc: '内容',
9
+  },
10
+  {
11
+    src: '//e.huawei.com/-/mediae/images/home/whatsnew/whatsnew-high-quality-cloudcampus-cn-0315-v3.png',
12
+    title: '标题',
13
+    desc: '内容',
14
+  },
15
+  {
16
+    src: '//e.huawei.com/-/mediae/images/home/whatsnew/whatsnew-high-quality-cloudcampus-cn-0315-v3.png',
17
+    title: '标题',
18
+    desc: '内容',
19
+  },
20
+  {
21
+    src: '//e.huawei.com/-/mediae/images/home/whatsnew/whatsnew-high-quality-cloudcampus-cn-0315-v3.png',
22
+    title: '标题',
23
+    desc: '内容',
24
+  },
25
+]
26
+---
27
+
28
+<!-- 左中右图片(左一右四) -->
29
+<div class="container">
30
+  <div class="row">
31
+    {
32
+      list?.map((item, index) => (
33
+        <div class="col-md-4 col-sm-12 my-5 px-5" id={index}>
34
+          <div
35
+            class="top-bottom-project-card"
36
+            style={index ? 'cursor: pointer' : ''}
37
+            data-post={index}
38
+          >
39
+            <div class="card border-0">
40
+              <img
41
+                src={item?.src}
42
+                class="card-img-top object-fit-cover img-fluid top-bottom-project-card-img1"
43
+                alt=""
44
+                style="width:100%;aspect-ratio: 4 / 3"
45
+              />
46
+              <div class="card-body px-0">
47
+                <h5 class="card-title line-ellipsis fw-bolder">
48
+                  {item?.title}
49
+                </h5>
50
+                <p class="card-text line-ellipsis-2 mb-1 fw-lighter">
51
+                  <Fragment set:html={item?.desc} />
52
+                </p>
53
+              </div>
54
+            </div>
55
+          </div>
56
+        </div>
57
+      ))
58
+    }
59
+  </div>
60
+</div>
61
+<style>
62
+  .top-bottom-project-card-img1:hover {
63
+    box-shadow: 8px 12px 12px 0 rgba(14, 14, 14, 0.2);
64
+  }
65
+  .line-ellipsis {
66
+    display: -webkit-box;
67
+    height: 2.4em;
68
+    -webkit-line-clamp: 2;
69
+    -webkit-box-orient: vertical;
70
+    overflow: hidden;
71
+    text-overflow: ellipsis;
72
+  }
73
+  .line-ellipsis-2 {
74
+    display: -webkit-box;
75
+    height: 4.2em;
76
+    -webkit-line-clamp: 3;
77
+    -webkit-box-orient: vertical;
78
+    overflow: hidden;
79
+    text-overflow: ellipsis;
80
+  }
81
+</style>

+ 115
- 0
src/components/LeftRightCarousel.astro 查看文件

@@ -0,0 +1,115 @@
1
+---
2
+const domId = `carousel-${Math.random().toString(36).substring(2, 7)}`
3
+
4
+const data = [
5
+  [
6
+    {
7
+      postId: '111',
8
+      src: 'https://e.huawei.com/-/mediae/images/home/whatsnew/whatsnew-primary-storage.jpg',
9
+    },
10
+  ],
11
+]
12
+---
13
+
14
+<!-- 左右轮播图 -->
15
+<div class="container">
16
+  <div id={domId} class="carousel slide" data-bs-ride="carousel">
17
+    <div class="carousel-inner">
18
+      {
19
+        data?.map((item, index) => (
20
+          <div
21
+            class={index == 0 ? 'carousel-item active' : 'carousel-item'}
22
+            id={index}
23
+          >
24
+            <div class="row">
25
+              {item.map((it, index) => (
26
+                <div class="col-md-4 col-sm-12 my-5 px-5">
27
+                  <div
28
+                    class="top-bottom-project-card-carousel"
29
+                    style={it.postId ? 'cursor: pointer' : ''}
30
+                    data-post={it.postId}
31
+                  >
32
+                    <div class="card border-0">
33
+                      <div>
34
+                        <img
35
+                          src={it?.src}
36
+                          class="card-img-top object-fit-cover img-fluid top-bottom-project-card-carousel-img"
37
+                          style="aspect-ratio:4 / 3"
38
+                          alt=""
39
+                        />
40
+                      </div>
41
+                      <div class="card-body px-0">
42
+                        <h5 class="card-title line-ellipsis-tbpcc fw-bolder">
43
+                          {it}
44
+                        </h5>
45
+                        <p class="card-text line-ellipsis-tbpcc2 mb-1 fw-lighter">
46
+                          <Fragment set:html={it} />
47
+                        </p>
48
+                      </div>
49
+                    </div>
50
+                  </div>
51
+                </div>
52
+              ))}
53
+            </div>
54
+          </div>
55
+        ))
56
+      }
57
+    </div>
58
+    <button
59
+      class="carousel-control-prev"
60
+      type="button"
61
+      data-bs-target={`#${domId}`}
62
+      data-bs-slide="prev"
63
+    >
64
+      <span
65
+        class="carousel-control-prev-icon"
66
+        style="background-color: #696969;"></span>
67
+      <span class="visually-hidden">Previous</span>
68
+    </button>
69
+    <button
70
+      class="carousel-control-next"
71
+      type="button"
72
+      data-bs-target={`#${domId}`}
73
+      data-bs-slide="next"
74
+    >
75
+      <span
76
+        class="carousel-control-next-icon"
77
+        style="background-color: #696969;"></span>
78
+      <span class="visually-hidden">Next</span>
79
+    </button>
80
+  </div>
81
+</div>
82
+
83
+<style>
84
+  .top-bottom-project-card-carousel-img:hover {
85
+    box-shadow: 8px 12px 12px 0 rgba(14, 14, 14, 0.2);
86
+  }
87
+  .line-ellipsis-tbpcc {
88
+    display: -webkit-box;
89
+    height: 2.4em;
90
+    -webkit-line-clamp: 2;
91
+    -webkit-box-orient: vertical;
92
+    overflow: hidden;
93
+    text-overflow: ellipsis;
94
+  }
95
+  .line-ellipsis-tbpcc2 {
96
+    display: -webkit-box;
97
+    height: 4.2em;
98
+    -webkit-line-clamp: 3;
99
+    -webkit-box-orient: vertical;
100
+    overflow: hidden;
101
+    text-overflow: ellipsis;
102
+  }
103
+</style>
104
+
105
+<script>
106
+  const path = window.location.pathname
107
+  var lang = path.substring(1, 3)
108
+
109
+  const items = document.querySelectorAll(`.top-bottom-project-card-carousel`)
110
+  items.forEach((item) => {
111
+    item.addEventListener('click', () => {
112
+      window.location.href = `${window.location.origin}/${lang}/detail?id=${item.dataset.post}`
113
+    })
114
+  })
115
+</script>

+ 66
- 0
src/components/NavItem.astro 查看文件

@@ -0,0 +1,66 @@
1
+---
2
+const { menu, lang } = Astro.props
3
+const hasChildren = menu?.children?.length > 0
4
+
5
+function getName(item = {}) {
6
+  return (
7
+    item[`categaryName${lang.charAt(0).toUpperCase() + lang.slice(1)}`] ||
8
+    item.categaryNameEn ||
9
+    item.categaryNameZh
10
+  )
11
+}
12
+
13
+const list = [
14
+  ['网络安全', '全闪存存储', 'AI计算', '软件平台与服务'],
15
+  // ['智慧园区', '数据中心', '广域网点'],
16
+  // ['金融', '商业市场', '电力', '制造', '医疗', '零售'],
17
+  ['关于华为企业业务'],
18
+]
19
+---
20
+
21
+<!-- <li class="nav-item dropdown mx-3">
22
+  <a
23
+    class="nav-link dropdown-toggle"
24
+    aria-current="page"
25
+    data-bs-toggle="dropdown"
26
+    href="/">{menu}</a
27
+  >
28
+  <ul
29
+    class="dropdown-menu bg-light"
30
+    style="--bs-bg-opacity: 0.9; --bs-dropdown-border-width: 0; --bs-dropdown-border-radius: 0; margin-top: 1.2rem"
31
+  >
32
+    {
33
+      list?.map((item) => (
34
+        <li>
35
+          <a class="dropdown-item" href="/">
36
+            {item}
37
+          </a>
38
+        </li>
39
+      ))
40
+    }
41
+  </ul>
42
+</li> -->
43
+<li class={hasChildren ? 'nav-item dropdown mx-3' : 'nav-item mx-3'}>
44
+  <a
45
+    class={hasChildren ? 'nav-link dropdown-toggle' : 'nav-link'}
46
+    aria-current="page"
47
+    data-bs-toggle={hasChildren ? 'dropdown' : ''}
48
+    href="/">{menu?.name}</a
49
+  >
50
+  {
51
+    hasChildren ? (
52
+      <ul
53
+        class="dropdown-menu bg-light"
54
+        style="--bs-bg-opacity: 0.9; --bs-dropdown-border-width: 0; --bs-dropdown-border-radius: 0; margin-top: 1.2rem"
55
+      >
56
+        {menu?.children?.map((item) => (
57
+          <li>
58
+            <a class="dropdown-item" href={`/${lang}/${item.categaryId}`}>
59
+              {item}
60
+            </a>
61
+          </li>
62
+        ))}
63
+      </ul>
64
+    ) : null
65
+  }
66
+</li>

+ 130
- 0
src/components/Navbar.astro 查看文件

@@ -0,0 +1,130 @@
1
+---
2
+import { arr2Tree } from '@/utils/array'
3
+import NavItem from './NavItem.astro'
4
+
5
+const [menus] = arr2Tree(Astro.locals._menus || [])
6
+const path = Astro.url.pathname
7
+const searchId = Astro.url.search
8
+var pathname = path.substring(4)
9
+const url = pathname.length == 0 ? '' : pathname
10
+const { lang } = Astro.props
11
+const title = 'Aacademe'
12
+
13
+const language = lang === 'zh' ? '简体中文' : 'English'
14
+
15
+const me = [
16
+  {
17
+    name: '产品与解决方案',
18
+    children: ['网络安全', '全闪存存储', 'AI计算', '软件平台与服务'],
19
+  },
20
+  {
21
+    name: '了解我们',
22
+    children: ['关于华为企业业务'],
23
+  },
24
+]
25
+---
26
+
27
+<nav
28
+  id="pageNav"
29
+  class="navbar navbar-expand-md fixed-top bg-light p-0 py-3"
30
+  style="--bs-bg-opacity: 0.9"
31
+>
32
+  <div class="container">
33
+    <button
34
+      class="navbar-toggler"
35
+      type="button"
36
+      data-bs-toggle="offcanvas"
37
+      data-bs-target="#academeNav"
38
+      aria-controls="academeNav"
39
+      aria-expanded="false"
40
+      aria-label="Toggle navigation"
41
+    >
42
+      <span class="navbar-toggler-icon"></span>
43
+    </button>
44
+    <a class="navbar-brand" href={`/${lang}/`}>
45
+      <img
46
+        src="https://e.huawei.com/-/mediae/images/common/logo/logo_huawei.png"
47
+        alt="Academe"
48
+        width="120"
49
+        class="d-inline-block align-text-top"
50
+      />
51
+    </a>
52
+    <div id="academeNav" class="offcanvas-lg offcanvas-end">
53
+      <div class="offcanvas-header">
54
+        <a class="navbar-brand" href={`/${lang}/`}>
55
+          <img
56
+            src="../logo.png"
57
+            alt="Academe"
58
+            width="120"
59
+            class="d-inline-block align-text-top"
60
+          />
61
+        </a>
62
+      </div>
63
+      <div class="offcanvas-body">
64
+        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
65
+          {
66
+            me.map((item, index) => (
67
+              <NavItem key={index} menu={item} lang={lang} />
68
+            ))
69
+          }
70
+          <li class="nav-item dropdown">
71
+            <a
72
+              class="nav-link dropdown-toggle"
73
+              aria-current="page"
74
+              data-bs-toggle="dropdown"
75
+              href="#"
76
+            >
77
+              {language}
78
+            </a>
79
+
80
+            <ul
81
+              class="dropdown-menu bg-light"
82
+              style="--bs-bg-opacity: 0.9; --bs-dropdown-border-width: 0; --bs-dropdown-border-radius: 0; margin-top: 1.2rem"
83
+            >
84
+              <li class="lang-btn" data-lang="zh">
85
+                <a class="dropdown-item" href=`/zh/${url}${searchId}`
86
+                  >简体中文</a
87
+                >
88
+              </li>
89
+              <li class="lang-btn" data-lang="en">
90
+                <a class="dropdown-item" href=`/en/${url}${searchId}`>English</a
91
+                >
92
+              </li>
93
+            </ul>
94
+          </li>
95
+        </ul>
96
+      </div>
97
+    </div>
98
+  </div>
99
+</nav>
100
+
101
+<script>
102
+  const pageNav = document.querySelector('#pageNav')
103
+
104
+  function pageNavScroll() {
105
+    const offset = window.pageYOffset
106
+    // console.log('----offset-----', offset)
107
+    if (offset > 450) {
108
+      pageNav.style.opacity = 0
109
+      pageNav.style.display = 'none'
110
+    } else if (offset > 50) {
111
+      const diff = (450 - offset) / 400
112
+      pageNav.style.opacity = diff
113
+    } else {
114
+      pageNav.style.opacity = 1
115
+      pageNav.style.display = 'block'
116
+    }
117
+  }
118
+
119
+  pageNavScroll()
120
+  window.addEventListener('scroll', pageNavScroll)
121
+
122
+  const langBtns = document.querySelectorAll('.lang-btn')
123
+  langBtns.forEach((btn) => {
124
+    btn.addEventListener('click', (e) => {
125
+      // e.preventDefault();
126
+      const lang = btn.dataset.lang
127
+      localStorage.setItem('lang', lang)
128
+    })
129
+  })
130
+</script>

+ 26
- 0
src/components/Request.astro 查看文件

@@ -0,0 +1,26 @@
1
+<!-- <script>
2
+  var request = window.axios.create({
3
+    baseURL: import.meta.env.PUBLIC_SERVER,
4
+    timeout: 10000,
5
+  })
6
+  window.request = request
7
+
8
+  request.interceptors.request.use((config) => {
9
+    // 暂无需要处理的内容
10
+    return config
11
+  })
12
+
13
+  request.interceptors.response.use((response) => {
14
+    const { data, status } = response
15
+
16
+    if (data?.code === 1000 || data?.code === 200) {
17
+      return data.data
18
+    }
19
+
20
+    if (data?.message || data?.msg) {
21
+      throw new Error(data?.message || data?.msg)
22
+    }
23
+
24
+    throw new Error(`网络异常 - ${status}`)
25
+  })
26
+</script> -->

+ 58
- 0
src/components/ScrollingNavbar.astro 查看文件

@@ -0,0 +1,58 @@
1
+---
2
+const { sNav } = Astro.props
3
+---
4
+
5
+<nav
6
+  id="scrolling-navbar"
7
+  class="navbar navbar-expand-lg bg-body-tertiary fixed-top"
8
+  style="margin-top: 5rem;z-index:10"
9
+>
10
+  <div class="container">
11
+    <button
12
+      class="navbar-toggler"
13
+      type="button"
14
+      data-bs-toggle="collapse"
15
+      data-bs-target="#navbarScroll"
16
+      aria-controls="navbarScroll"
17
+      aria-expanded="false"
18
+      aria-label="Toggle navigation"
19
+    >
20
+      <span class="navbar-toggler-icon"></span>
21
+    </button>
22
+    <div class="collapse navbar-collapse" id="navbarScroll">
23
+      <ul
24
+        class="navbar-nav me-auto my-2 my-lg-0 navbar-nav-scroll d-flex justify-content-between"
25
+        style="--bs-scroll-height: 100px;--bs-bg-opacity: 0.9;flex:1"
26
+      >
27
+        {
28
+          sNav?.map((item, index) => (
29
+            <li class="nav-item mb-2">
30
+              <a
31
+                class={index == 0 ? 'nav-link active' : 'nav-link'}
32
+                href={`#${item}`}
33
+              >
34
+                {item}
35
+              </a>
36
+            </li>
37
+          ))
38
+        }
39
+      </ul>
40
+    </div>
41
+  </div>
42
+</nav>
43
+
44
+<script>
45
+  const NavMargin = document.querySelector('#scrolling-navbar')
46
+
47
+  function pagescrollingNavbarMargin() {
48
+    const offset = window.pageYOffset
49
+    if (offset > 450) {
50
+      NavMargin.style.marginTop = 0
51
+    } else {
52
+      NavMargin.style.marginTop = '5em'
53
+    }
54
+  }
55
+
56
+  pagescrollingNavbarMargin()
57
+  window.addEventListener('scroll', pagescrollingNavbarMargin)
58
+</script>

+ 83
- 0
src/components/children/Carousel.astro 查看文件

@@ -0,0 +1,83 @@
1
+---
2
+const {} = Astro.props
3
+const domId = `carousel-${Math.random().toString(36).substring(2, 7)}`
4
+const list = [
5
+  {
6
+    value: [
7
+      {
8
+        url: 'https://e.huawei.com/-/mediae/images/home/casestorys/casestorys-shenyang-metro.jpg',
9
+      },
10
+    ],
11
+  },
12
+  {
13
+    value: [
14
+      {
15
+        url: 'https://e.huawei.com/-/mediae/images/home/casestorys/casestorys-wuling-manufacturing-plant.jpg',
16
+      },
17
+    ],
18
+  },
19
+]
20
+---
21
+
22
+<!-- 轮播 -->
23
+<div class="container">
24
+  <div id={domId} class="carousel slide" data-bs-ride="carousel">
25
+    <div class="carousel-inner">
26
+      {
27
+        list?.map((item, index) => (
28
+          <div
29
+            class={index == 0 ? 'carousel-item active' : 'carousel-item'}
30
+            id={index}
31
+          >
32
+            <div class="row">
33
+              {item.value.map((it, index) => (
34
+                <img
35
+                  src={it?.url}
36
+                  class="img-fluid object-fit-cover"
37
+                  style="width:30%;aspect-ratio:4 / 3"
38
+                  alt=""
39
+                />
40
+              ))}
41
+            </div>
42
+          </div>
43
+        ))
44
+      }
45
+    </div>
46
+    <button
47
+      class="carousel-control-prev"
48
+      type="button"
49
+      data-bs-target={`#${domId}`}
50
+      data-bs-slide="prev"
51
+    >
52
+      <span
53
+        class="carousel-control-prev-icon"
54
+        style="background-color: #696969;"></span>
55
+      <span class="visually-hidden">Previous</span>
56
+    </button>
57
+    <button
58
+      class="carousel-control-next"
59
+      type="button"
60
+      data-bs-target={`#${domId}`}
61
+      data-bs-slide="next"
62
+    >
63
+      <span
64
+        class="carousel-control-next-icon"
65
+        style="background-color: #696969;"></span>
66
+      <span class="visually-hidden">Next</span>
67
+    </button>
68
+  </div>
69
+</div>
70
+
71
+<style></style>
72
+
73
+<script>
74
+  const path = window.location.pathname
75
+  var lang = path.substring(1, 3)
76
+
77
+  const items = document.querySelectorAll(`.top-bottom-project-card-carousel`)
78
+  items.forEach((item) => {
79
+    item.addEventListener('click', () => {
80
+      window.location.href = `${window.location.origin}/${lang}/detail?id=${item.dataset.post}`
81
+    })
82
+  })
83
+</script>

+ 11
- 0
src/components/children/Img.astro 查看文件

@@ -0,0 +1,11 @@
1
+---
2
+const { url, ratio, circle = '', transformEnlarge = '' } = Astro.props
3
+---
4
+
5
+<!-- 图片 -->
6
+<img
7
+  src={url}
8
+  class=`img-fluid object-fit-cover ${circle} ${transformEnlarge}`
9
+  style=`aspect-ratio:${ratio}`
10
+  alt=""
11
+/>

+ 22
- 0
src/components/children/Text.astro 查看文件

@@ -0,0 +1,22 @@
1
+---
2
+const { textSize, textColor, textWeight, btnDisplay, textUnderline } =
3
+  Astro.props
4
+---
5
+
6
+<!-- 文本 -->
7
+<div>
8
+  <p class="fs-4 mb-0">上汽通用五菱</p>
9
+  <p class="fs-4">打造全球首个“岛式”精益智造工厂</p>
10
+  <div class="text-underline"></div>
11
+  <p class="text-secondary">重新定义汽车总装方式</p>
12
+  <button type="button" class="btn btn-outline-danger">了解更多</button>
13
+</div>
14
+
15
+<style>
16
+  .text-underline {
17
+    width: 100px;
18
+    border-bottom: 2px solid red;
19
+    margin-left: 50px;
20
+    margin-bottom: 1em;
21
+  }
22
+</style>

+ 1
- 0
src/env.d.ts 查看文件

@@ -0,0 +1 @@
1
+/// <reference types="astro/client" />

+ 73
- 0
src/layouts/Layout.astro 查看文件

@@ -0,0 +1,73 @@
1
+---
2
+import Request from '@/components/Request.astro'
3
+const { title } = Astro.props
4
+---
5
+
6
+<!doctype html>
7
+<html lang="zh">
8
+  <head>
9
+    <meta charset="UTF-8" />
10
+    <meta name="description" content="Astro description" />
11
+    <meta name="viewport" content="width=device-width" />
12
+    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
13
+    <link
14
+      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
15
+      rel="stylesheet"
16
+      crossorigin="anonymous"
17
+    />
18
+    <script
19
+      src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
20
+      crossorigin="anonymous"></script>
21
+    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
22
+    <meta name="generator" content={Astro.generator} />
23
+    <title>{title} - Academe</title>
24
+    <style is:global>
25
+      html,
26
+      body {
27
+        height: 100%;
28
+        margin: 0 !important;
29
+        padding: 0 !important;
30
+        background: transparent linear-gradient(0deg, #1f2935, #1f2935) 0 100%
31
+          no-repeat;
32
+      }
33
+
34
+      @media screen and (min-width: 1900px) {
35
+        .container {
36
+          max-width: 1600px;
37
+        }
38
+      }
39
+
40
+      .bg-d {
41
+        background: transparent linear-gradient(0deg, #1f2935, #1f2935) 0 100%
42
+          no-repeat;
43
+      }
44
+
45
+      .bg-l {
46
+        background: #fff;
47
+      }
48
+
49
+      .cc-module {
50
+      }
51
+
52
+      .x-motion {
53
+        overflow: hidden;
54
+      }
55
+
56
+      .x-motion img {
57
+        width: 100%; /* 按照容器宽度自适应 */
58
+        transition: transform 0.3s ease-in-out;
59
+      }
60
+
61
+      .x-motion img:hover {
62
+        transform: scale(1.1);
63
+      }
64
+
65
+      :root {
66
+      }
67
+    </style>
68
+  </head>
69
+  <body>
70
+    <!-- <Request client:load /> -->
71
+    <slot />
72
+  </body>
73
+</html>

+ 12
- 0
src/middleware.js 查看文件

@@ -0,0 +1,12 @@
1
+// import { sequence } from "astro:middleware";
2
+// import { getCategary } from "./services/apis";
3
+
4
+
5
+// async function getGloalData(context, next) {
6
+//   const menus = await getCategary();
7
+//   context.locals._menus = menus;
8
+  
9
+//   return next();
10
+// }
11
+
12
+// export const onRequest = sequence(getGloalData);

+ 32
- 0
src/pages/[lang]/[categaryId].astro 查看文件

@@ -0,0 +1,32 @@
1
+---
2
+import Layout from '@/layouts/Layout.astro'
3
+import Footer from '@/components/Footer.astro'
4
+import Navbar from '@/components/Navbar.astro'
5
+// import Dynamic from '@/components/Dynamic.astro'
6
+import { getContentList } from '@/services/apis'
7
+
8
+function getName(item = {}) {
9
+  return (
10
+    item[`categaryName${lang.charAt(0).toUpperCase() + lang.slice(1)}`] ||
11
+    item.categaryNameEn ||
12
+    item.categaryNameZh
13
+  )
14
+}
15
+
16
+const { categaryId, lang = 'zh' } = Astro.params
17
+const categary = Astro.locals._menus?.find(
18
+  (item) => item.categaryId == categaryId
19
+)
20
+const title = getName(categary)
21
+
22
+// const contentList = await getContentList(categaryId);
23
+---
24
+
25
+<Layout title={title}>
26
+  <!-- 导航栏 -->
27
+  <Navbar lang={lang} />
28
+
29
+  <!-- <Dynamic contentList={contentList} lang={lang} /> -->
30
+
31
+  <Footer lang={lang} />
32
+</Layout>

+ 48
- 0
src/pages/[lang]/detail/index.astro 查看文件

@@ -0,0 +1,48 @@
1
+---
2
+import Layout from '@/layouts/Layout.astro'
3
+import Footer from '@/components/Footer.astro'
4
+import Navbar from '@/components/Navbar.astro'
5
+import ScrollingNavbar from '@/components/ScrollingNavbar.astro'
6
+import { getPostById } from '@/services/apis'
7
+const { lang = 'zh' } = Astro.params
8
+console.log('---------fff------>', lang)
9
+var url = new URL(Astro.request.url)
10
+var id = url.searchParams.get('id')
11
+// const post = await getPostById(id)
12
+function getContent(item = {}) {
13
+  return (
14
+    item[`content${lang.charAt(0).toUpperCase() + lang.slice(1)}`] ||
15
+    item.contentEn ||
16
+    item.contentZh
17
+  )
18
+}
19
+
20
+// 使用中文标题即ID
21
+// 保存所有生成的 id
22
+const ids = []
23
+
24
+function appendHId(html) {
25
+  const reg = /(<)(h\d)(>(.*?)<\/h\d>)/g
26
+
27
+  return html.replaceAll(reg, (_, p1, p2, p3, p4) => {
28
+    ids.push(p4)
29
+    return `${p1}${p2} id="${p4}"${p3}`
30
+  })
31
+}
32
+
33
+// let contentHtml = getContent(post)
34
+// contentHtml = appendHId(contentHtml)
35
+---
36
+
37
+<Layout>
38
+  <Navbar lang={lang} />
39
+  <ScrollingNavbar sNav={ids} />
40
+  <div class="container-fulid" style="margin-top: 9rem;background-color:#fff">
41
+    <div class="container">
42
+      <div style="word-break:break-word">
43
+        <!-- <Fragment set:html={contentHtml} /> -->
44
+      </div>
45
+    </div>
46
+  </div>
47
+  <Footer lang={lang} />
48
+</Layout>

+ 43
- 0
src/pages/[lang]/index.astro 查看文件

@@ -0,0 +1,43 @@
1
+---
2
+import Layout from '@/layouts/Layout.astro'
3
+import Footer from '@/components/Footer.astro'
4
+import Navbar from '@/components/Navbar.astro'
5
+import FirstScreen from '@/components/FirstScreen.astro'
6
+import LeftOneMiddleRightFour from '@/components/LeftOneMiddleRightFour.astro'
7
+import Text from '@/components/children/Text.astro'
8
+import Img from '@/components/children/Img.astro'
9
+import Carousel from '@/components/children/Carousel.astro'
10
+import BigImg from '@/components/BigImg.astro'
11
+// import Dynamic from '@/components/Dynamic.astro'
12
+import { getContentList } from '@/services/apis'
13
+
14
+function getName(item = {}) {
15
+  return (
16
+    item[`categaryName${lang.charAt(0).toUpperCase() + lang.slice(1)}`] ||
17
+    item.categaryNameEn ||
18
+    item.categaryNameZh
19
+  )
20
+}
21
+
22
+const categaryId = 'index'
23
+const { lang = 'zh' } = Astro.params
24
+const categary = Astro.locals._menus?.find(
25
+  (item) => item.categaryId == categaryId
26
+)
27
+const title = getName(categary)
28
+
29
+// const contentList = await getContentList(categaryId);
30
+---
31
+
32
+<Layout title={title}>
33
+  <!-- 导航栏 -->
34
+  <Navbar lang={lang} />
35
+  <FirstScreen />
36
+  <BigImg />
37
+  <!-- <Text />
38
+  <Img />
39
+  <Carousel /> -->
40
+  <!-- <Dynamic contentList={contentList} lang={lang} /> -->
41
+
42
+  <!-- <Footer lang={lang} /> -->
43
+</Layout>

+ 23
- 0
src/pages/index.astro 查看文件

@@ -0,0 +1,23 @@
1
+---
2
+import Layout from '@/layouts/Layout.astro'
3
+---
4
+
5
+<Layout title="首页">
6
+  <div style="width: 100px; height: 100px; margin: auto; padding-top: 100px;">
7
+    <div class="spinner-border text-light" role="status">
8
+      <span class="visually-hidden">Loading...</span>
9
+    </div>
10
+  </div>
11
+</Layout>
12
+
13
+<script>
14
+  let lang = window.localStorage.getItem('lang')
15
+  if (!lang) {
16
+    lang = window.navigator.language.toLocaleLowerCase().includes('zh')
17
+      ? 'zh'
18
+      : 'en'
19
+    window.localStorage.setItem('lang', lang);
20
+  }
21
+
22
+  window.location.replace(`${window.location.origin}/${lang}/`)
23
+</script>

+ 32
- 0
src/services/apis.js 查看文件

@@ -0,0 +1,32 @@
1
+import { request } from "@/utils/request";
2
+
3
+/*
4
+ * 获取分类列表
5
+ */
6
+export function getCategary () {
7
+  return request('/taCategary', { params: { isMenu: 1, pageSize: 999 } }).then(res => (res.records || []));
8
+}
9
+
10
+/**
11
+ * 获取分类下的内容列表
12
+ * @param {String} categaryId 分类id
13
+ */
14
+export function getContentList (categaryId) {
15
+  return request('/taCategaryContent', { params: { categaryId, pageSize: 999 } }).then(res => (res.records || []));
16
+}
17
+
18
+/**
19
+ * 获取轮播图下的内容列表
20
+ * @param {String} carouselId 轮播图id
21
+ */
22
+export function getCarouselItemList (carouselId) {
23
+  return request('/taCarouselItem', { params: { carouselId, pageSize: 999 } }).then(res => (res.records || []));
24
+}
25
+
26
+/*
27
+ * 获取文章详情
28
+ * @param {String} postId 文章id
29
+ */
30
+export function getPostById (postId) {
31
+  return request(`/taPost/${postId}`);
32
+}

+ 9
- 0
src/services/taConcatUs.js 查看文件

@@ -0,0 +1,9 @@
1
+// import { request } from "@/utils/request";
2
+
3
+/**
4
+ * 联系我们新增数据
5
+ * @param data
6
+ */
7
+export function postConcatUs (data) {
8
+  return request('/taConcatUs', { data, method: 'post' });
9
+}

+ 35
- 0
src/utils/array.js 查看文件

@@ -0,0 +1,35 @@
1
+/**
2
+ * 数组 转 Tree
3
+ * @param {*} arr
4
+ * @param {*} parent
5
+ * @param {*} key
6
+ * @returns
7
+ */
8
+export function arr2Tree(arr = [], parent = "parentId", key = "categaryId") {
9
+  // 转换为字典
10
+  const dict = arr.reduce((acc, item) => {
11
+    return {
12
+      ...acc,
13
+      [item[key]]: {
14
+        ...item,
15
+        children: [],
16
+      },
17
+    };
18
+  }, {});
19
+
20
+  // 挂载父子节点
21
+  const tree = [];
22
+  for (let item of arr) {
23
+    const it = dict[item[key]];
24
+    const parentNodeId = it[parent];
25
+    const parentNode = dict[parentNodeId];
26
+
27
+    if (!parentNode) {
28
+      tree.push(it);
29
+    } else {
30
+      dict[parentNodeId].children.push(it);
31
+    }
32
+  }
33
+  
34
+  return [tree, dict];
35
+}

+ 5
- 0
src/utils/img.js 查看文件

@@ -0,0 +1,5 @@
1
+/*写一个图片地址加前缀的函数*/
2
+export function imgAddPrefix (imgUrl) {
3
+  var prefix = import.meta.env.IMG_SERVER;
4
+  return prefix + imgUrl;
5
+}

+ 28
- 0
src/utils/request.js 查看文件

@@ -0,0 +1,28 @@
1
+import axios from "axios";
2
+
3
+// 服务端请求
4
+
5
+const server = axios.create({
6
+  baseURL: import.meta.env.BASE_SERVER,
7
+  timeout: 10000,
8
+});
9
+
10
+server.interceptors.request.use(config => {
11
+  // 暂无需要处理的内容
12
+  return config;
13
+});
14
+
15
+server.interceptors.response.use(response => {
16
+  const { data, status } = response;
17
+  if (data?.code === 1000 || data?.code === 200) {
18
+    return data.data;
19
+  }
20
+
21
+  if (data?.message || data?.msg) {
22
+    throw new Error(data?.message || data?.msg);
23
+  }
24
+
25
+  throw new Error(`网络异常 - ${status}`)
26
+});
27
+
28
+export const request = server;