Compare commits

...

16 Commits

Author SHA1 Message Date
李志鹏
4254f291f4 登录注册 2026-05-18 16:46:55 +08:00
李志鹏
35df75d4ea Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-18 15:22:09 +08:00
李志鹏
d327797236 登录注册 2026-05-18 15:22:08 +08:00
X1627315083@163.com
6523c30d9f about页面 2026-05-18 13:57:05 +08:00
X1627315083@163.com
4af58134fd about页面 2026-05-18 11:33:26 +08:00
李志鹏
e36b17642f 头尾多语言 2026-05-18 11:13:48 +08:00
X1627315083@163.com
57835e6416 Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-18 10:42:33 +08:00
X1627315083@163.com
892c568efc fix 2026-05-18 10:42:24 +08:00
李志鹏
a92ceff8e4 Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-18 10:42:22 +08:00
李志鹏
2cf20d1b81 1 2026-05-18 10:41:59 +08:00
X1627315083@163.com
27a280ab46 添加全局视频 2026-05-18 10:41:18 +08:00
李志鹏
1c84d3949f Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-18 10:39:53 +08:00
李志鹏
f282adfd87 多语言 2026-05-18 10:39:52 +08:00
X1627315083@163.com
09af83050a fix 2026-05-18 09:28:36 +08:00
李志鹏
4587a59a89 Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-15 17:32:55 +08:00
李志鹏
d237dab098 aaa 2026-05-15 17:31:43 +08:00
37 changed files with 2097 additions and 179 deletions

View File

@@ -5,7 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>test-ssg</title>
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4403230_bui5mtufs1c.css" />
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4403230_70xz405a1wg.css" />
</head>
<body>
<div id="app"></div>

View File

@@ -11,11 +11,14 @@
"dependencies": {
"@kagol/vue-carousel": "^0.1.2",
"@unhead/vue": "^2.1.15",
"unhead": "2.1.15",
"gsap": "^3.15.0",
"less": "^4.6.4",
"pinia": "^3.0.4",
"pinia-persistedstate-plugin": "^0.1.0",
"unhead": "2.1.15",
"vite-ssg": "^28.3.0",
"vue": "^3.5.34",
"vue-i18n": "^11.4.4",
"vue-router": "^4.6.4"
},
"devDependencies": {

215
pnpm-lock.yaml generated
View File

@@ -20,6 +20,12 @@ importers:
less:
specifier: ^4.6.4
version: 4.6.4
pinia:
specifier: ^3.0.4
version: 3.0.4(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3))
pinia-persistedstate-plugin:
specifier: ^0.1.0
version: 0.1.0(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3))
unhead:
specifier: 2.1.15
version: 2.1.15
@@ -29,6 +35,9 @@ importers:
vue:
specifier: ^3.5.34
version: 3.5.34(typescript@6.0.3)
vue-i18n:
specifier: ^11.4.4
version: 11.4.4(vue@3.5.34(typescript@6.0.3))
vue-router:
specifier: ^4.6.4
version: 4.6.4(vue@3.5.34(typescript@6.0.3))
@@ -149,6 +158,22 @@ packages:
'@noble/hashes':
optional: true
'@intlify/core-base@11.4.4':
resolution: {integrity: sha512-w/vItlylrAmhebkIbVl5YY8XMCtj8Mb2g70ttxktMYuf5AuRahgEHL2iLgLIsZBIbTSgs4hkUo7ucCL0uTJvOg==}
engines: {node: '>= 22'}
'@intlify/devtools-types@11.4.4':
resolution: {integrity: sha512-PcBLmGmDQsTSVV911P8upzpcLJO1CNVYi/IH6bGnLR2nA+0L963+kXN1ZrisTEnbtw2ewN6HMMSldqzjronA0Q==}
engines: {node: '>= 22'}
'@intlify/message-compiler@11.4.4':
resolution: {integrity: sha512-vn0OAV9pYkJlPPmgnsSm5eAG3mL0+9C/oaded2JY9jmxBbhmUXT3TcAUY8WRgLY9Hte7lkUJKpXrVlYjMXBD2w==}
engines: {node: '>= 22'}
'@intlify/shared@11.4.4':
resolution: {integrity: sha512-QRUCHqda1U6aR14FR0vvXD4+4gj6+fm0AhAozvSuRCw0fCvrmCugWpgiR4xH2NI6s8am6N9p5OhirplsX8ZS3g==}
engines: {node: '>= 22'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -212,36 +237,42 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.0':
resolution: {integrity: sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.0.0':
resolution: {integrity: sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.0':
resolution: {integrity: sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.0':
resolution: {integrity: sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.0':
resolution: {integrity: sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.0':
resolution: {integrity: sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==}
@@ -281,10 +312,14 @@ packages:
resolution: {integrity: sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/js-cookie@3.0.6':
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
'@types/node@24.12.4':
resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==}
@@ -329,6 +364,15 @@ packages:
'@vue/devtools-api@6.6.4':
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
'@vue/devtools-api@7.7.9':
resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==}
'@vue/devtools-kit@7.7.9':
resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==}
'@vue/devtools-shared@7.7.9':
resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==}
'@vue/language-core@3.2.8':
resolution: {integrity: sha512-9OiSPQFiAAWNVnXb0d2dcTmcKnFQamhuNES6ayyISrb/mwPWVgoGdAqSfCWqKhQpa3D5gDTcYD+w7ObiheZ81g==}
@@ -379,6 +423,9 @@ packages:
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
birpc@2.9.0:
resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==}
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -404,6 +451,10 @@ packages:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'}
copy-anything@4.0.5:
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
engines: {node: '>=18'}
css-tree@3.2.1:
resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
@@ -477,6 +528,9 @@ packages:
gsap@3.15.0:
resolution: {integrity: sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==}
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
hookable@6.1.1:
resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==}
@@ -516,6 +570,10 @@ packages:
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
engines: {node: '>=12.13'}
is-what@5.5.0:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'}
jsdom@28.1.0:
resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
@@ -565,24 +623,28 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.32.0:
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
@@ -622,6 +684,9 @@ packages:
engines: {node: '>=4'}
hasBin: true
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -657,6 +722,9 @@ packages:
path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -668,6 +736,27 @@ packages:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
engines: {node: '>=6'}
pinia-persistedstate-plugin@0.1.0:
resolution: {integrity: sha512-ToKR/EJzhhXElQ5YL8PVVY4CqLJjywxszAJjOCgprjmIVkTrPBsEOY4b/ATOzHQc1TtuaJs/3MJuoCpA3pv8Ew==}
pinia@2.3.1:
resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
peerDependencies:
typescript: '>=4.4.4'
vue: ^2.7.0 || ^3.5.11
peerDependenciesMeta:
typescript:
optional: true
pinia@3.0.4:
resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==}
peerDependencies:
typescript: '>=4.5.0'
vue: ^3.5.11
peerDependenciesMeta:
typescript:
optional: true
postcss@8.5.14:
resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==}
engines: {node: ^10 || ^12 || >=14}
@@ -687,6 +776,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
rolldown@1.0.0:
resolution: {integrity: sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -718,6 +810,14 @@ packages:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
speakingurl@14.0.1:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'}
superjson@2.2.6:
resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==}
engines: {node: '>=16'}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
@@ -830,6 +930,23 @@ packages:
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-i18n@11.4.4:
resolution: {integrity: sha512-gIbXVSFQV4jcSJxfwdZ5zSZmZ+12CnX0K3vBkRSd6Zn+HSzCp+QwUgPwpD/uN0oKNKI9RzlUXPKVedEuMgNG0A==}
engines: {node: '>= 22'}
peerDependencies:
vue: ^3.0.0
vue-router@4.6.4:
resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
peerDependencies:
@@ -958,6 +1075,24 @@ snapshots:
'@exodus/bytes@1.15.0': {}
'@intlify/core-base@11.4.4':
dependencies:
'@intlify/devtools-types': 11.4.4
'@intlify/message-compiler': 11.4.4
'@intlify/shared': 11.4.4
'@intlify/devtools-types@11.4.4':
dependencies:
'@intlify/core-base': 11.4.4
'@intlify/shared': 11.4.4
'@intlify/message-compiler@11.4.4':
dependencies:
'@intlify/shared': 11.4.4
source-map-js: 1.2.1
'@intlify/shared@11.4.4': {}
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -1060,6 +1195,8 @@ snapshots:
tslib: 2.8.1
optional: true
'@types/js-cookie@3.0.6': {}
'@types/node@24.12.4':
dependencies:
undici-types: 7.16.0
@@ -1124,6 +1261,24 @@ snapshots:
'@vue/devtools-api@6.6.4': {}
'@vue/devtools-api@7.7.9':
dependencies:
'@vue/devtools-kit': 7.7.9
'@vue/devtools-kit@7.7.9':
dependencies:
'@vue/devtools-shared': 7.7.9
birpc: 2.9.0
hookable: 5.5.3
mitt: 3.0.1
perfect-debounce: 1.0.0
speakingurl: 14.0.1
superjson: 2.2.6
'@vue/devtools-shared@7.7.9':
dependencies:
rfdc: 1.4.1
'@vue/language-core@3.2.8':
dependencies:
'@volar/language-core': 2.4.28
@@ -1175,6 +1330,8 @@ snapshots:
dependencies:
require-from-string: 2.0.2
birpc@2.9.0: {}
buffer-from@1.1.2: {}
cac@6.7.14: {}
@@ -1196,6 +1353,10 @@ snapshots:
dependencies:
is-what: 4.1.16
copy-anything@4.0.5:
dependencies:
is-what: 5.5.0
css-tree@3.2.1:
dependencies:
mdn-data: 2.27.1
@@ -1255,6 +1416,8 @@ snapshots:
gsap@3.15.0: {}
hookable@5.5.3: {}
hookable@6.1.1: {}
html-encoding-sniffer@6.0.0:
@@ -1303,6 +1466,8 @@ snapshots:
is-what@4.1.16: {}
is-what@5.5.0: {}
jsdom@28.1.0:
dependencies:
'@acemir/cssom': 0.9.31
@@ -1413,6 +1578,8 @@ snapshots:
mime@1.6.0:
optional: true
mitt@3.0.1: {}
ms@2.1.3: {}
muggle-string@0.4.1: {}
@@ -1448,6 +1615,8 @@ snapshots:
path-browserify@1.0.1: {}
perfect-debounce@1.0.0: {}
picocolors@1.1.1: {}
picomatch@4.0.4: {}
@@ -1455,6 +1624,32 @@ snapshots:
pify@4.0.1:
optional: true
pinia-persistedstate-plugin@0.1.0(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@types/js-cookie': 3.0.6
pinia: 2.3.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3))
transitivePeerDependencies:
- '@vue/composition-api'
- typescript
- vue
pinia@2.3.1(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@vue/devtools-api': 6.6.4
vue: 3.5.34(typescript@6.0.3)
vue-demi: 0.14.10(vue@3.5.34(typescript@6.0.3))
optionalDependencies:
typescript: 6.0.3
transitivePeerDependencies:
- '@vue/composition-api'
pinia@3.0.4(typescript@6.0.3)(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@vue/devtools-api': 7.7.9
vue: 3.5.34(typescript@6.0.3)
optionalDependencies:
typescript: 6.0.3
postcss@8.5.14:
dependencies:
nanoid: 3.3.12
@@ -1470,6 +1665,8 @@ snapshots:
require-from-string@2.0.2: {}
rfdc@1.4.1: {}
rolldown@1.0.0:
dependencies:
'@oxc-project/types': 0.129.0
@@ -1513,6 +1710,12 @@ snapshots:
source-map@0.6.1: {}
speakingurl@14.0.1: {}
superjson@2.2.6:
dependencies:
copy-anything: 4.0.5
symbol-tree@3.2.4: {}
terser@5.47.1:
@@ -1589,6 +1792,18 @@ snapshots:
vscode-uri@3.1.0: {}
vue-demi@0.14.10(vue@3.5.34(typescript@6.0.3)):
dependencies:
vue: 3.5.34(typescript@6.0.3)
vue-i18n@11.4.4(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@intlify/core-base': 11.4.4
'@intlify/devtools-types': 11.4.4
'@intlify/shared': 11.4.4
'@vue/devtools-api': 6.6.4
vue: 3.5.34(typescript@6.0.3)
vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@vue/devtools-api': 6.6.4

View File

@@ -3,13 +3,22 @@
<RouterView />
<MainFooter />
<BackTop />
<VideoModel />
<div v-show="loading" class="main-loading">
<span class="iconfont icon-loading"></span>
</div>
</template>
<script setup lang="ts">
import { RouterView } from "vue-router";
import MainHeader from "./components/main-header.vue";
import MainFooter from "./components/main-footer.vue";
import BackTop from "./components/back-top.vue";
import { ref, computed } from 'vue'
import { RouterView } from 'vue-router'
import MainHeader from './components/main-header.vue'
import MainFooter from './components/main-footer.vue'
import BackTop from './components/back-top.vue'
import VideoModel from './components/video-model.vue'
import { useGlobalStore } from './stores/global'
const globalStore = useGlobalStore()
const loading = computed(() => globalStore.state.loading)
</script>
<style scoped lang="less">
// .main {
@@ -22,4 +31,26 @@
// height: auto;
// }
// }
.main-loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999999999;
> .iconfont {
font-size: 80px;
color: #fff;
animation: loading 2s linear infinite;
}
}
</style>
<style lang="less">
html:root {
--main-header-height: 85px;
}
</style>

View File

@@ -24,7 +24,6 @@ h6,
font-family: Poppins, sans-serif;
font-weight: 600;
letter-spacing: 2px;
color: #222222;
text-transform: capitalize;
}
@keyframes loading {
@@ -122,35 +121,56 @@ h6,
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
}
button[custom],
button[custom="white"] {
min-width: 19.4rem;
height: 5rem;
padding: 0 1rem;
border-radius: 0;
font-family: KaiseiOpti-Bold;
font-size: var(--button-font-size, 2rem);
color: var(--button-color, #232323);
background: var(--button-bgcolor, #fff);
border: var(--button-border, none);
button[custom="red"] {
width: 100%;
height: 38px;
border-radius: 4px;
border: none;
background-color: #9a2125;
color: #fff;
transition: all 0.3s ease-in-out;
box-shadow: 0 2px 5px rgba(7, 129, 105, 0.3);
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
button[custom]:hover,
button[custom="red"]:hover {
background-color: #99494c;
}
button[custom] > .iconfont,
button[custom="red"] > .iconfont {
margin-right: 4px;
font-size: 16px;
}
button[custom] > .label,
button[custom="red"] > .label {
font-size: 14px;
}
.hover-bottom-animation {
position: relative;
cursor: pointer;
}
button[custom]:active,
button[custom="white"]:active {
background: var(--button-click-bgcolor, #e4e4e4);
color: var(--button-click-color, #232323);
.hover-bottom-animation::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
button[custom="black"] {
--button-bgcolor: #232323;
--button-color: #fff;
--button-click-bgcolor: #333;
--button-click-color: #fff;
--button-font-size: 1.6rem;
.hover-bottom-animation:hover::before {
width: 100%;
left: 0;
right: auto;
}
button[custom="black-box"] {
--button-bgcolor: transparent;
--button-color: #232323;
--button-border: 0.2rem solid #979797;
--button-click-bgcolor: #979797;
--button-click-color: #fff;
--button-font-size: 1.6rem;
.hover-bottom-animation.active:before,
.hover-bottom-animation.router-link-exact-active:before {
width: 100%;
}

View File

@@ -15,12 +15,18 @@ p {
* {
box-sizing: border-box;
}
h1, h2, h3, h4, h5, h6, .products-title{
h1,
h2,
h3,
h4,
h5,
h6,
.products-title {
font-family: Poppins, sans-serif;
font-weight: 600;
letter-spacing: 2px;
color: #222222;
text-transform: capitalize;
font-weight: 600;
letter-spacing: 2px;
text-transform: capitalize;
}
@keyframes loading {
@@ -142,37 +148,63 @@ h1, h2, h3, h4, h5, h6, .products-title{
// 自定义button按钮
button[custom],
button[custom="white"] {
min-width: 19.4rem;
height: 5rem;
padding: 0 1rem;
border-radius: 0;
font-family: KaiseiOpti-Bold;
font-size: var(--button-font-size, 2rem);
color: var(--button-color, #232323);
background: var(--button-bgcolor, #fff);
border: var(--button-border, none);
button[custom="red"] {
width: 100%;
height: 38px;
border-radius: 4px;
border: none;
background-color: #9a2125;
color: #fff;
transition: all 0.3s ease-in-out;
box-shadow: 0 2px 5px rgba(7, 129, 105, 0.3);
cursor: pointer;
font-size: 12px;
&:hover {
background-color: #99494c;
}
display: flex;
align-items: center;
justify-content: center;
>.iconfont {
margin-right: 4px;
font-size: 16px;
}
>.label {
font-size: 14px;
}
}
.hover-bottom-animation {
position: relative;
cursor: pointer;
&:active {
background: var(--button-click-bgcolor, #e4e4e4);
color: var(--button-click-color, #232323);
&::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.active:before,
&.router-link-exact-active:before {
width: 100%;
}
}
button[custom="black"] {
--button-bgcolor: #232323;
--button-color: #fff;
--button-click-bgcolor: #333;
--button-click-color: #fff;
--button-font-size: 1.6rem;
}
button[custom="black-box"] {
--button-bgcolor: transparent;
--button-color: #232323;
--button-border: 0.2rem solid #979797;
--button-click-bgcolor: #979797;
--button-click-color: #fff;
--button-font-size: 1.6rem;
}

View File

@@ -7,7 +7,7 @@
transition: 'stroke-dashoffset 10ms linear',
strokeDasharray: `${progress}, ${max}`,
stroke: '#222',
strokeWidth: 4,
strokeWidth: 4
}"
fill="none"
></path>
@@ -21,11 +21,11 @@
const max = ref(98 * Math.PI);
const progress = ref(0);
const handleScroll = (e: number) => {
progress.value = (e / 100) * max.value;
};
progress.value = (e / 100) * max.value
}
const handleClick = () => {
document.documentElement.scrollTo({ top: 0, behavior: "smooth" });
};
document.documentElement.scrollTo({ top: 0, behavior: 'smooth' })
}
</script>
<style scoped lang="less">
.back-top {
@@ -52,6 +52,20 @@
transition: stroke-dashoffset 10ms linear;
}
}
&:hover > .iconfont {
animation: animArrow 1s infinite;
}
@keyframes animArrow {
0% {
transform: rotate(0deg);
}
50% {
transform: translateY(-3px);
}
100% {
transform: rotate(0deg);
}
}
animation: back-top-hidden 0.2s linear both;
&.active {

View File

@@ -0,0 +1,100 @@
<template>
<div class="down-menu">
<div class="title hover-bottom-animation" to="#">
{{ title }}
<span class="iconfont icon-arrow-down-bold"></span>
</div>
<div class="child">
<slot></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
title: {
type: String,
default: ''
}
})
</script>
<style scoped lang="less">
.down-menu {
position: relative;
> .title {
margin: 0 14px;
color: #fff;
font-size: 14px;
text-decoration: none;
line-height: 37px;
display: inline-block;
position: relative;
cursor: pointer;
&::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.router-link-exact-active:not(.parent):before {
width: 100%;
}
> .iconfont {
opacity: 0.5;
font-size: 10px;
margin-left: 5px;
}
}
> .child {
position: absolute;
bottom: 0;
visibility: hidden;
width: 250px;
height: auto;
padding: 10px 0;
box-sizing: border-box;
border: 1px solid #e1e1e1;
background-color: #fff;
display: flex;
flex-direction: column;
transform: translateY(calc(100% + 5px));
> * {
display: inline-block;
padding: 10px 15px;
color: #000;
font-size: 15px;
text-decoration: none;
text-align: left;
&:hover {
opacity: 0.5;
}
}
}
&:hover > .child {
animation: child-show 0.2s linear both;
}
@keyframes child-show {
0% {
visibility: hidden;
// opacity: 0;
}
100% {
// opacity: 1;
transform: translateY(100%);
visibility: visible;
}
}
}
</style>

View File

@@ -1,13 +1,83 @@
<script setup lang="ts">
defineExpose({})
</script>
<template>
<header class="header">
</header>
<footer class="main-footer">
<div class="left">
<span>{{
$t('MainFooter.Copyright', {
year: new Date().getFullYear(),
name: 'Code-Create'
})
}}</span>
</div>
<div class="right">
<div v-for="item in nav" :key="item.path">
<router-link class="link" :to="item.path">{{ $t(item.name) }}</router-link>
</div>
</div>
</footer>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from 'vue'
const nav = ref([
{
name: 'MainFooter.PrivacyPolicy',
path: '/privacy-policy'
},
{
name: 'MainFooter.TermsOfUse',
path: '/terms-of-use'
},
{
name: 'MainFooter.Disclaimer',
path: '/disclaimer'
},
{
name: 'MainFooter.SiteMap',
path: '/site-map'
}
])
</script>
<style lang="less" scoped>
.header{
position: relative;
.main-footer {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 15px 0;
min-height: 140px;
display: flex;
justify-content: space-between;
font-family: Poppins, sans-serif;
> .left {
font-size: 13px;
font-weight: normal;
line-height: 24px;
color: #000000b3;
}
> .right {
display: flex;
align-items: flex-start;
> div {
display: flex;
align-items: center;
justify-content: center;
padding-left: 20px;
border-left: 1px solid #0a0a0a;
margin-left: 20px;
&:first-child {
border-left: none;
padding-left: 0;
margin-left: 0;
}
> .link {
font-weight: 400;
font-size: 12px;
transition: all 0.2s ease-out;
box-sizing: border-box;
box-shadow: none;
text-decoration: none;
display: inline-block;
color: #0a0a0a;
}
}
}
}
</style>

View File

@@ -1,92 +1,126 @@
<template>
<header class="main-header" v-scroll-progress>
<img class="logo" src="../assets/logo-full.png" alt="code-create" />
<a href="/" class="logo"><img src="../assets/logo-full.png" alt="code-create" /></a>
<div class="center-nav">
<div class="nav-item" v-for="item in navList" :key="item.path">
<router-link class="link" :to="item.path" v-if="item.path">
{{ item.name }}
</router-link>
<span v-else class="link">{{ item.name }}</span>
<div
class="child"
v-if="item.children && item.children.length > 0"
>
<router-link
class="child-link"
:to="child.path"
v-for="child in item.children"
:key="child.path"
>
{{ child.name }}
<div class="nav-item" v-for="item in navList" :key="item.name">
<down-menu :title="$t(item.name)" v-if="item.children">
<router-link :to="child.path" v-for="child in item.children" :key="child.name">
{{ $t(child.name) }}
</router-link>
</div>
</down-menu>
<router-link class="link hover-bottom-animation" :to="item.path" v-else>{{
$t(item.name)
}}</router-link>
</div>
</div>
<div class="right">
<span>English</span>
<span>My Account</span>
<down-menu :title="langList.find((v) => v.value === locale)?.label || 'English'">
<router-link
class="link"
:to="`/${item.value}${path}`"
v-for="item in langList"
:key="item.value"
v-show="item.value !== locale"
>
{{ item.label }}
</router-link>
</down-menu>
<router-link class="link" to="/my-account">
<span class="iconfont icon-tubiao-"></span>
<span v-if="token">{{ $t('MainHeader.MyAccount') }}</span>
<span v-else>{{ $t('MainHeader.LoginOrSignin') }}</span>
</router-link>
</div>
</header>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
console.log(route);
import { ref, watch, computed } from 'vue'
import DownMenu from './down-menu.vue'
import { setLang, LangType } from '../lang'
import { useI18n } from 'vue-i18n'
const { locale } = useI18n()
import { useRoute } from 'vue-router'
import { useUserInfoStore } from '@/stores/userInfo'
const userInfoStore = useUserInfoStore()
const token = computed(() => userInfoStore.state.token)
const route = useRoute()
const lang = computed(() => route.params.lang)
const path = computed(() => route.path.replace(new RegExp(`^/${lang.value}/`), '/'))
if (lang.value) setLang(lang.value)
watch(lang, (newVal) => {
if (lang.value) setLang(newVal)
})
const langList = ref([
{
label: 'English',
value: LangType.en
},
{
label: '简体中文',
value: LangType.zhCn
},
{
label: '繁體中文',
value: LangType.zhTw
}
])
const navList = ref([
{
name: "Home",
path: "/",
name: 'MainHeader.Home',
path: '/'
},
{
name: "About Us",
path: "/about-us",
name: 'MainHeader.AboutUs',
path: '/about-us'
},
{
name: "Our Solutions",
name: 'MainHeader.OurSolutions',
path: '',
children: [
{
name: "AiDA 3.1",
path: "/aida",
name: 'MainHeader.AiDA31',
path: '/aida'
},
{
name: "Mixi",
path: "/mixi",
},
],
name: 'MainHeader.Mixi',
path: '/mixi'
}
]
},
{
name: "Communities",
name: 'MainHeader.Communities',
path: '',
children: [
{
name: "Events",
path: "/events",
name: 'MainHeader.Events',
path: '/events'
},
{
name: "User Stories",
path: "/user-stories",
name: 'MainHeader.UserStories',
path: '/user-stories'
},
{
name: "Help Centre",
path: "/help-centre",
},
],
name: 'MainHeader.HelpCentre',
path: '/help-centre'
}
]
},
{
name: "Media",
path: "/media",
name: 'MainHeader.Media',
path: '/media'
},
{
name: "Contact Us",
path: "/contact-us",
},
]);
name: 'MainHeader.ContactUs',
path: '/contact-us'
}
])
</script>
<style lang="less" scoped>
.main-header {
position: fixed;
width: 100%;
height: 85px;
height: var(--main-header-height, 85px);
padding: 15px 30px;
box-sizing: border-box;
top: 0;
@@ -102,6 +136,10 @@
> .logo {
height: 100%;
width: auto;
img {
width: auto;
height: 100%;
}
}
> .center-nav {
display: flex;
@@ -109,35 +147,14 @@
justify-content: center;
> .nav-item {
position: relative;
&:deep(> .down-menu > .title),
> .link {
margin: 0 14px;
color: #fff;
font-size: 15px;
font-size: 14px;
text-decoration: none;
line-height: 37px;
display: inline-block;
position: relative;
cursor: pointer;
&::before {
content: "";
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.router-link-exact-active:before {
width: 100%;
}
}
> .child {
position: absolute;
@@ -184,14 +201,23 @@
display: flex;
align-items: center;
justify-content: center;
> span {
> .link {
margin: 0 14px;
color: #fff;
font-size: 15px;
font-size: 14px;
text-decoration: none;
line-height: 37px;
display: inline-block;
position: relative;
display: flex;
align-items: center;
justify-content: center;
&:hover {
opacity: 0.8;
}
> .iconfont {
margin-right: 5px;
font-size: 22px;
}
}
}
}

View File

@@ -0,0 +1,74 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import MyEvent from "@/directives/myEvents";
//const props = defineProps({
//})
//const emit = defineEmits([
//])
const isVideoShow = ref(false)
const url = ref('')
const poster = ref('')
const playVideo = (data)=>{
url.value = data.url || ''
poster.value = data.poster || ''
isVideoShow.value = true
}
const closeVideoModel = ()=>{
url.value = ''
poster.value = ''
isVideoShow.value = false
}
onMounted(()=>{
MyEvent.add("playVideo",playVideo);
})
onUnmounted(()=>{
})
defineExpose({})
</script>
<template>
<div class="vide-model" v-if="isVideoShow">
<div class="mask"></div>
<video :src="url" autoplay controls preload="metadata" controlslist="nodownload" :poster="poster"></video>
<div class="close-btn">
<span class="iconfont icon-close" @click="closeVideoModel"></span>
</div>
</div>
</template>
<style lang="less" scoped>
.vide-model{
z-index: 99999;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
> .mask{
width: 100%;
height: 100%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background-color: rgba(0,0,0,.8);
}
> video{
position: absolute;
top: 50%;
left: 50%;
max-height: 80vh;
max-width: 80vw;
transform: translate(-50%,-50%);
}
> .close-btn{
position: absolute;
top: 20px;
right: 20px;
font-size: 30px;
color: #fff;
cursor: pointer;
span{
font-size: 30px;
}
}
}
</style>

View File

@@ -40,7 +40,6 @@ const T = {
rotateZ: 'rotate-z',
opacity_s: 'opacity-s',
opacity: 'opacity',
once: 'once',
}
const types = Object.values(T)
const typesStr = types.map(v => `[${v}]`).join(',')

View File

@@ -0,0 +1,39 @@
class MyEvent {
private events: Map<string, Array<(data: any) => void>>;
constructor() {
// 使用 Object 或 Map 存储,实现 O(1) 级别的查找
this.events = new Map()
}
add(name: string, call: (data: any) => void) {
if (!this.events.has(name)) {
this.events.set(name, [])
}
this.events.get(name)!.push(call)
}
remove(name: string, call?: (data: any) => void) {
if (!this.events.has(name)) return
if (!call) {
this.events.delete(name)
} else {
const callbacks = this.events.get(name)
const index = callbacks.indexOf(call)
if (index !== -1) {
callbacks.splice(index, 1)
}
// 如果该事件没有监听者了,彻底清理 key
if (callbacks.length === 0) {
this.events.delete(name)
}
}
}
emit(name: string, data?: any) {
const callbacks = this.events.get(name)
if (callbacks) {
// 使用 slice() 镜像一份副本,防止在执行回调过程中有 remove 操作导致索引错乱
callbacks.slice().forEach((cb) => cb(data))
}
}
}
export default new MyEvent()

View File

@@ -1,13 +1,14 @@
import { gsap, } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
export default {
name: 'tween-animation',
mounted(el: HTMLElement) {
name: 'tween-Y',
mounted(el: HTMLElement, binding: any) {
const params = binding.value
// if(!binding.value.isGsap)return
let dom = document.querySelector('body')
gsap.registerPlugin(ScrollTrigger);
let tl1 = gsap.timeline();
tl1.from(el,1, {y:'30px',opacity:0},)
tl1.from(el,1, {y:params || '30px',opacity:0},)
ScrollTrigger.create({
trigger: el, // 触发器元素
start: "top 90%", // 滚动触发器的起始滚动位置
@@ -15,7 +16,8 @@ export default {
markers: false, // 开启标注功能
animation:tl1,
scroller:dom,//设置指定元素为滚动依据
scrub:2,
scrub:false,
// toggleActions: "play reset play reset",
// onUpdate:(v)=>{
// if(v.progress < 0.1){
// v.trigger?.classList.remove('active')

24
src/lang/en.ts Normal file
View File

@@ -0,0 +1,24 @@
export default {
MainHeader: {
Home: 'Home',
AboutUs: 'About Us',
OurSolutions: 'Our Solutions',
AiDA31: 'AiDA 3.1',
Mixi: 'Mixi',
Communities: 'Communities',
Events: 'Events',
UserStories: 'User Stories',
HelpCentre: 'Help Centre',
Media: 'Media',
ContactUs: 'Contact Us',
MyAccount: 'My Account',
LoginOrSignin: 'Log in / Sign in',
},
MainFooter: {
Copyright: '©{year} {name} Limited',
PrivacyPolicy: 'Privacy Policy',
TermsOfUse: 'Terms of Use',
Disclaimer: 'Disclaimer',
SiteMap: 'Site Map',
}
}

40
src/lang/index.ts Normal file
View File

@@ -0,0 +1,40 @@
import { createI18n } from 'vue-i18n'
import enLocale from './en.ts'
import zhCnLocale from './zh-cn.ts'
import zhTwLocale from './zh-tw.ts'
export const LangType = {
en: "en", // 英文
zhTw: "zh-tw", // 繁体中文
zhCn: "zh-cn", // 简体中文
}
export const LANGS = Object.values(LangType)
// 语言配置整合
const messages = {
[LangType.en]: enLocale,
[LangType.zhCn]: zhCnLocale,
[LangType.zhTw]: zhTwLocale,
}
const localeLang = localStorage.getItem('language')
const defaultLocale = checkLocale(localeLang) ? localeLang! : LangType.en
// 创建 i18n
const i18n = createI18n({
legacy: false,
globalInjection: true, // 全局模式,可以直接使用 $t
locale: defaultLocale,
messages: messages
})
export default i18n
// 检查语言是否存在
function checkLocale(lang: any) {
return LANGS.includes(lang)
}
export const setLang = (lang: any) => {
if (lang === "") lang = LangType.en
if (!checkLocale(lang)) return false
i18n.global.locale.value = lang
localStorage.setItem('language', lang)
return true
}

24
src/lang/zh-cn.ts Normal file
View File

@@ -0,0 +1,24 @@
export default {
MainHeader: {
Home: '首页',
AboutUs: '关于我们',
OurSolutions: '我们的产品',
AiDA31: 'AiDA 3.1',
Mixi: 'Mixi',
Communities: '社区',
Events: '活动',
UserStories: '使用者故事',
HelpCentre: '支援中心',
Media: '媒体报道',
ContactUs: '联系我们',
MyAccount: '我的账户',
LoginOrSignin: '登入 / 注册',
},
MainFooter: {
Copyright: '©{year} {name} 有限公司',
PrivacyPolicy: '隐私政策',
TermsOfUse: '使用条款',
Disclaimer: '免责声明',
SiteMap: '网站地图',
}
}

24
src/lang/zh-tw.ts Normal file
View File

@@ -0,0 +1,24 @@
export default {
MainHeader: {
Home: '首頁',
AboutUs: '關於我們',
OurSolutions: '我們的產品',
AiDA31: 'AiDA 3.1',
Mixi: 'Mixi',
Communities: '社區',
Events: '活動',
UserStories: '使用者故事',
HelpCentre: '支援中心',
Media: '媒體報導',
ContactUs: '聯絡我們',
MyAccount: '我的帳號',
LoginOrSignin: '登錄 / 登冊',
},
MainFooter: {
Copyright: '©{year} {name} 有限公司',
PrivacyPolicy: '私隱政策',
TermsOfUse: '使用條款',
Disclaimer: '免責聲明',
SiteMap: '網站地圖',
}
}

View File

@@ -4,13 +4,17 @@ import { routes } from './routes'
// import './style.css'
import '@/assets/css/style.less'
import directives from './directives/index'
import i18n from './lang/index'
import store from './stores/index'
export const createApp = ViteSSG(App, {
routes,
base: import.meta.env.BASE_URL,
},
routes,
base: import.meta.env.BASE_URL,
},
({ app }) => {
// 注册全局指令
app.use(directives)
app.use(store)
app.use(i18n)
}
)

View File

@@ -1,5 +1,16 @@
<script setup lang="ts">
defineExpose({})
import { ref } from "vue";
import MyEvent from "@/directives/myEvents";
let videoUrl = 'https://code-create.com.hk/wp-content/uploads/2023/05/codec_brand_vid_16x9_ENG.mp4'
let videoPosterUrl = 'https://code-create.com.hk/wp-content/uploads/revslider/video-media/codec_brand_vid_16x9_ENG_11_layer.jpeg'
const playVideo = ()=>{
MyEvent.emit("playVideo",{
url: videoUrl,
poster: videoPosterUrl,
});
}
defineExpose({})
</script>
<template>
<section class="ecosystem">
@@ -11,6 +22,8 @@ defineExpose({})
</section>
<section class="ecosystem-video">
<div class="content">
<img src="https://code-create.com.hk/wp-content/uploads/revslider/video-media/codec_brand_vid_16x9_ENG_11_layer.jpeg" alt="">
<span class="iconfont icon-bofang" @click="playVideo"></span>
</div>
</section>
</template>
@@ -48,6 +61,37 @@ defineExpose({})
max-width: 1200px;
margin: 0 auto;
padding: 100px 0;
position: relative;
> img{
width: 100%;
height: 675px;
}
> .icon-bofang{
font-size: 100px;
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
animation: identifier 2s ease-in-out infinite;
// box-shadow: 0 0 10px #fff;
transition: .3s all;
cursor: pointer;
@keyframes identifier {
0% {
transform: translate(-50%,-50%) scale(1);
filter: drop-shadow(0px 0px 8px rgba(255, 255, 255, 1));
}
50% {
transform: translate(-50%,-50%) scale(.95);
filter: drop-shadow(0px 0px 0px rgba(255, 255, 255, 1));
}
100% {
transform: translate(-50%,-50%) scale(1);
filter: drop-shadow(0px 0px 8px rgba(255, 255, 255, 1));
}
}
}
}
}
</style>

View File

@@ -1,6 +1,9 @@
<script setup lang="ts">
import Ecosystem from './ecosystem.vue'
import Title from './title.vue'
import Mission from './mission.vue'
import OurTeam from './our-team.vue'
import StrategicPartners from './strategic-partners.vue'
defineExpose({})
</script>
<template>
@@ -10,6 +13,9 @@ defineExpose({})
</div>
<Title />
<Ecosystem />
<Mission />
<OurTeam />
<StrategicPartners />
</div>
</template>
<style lang="less" scoped>

View File

@@ -0,0 +1,148 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { gsap, TweenMax, TweenLite } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
const imgItem1 = ref(null)
const imgItem2 = ref(null)
const imgItem3 = ref(null)
const imgItem4 = ref(null)
const imgBox = ref(null)
let data = reactive({
})
onMounted(()=>{
let dom = document.querySelector('body')
gsap.registerPlugin(ScrollTrigger);
let tl1 = gsap.timeline();
tl1.from(imgItem1.value,1, {y:'200px',opacity:0,ease:'power2.out'},0)
tl1.from(imgItem2.value,1, {y:'200px',opacity:0,ease:'power2.out'},0.2)
tl1.from(imgItem3.value,1, {y:'200px',opacity:0,ease:'power2.out'},0.4)
tl1.from(imgItem4.value,1, {y:'200px',opacity:0,ease:'power2.out'},0.6)
ScrollTrigger.create({
trigger: imgBox.value, // 触发器元素
start: "top 90%", // 滚动触发器的起始滚动位置
end: '100% 80%', // 滚动触发器的结束滚动位置
markers: false, // 开启标注功能
animation:tl1,
scroller:dom,//设置指定元素为滚动依据
// toggleActions: "play reset play reset",
scrub:false,
});
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<section class="mission">
<div class="content">
<h2>Mission</h2>
<p>To be the world leading innovative leader in offering the state-of-the-art AI based solutions and systems to disrupt the fashion industry</p>
</div>
</section>
<section class="mission-focus-area">
<div class="content">
<h2>Focus Area</h2>
<div class="img-box" ref="imgBox">
<div class="img-item" ref="imgItem1">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_focus_01.png" alt="">
<h2>Elevate Operation Efficiency</h2>
</div>
<div class="img-item" ref="imgItem2">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_focus_02-1-600x888.png" alt="">
<h2>Vertical Design Platform</h2>
</div>
<div class="img-item" ref="imgItem3">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_focus_03-1-600x887.png" alt="">
<h2>Education</h2>
</div>
<div class="img-item" ref="imgItem4">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_focus_04-1-600x888.png" alt="">
<h2>Community</h2>
</div>
</div>
</div>
</section>
</template>
<style lang="less" scoped>
.mission{
width: 100%;
background-color: #eeeeee;
> .content{
margin: 0 auto;
max-width: 730px;
padding: 200px 0px 200px 0px;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
> h2{
margin-bottom: 30px;
color: #000000;
font-size: 40px;
font-weight: 600;
letter-spacing: 1px;
font-family: "Poppins", Sans-serif;
}
> p{
color: #555;
font-size: 16px;
}
}
}
.mission-focus-area{
width: 100%;
background-color: #f9f9f9;
> .content{
max-width: 1440px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
> h2{
font-family: "Poppins", Sans-serif;
font-size: 40px;
font-weight: 600;
letter-spacing: 1px;
color: #000000;
margin: 100px auto;
}
> .img-box{
padding: 10px;
margin: 0 auto;
margin-bottom: 20px;
position: relative;
display: flex;
> .img-item{
margin: 10px;
// width: 1120px;
width: 340px;
height: 503px;
position: relative;
> h2{
font-family: "Poppins", Sans-serif;
font-weight: 600;
line-height: 1.3em;
letter-spacing: 2px;
color: #FFFFFF;
width: 320px;
position: absolute;
bottom: 25%;
text-align: center;
left: 50%;
transform: translateX(-50%);
}
> img{
width: 100%;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,204 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { gsap, TweenMax, TweenLite } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
const imgItem1 = ref(null)
let data = reactive({
})
onMounted(()=>{
let dom = document.querySelector('body')
let ourListDom = document.querySelectorAll('.our-team-item')
ourListDom.forEach((item,index)=>{
gsap.registerPlugin(ScrollTrigger);
let tl1 = gsap.timeline();
let img = item.querySelector('.img')
let textTop = item.querySelector('.text p')
let textBottom = item.querySelector('.text .bottom-text')
tl1.from(img,1, {opacity:'0',ease:'power2.out'},0)
.from(textTop,1, {y:'20px',opacity:'0',ease:'power2.out'},0)
.from(textBottom,1, {y:'-20px',opacity:'0',ease:'power2.out'},0)
ScrollTrigger.create({
trigger: img, // 触发器元素
start: "top 90%", // 滚动触发器的起始滚动位置
end: '100% 80%', // 滚动触发器的结束滚动位置
markers: false, // 开启标注功能
animation:tl1,
scroller:dom,//设置指定元素为滚动依据
// toggleActions: "play reset play reset",
scrub:false,
});
})
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<section class="our-team">
<div class="content">
<h2>Our Team</h2>
</div>
</section>
<section class="our-team-item bg1">
<div class="content">
<div class="text">
<p>
Prof Wong is Cheng Yik Hung Professor in Fashion of School of Fashion and Textiles at The Hong Kong Polytechnic University and currently serving as the Chief Executive Officer and Centre Director of
<a href="https://www.aidlab.hk/">Laboratory for Artificial Intelligence in Design (AiDLab)</a>.
He is one of the inventors of the technologies to be commercialized in the start-up.
</p>
<div class="bottom-text" ref="bottomText">
<h4 class="name">Prof Calvin WONG</h4>
<h4 class="position">Co-Founder and Technical Advisor</h4>
</div>
</div>
<div class="img">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_team_01-600x887.png" alt="">
</div>
</div>
</section>
<section class="our-team-item bg2">
<div class="content">
<div class="img">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_team_02-600x887.png" alt="">
</div>
<div class="text">
<p>
Ms Wong is an accomplished C-level business executive with extensive experience in the fashion and luxury goods industries, building business across China and APAC and leading operations for renowned fashion houses such as DFS USA, Lane Crawford, Burberry Asia, Brunello Cucinelli and Versace Asia Pacific.
</p>
<div class="bottom-text" ref="bottomText">
<h4 class="name">Ms Kim WONG</h4>
<h4 class="position">Co-Founder and Chief Executive Officer</h4>
</div>
</div>
</div>
</section>
<section class="our-team-item bg1">
<div class="content">
<div class="text">
<p>
Dr Zou is currently serving as Assistant Professor at School of Fashion and Textiles at The Hong Kong Polytechnic University. She is one of the inventors of the technologies to be commercialized in the start-up.
</p>
<div class="bottom-text" ref="bottomText">
<h4 class="name">Dr Aemika ZOU</h4>
<h4 class="position">Technical Advisor</h4>
</div>
</div>
<div class="img">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_team_03-600x887.png" alt="">
</div>
</div>
</section>
<section class="our-team-item bg2">
<div class="content">
<div class="img">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_team_04-600x887.png" alt="">
</div>
<div class="text">
<p>
Giovanni is currently the Chief Executive Officer Asia of Salvatore Ferragamo.
</p>
<div class="bottom-text" ref="bottomText">
<h4 class="name">Mr Giovanni DI SALVO</h4>
<h4 class="position">Advisory Member</h4>
</div>
</div>
</div>
</section>
</template>
<style lang="less" scoped>
.our-team{
width: 100%;
background-color: #f9f9f9;
> .content{
margin: 0 auto;
max-width: 730px;
padding: 100px 0px 100px 0px;
> h2{
text-align: center;
margin-bottom: 30px;
color: #000000;
font-size: 40px;
font-weight: 600;
letter-spacing: 1px;
font-family: "Poppins", Sans-serif;
}
}
}
.our-team-item{
width: 100%;
&.bg1{
background-color: #eeeeee;
.img{
text-align: right;
}
}
&.bg2{
background-color: #ffffff;
.img{
text-align: left;
}
}
> .content{
padding: 100px 0;
max-width: 960px;
margin: 0 auto;
display: flex;
> div{
width: 50%;
}
> .text{
display: flex;
flex-direction: column;
justify-content: center;
> p{
font-family: "Poppins", Sans-serif;
font-size: 16px;
font-weight: 600;
line-height: 1.6em;
color: #000000;
margin-bottom: 20px;
> a{
color: inherit;
font-size: inherit;
font-family: inherit;
line-height: inherit;
text-decoration: none;
}
}
> .bottom-text{
> .name{
font-family: "Poppins", Sans-serif;
font-size: 16px;
font-weight: 600;
color: #000000;
line-height: 1;
margin-bottom: 10px;
}
> .position{
font-family: "Poppins", Sans-serif;
font-size: 16px;
font-weight: 400;
color: #000000;
line-height: 1;
}
}
}
> .img{
> img{
width: 100%;
height: 492px;
object-fit: cover;
max-width: 330px;
}
}
}
}
</style>

View File

@@ -0,0 +1,78 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { gsap, TweenMax, TweenLite } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
const imgItem1 = ref(null)
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<section class="strategic-partners">
<div class="content">
<h2 v-tween-Y="'30px'">Strategic Partners</h2>
<div class="img-box" v-tween-Y="'30px'">
<a href="https://www.aidlab.hk/">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_partners_01.png" alt="">
</a>
<a href="https://www.polyu.edu.hk/">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_partners_02-1.png" alt="">
</a>
<a href="https://www.rca.ac.uk/">
<img src="https://code-create.com.hk/wp-content/uploads/2022/11/about_partners_03-300x145.png" alt="">
</a>
<img src="https://code-create.com.hk/wp-content/uploads/2025/05/Eschange-600x130.jpg" alt="">
</div>
</div>
</section>
</template>
<style lang="less" scoped>
.strategic-partners{
width: 100%;
background-color: #fff;
> .content{
margin: 0 auto;
max-width: 1440px;
padding: 200px 0px 200px 0px;
> h2{
font-family: "Poppins", Sans-serif;
font-size: 40px;
font-weight: 600;
letter-spacing: 1px;
color: #000000;
margin-bottom: 30px;
text-align: center;
}
> .img-box{
width: 1110px;
margin: 0 auto;
margin-top: 40px;
display: flex;
height: 100px;
> a{
width: 25%;
> img{
object-fit: contain;
height: 100%;
width: 100%;
}
}
> img{
width: 25%;
object-fit: contain;
padding: 10px;
}
}
}
}
</style>

View File

@@ -0,0 +1,115 @@
<template>
<div class="account-info">
<div class="left">
<div class="info">
<img alt="" src="" class="avatar" />
<div class="name">12312</div>
<div class="email">12312@example.com</div>
</div>
<router-link
class="link"
v-for="(v, i) in navs"
:key="i"
:to="v.path"
@click="typeof v.onClick === 'function' && v.onClick()"
>
<span class="iconfont" :class="v.icon"></span>
<span class="label">{{ v.label }}</span>
</router-link>
</div>
<div class="content">
<router-view></router-view>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useUserInfoStore } from '@/stores/userInfo'
const userInfoStore = useUserInfoStore()
const navs = ref([
{
path: '/my-account',
label: 'Dashboard',
icon: 'icon-dashboard'
},
{
path: '/my-account/orders',
label: 'Orders',
icon: 'icon-orders'
},
{
path: '/my-account/subscriptions',
label: 'Subscriptions',
icon: 'icon-subscriptions'
},
{
path: '/my-account/address',
label: 'Address',
icon: 'icon-address'
},
{
path: '/my-account/methods',
label: 'Payment methods',
icon: 'icon-duidiaojiaohuanduihuan'
},
{
path: '/my-account/details',
label: 'Account details',
icon: 'icon-tubiao-'
},
{
path: '/my-account',
label: 'Log out',
icon: 'icon-tuichu',
onClick: () => {
console.log('logout')
userInfoStore.setToken('')
}
}
])
</script>
<style scoped lang="less">
.account-info {
display: flex;
> .left {
width: 270px;
border-right: 1px solid #e1e1e1;
margin-right: 30px;
> .info {
margin-bottom: 30px;
> .avatar {
width: 86px;
height: 86px;
margin-bottom: 15px;
border-radius: 50%;
}
> .name {
color: #222;
font-size: 16px;
}
> .email {
color: #333;
font-size: 14px;
}
}
> .link {
display: flex;
align-items: center;
width: 100%;
color: #222;
font-size: 16px;
text-decoration: none;
padding: 7px 0;
line-height: 1.6;
> .iconfont {
font-size: 20px;
margin-right: 5px;
}
}
}
> .content {
flex: 1;
}
}
</style>

View File

@@ -0,0 +1,107 @@
.login,
.register {
padding: 35px;
border: 1px solid #e1e1e1;
background-color: #fff;
border-radius: 5px;
}
.login > h2,
.register > h2 {
font-weight: 600;
color: #222;
font-size: 24px;
margin-bottom: 24px;
}
.login > form > *,
.register > form > * {
margin-bottom: 20px;
}
.login > form > .form-item,
.register > form > .form-item {
display: flex;
flex-direction: column;
}
.login > form > .form-item > label,
.register > form > .form-item > label {
margin-bottom: 5px;
font-size: 16px;
line-height: 1.6;
color: #333;
font-weight: 400;
}
.login > form > .form-item > label::after,
.register > form > .form-item > label::after {
content: ' *';
color: #f00;
}
.login > form > .form-item > .input-container > input,
.register > form > .form-item > .input-container > input,
.login > form > .form-item > input,
.register > form > .form-item > input {
width: 100%;
height: 35px;
padding: 0 17px;
font-size: 16px;
border: 1px solid #e1e1e1;
outline: none;
}
.login > form > .form-item > .input-container > input:focus,
.register > form > .form-item > .input-container > input:focus,
.login > form > .form-item > input:focus,
.register > form > .form-item > input:focus {
border-color: #000;
}
.login > form > .form-item > .input-container,
.register > form > .form-item > .input-container {
position: relative;
}
.login > form > .form-item > .input-container > input,
.register > form > .form-item > .input-container > input {
padding-right: 35px;
}
.login > form > .form-item > .input-container > .iconfont,
.register > form > .form-item > .input-container > .iconfont {
position: absolute;
right: 10px;
top: 0;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
cursor: pointer;
}
.login > form > .remember,
.register > form > .remember {
display: flex;
align-items: center;
}
.login > form > .remember > input,
.register > form > .remember > input {
margin: 4px 8px 0 0;
}
.login > form > .remember > label,
.register > form > .remember > label {
color: #333;
}
.login > form > .remember > .link,
.register > form > .remember > .link {
margin-left: auto;
color: #222;
}
.login > form > .subscribe,
.register > form > .subscribe {
font-size: 16px;
line-height: 1.6;
color: #333;
}
.login > form > .tip,
.register > form > .tip {
font-size: 16px;
line-height: 1.6;
color: #333;
}
.login > form > .tip > a,
.register > form > .tip > a {
color: #000;
}

View File

@@ -0,0 +1,61 @@
<template>
<div class="my-account">
<div class="header">
<h1 class="title">
<span class="iconfont icon-tubiao-"></span>
<span>My account</span>
</h1>
</div>
<div class="content" v-if="!token">
<Login />
<Register />
</div>
<div class="content" v-else>
<AccountInfo />
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import Login from './login.vue'
import Register from './register.vue'
import AccountInfo from './account-info.vue'
import { useUserInfoStore } from '@/stores/userInfo'
const userInfoStore = useUserInfoStore()
const token = computed(() => userInfoStore.state.token)
</script>
<style scoped lang="less">
.my-account {
background-color: #f9f9f9;
> .header {
border-top: var(--main-header-height, 85px) solid #000;
background-color: #666;
padding: 32px 0;
color: #fff;
margin-bottom: 32px;
> h1 {
display: flex;
align-items: center;
justify-content: center;
height: 80px;
> span {
font-size: 40px;
font-weight: 400;
}
}
}
> .content {
max-width: 1200px;
margin: 0 auto;
padding-bottom: 80px;
display: flex;
align-items: flex-start;
gap: 60px;
> * {
flex: 1;
}
animation: opacity-in 0.3s linear both;
}
}
</style>

View File

@@ -0,0 +1,107 @@
.login,
.register {
padding: 35px;
border: 1px solid #e1e1e1;
background-color: #fff;
border-radius: 5px;
>h2 {
font-weight: 600;
color: #222;
font-size: 24px;
margin-bottom: 24px;
}
>form {
>* {
margin-bottom: 20px;
}
>.form-item {
display: flex;
flex-direction: column;
>label {
margin-bottom: 5px;
font-size: 16px;
line-height: 1.6;
color: #333;
font-weight: 400;
&::after {
content: ' *';
color: #f00;
}
}
>.input-container>input,
>input {
width: 100%;
height: 35px;
padding: 0 17px;
font-size: 16px;
border: 1px solid #e1e1e1;
outline: none;
&:focus {
border-color: #000;
}
}
>.input-container {
position: relative;
>input {
padding-right: 35px;
}
>.iconfont {
position: absolute;
right: 10px;
top: 0;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
cursor: pointer;
}
}
}
>.remember {
display: flex;
align-items: center;
>input {
margin: 4px 8px 0 0;
}
>label {
color: #333;
}
>.link {
margin-left: auto;
color: #222;
}
}
>.subscribe {
font-size: 16px;
line-height: 1.6;
color: #333;
}
>.tip {
font-size: 16px;
line-height: 1.6;
color: #333;
>a {
color: #000;
}
}
}
}

View File

@@ -0,0 +1,62 @@
<template>
<div class="login">
<h2>Login</h2>
<form @submit.prevent="handleSubmit">
<div class="form-item">
<label for="email">Username or email address</label>
<input type="email" id="email" name="email" required v-model="fromData.email" />
</div>
<div class="form-item">
<label for="password">Password</label>
<div class="input-container">
<input
id="password"
name="password"
required
:type="passShow ? 'text' : 'password'"
v-model="fromData.password"
/>
<span
class="iconfont"
:class="[passShow ? 'icon-hide' : 'icon-show']"
@click="passShow = !passShow"
></span>
</div>
</div>
<div class="remember">
<input type="checkbox" id="remember" name="remember" v-model="remember" />
<label for="remember">Remember me</label>
<router-link class="link" to="/my-account/lost-password"
>Lost your password?</router-link
>
</div>
<button type="submit" custom>LOG IN</button>
</form>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useGlobalStore } from '@/stores/global'
const globalStore = useGlobalStore()
import { useUserInfoStore } from '@/stores/userInfo'
const userInfoStore = useUserInfoStore()
const passShow = ref(false)
const remember = ref(false)
const fromData = ref({
email: '',
password: ''
})
const handleSubmit = () => {
console.log(fromData.value, remember.value)
globalStore.setLoading(true)
setTimeout(() => {
globalStore.setLoading(false)
userInfoStore.setToken('123456')
}, 1000)
}
</script>
<style scoped lang="less">
@import './less/style.less';
</style>

View File

@@ -0,0 +1,11 @@
<template>
<div class="orders">No order has been made yet.</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
</script>
<style scoped lang="less">
.orders {
}
</style>

View File

@@ -0,0 +1,78 @@
<template>
<div class="register">
<h2>Register</h2>
<form @submit.prevent="handleSubmit">
<div class="form-item">
<label for="username">Username</label>
<input
type="username"
id="username"
name="username"
required
v-model="fromData.username"
/>
</div>
<div class="form-item">
<label for="email">Email address</label>
<input type="email" id="email" name="email" required v-model="fromData.email" />
</div>
<div class="form-item">
<label for="password">Password</label>
<div class="input-container">
<input
id="password"
name="password"
required
:type="passShow ? 'text' : 'password'"
v-model="fromData.password"
/>
<span
class="iconfont"
:class="[passShow ? 'icon-hide' : 'icon-show']"
@click="passShow = !passShow"
></span>
</div>
</div>
<div class="subscribe">
<input
type="checkbox"
id="subscribe"
name="subscribe"
v-model="fromData.subscribe"
/>
<label for="subscribe"
>Subscribe to Code Create product/service news and newsletter</label
>
</div>
<div class="tip">
Your personal data will be used to support your experience throughout this website,
to manage access to your account, and for other purposes described in our
<router-link class="link" to="/my-account/privacy-policy"
>Privacy Policy</router-link
>
</div>
<button type="submit" custom>REGISTER</button>
</form>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useUserInfoStore } from '@/stores/userInfo'
const userInfoStore = useUserInfoStore()
const passShow = ref(false)
const remember = ref(false)
const fromData = ref({
username: '',
email: '',
password: '',
subscribe: false
})
const handleSubmit = () => {
console.log(fromData.value, remember.value)
}
</script>
<style scoped lang="less">
@import './less/style.less';
</style>

View File

@@ -0,0 +1,64 @@
<template>
<div class="welcome">
<h3 class="title">Welcome to your account page</h3>
<div class="tip">
Hi <b>XXX</b>, today is a great day to check your account page. You can check also:
</div>
<div class="buttons">
<router-link class="link" v-for="(v, i) in navs" :key="i" :to="v.path">
<button custom>
<span class="iconfont" :class="v.icon"></span>
<span class="label">{{ v.label }}</span>
</button>
</router-link>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
const navs = ref([
{
path: '/my-account/orders',
label: 'RECENT ORDERS',
icon: 'icon-orders'
},
{
path: '/my-account/address',
label: 'ADDRESSSES',
icon: 'icon-address'
},
{
path: '/my-account/details',
label: 'ACCOUNT DETAILS',
icon: 'icon-tubiao-'
}
])
</script>
<style scoped lang="less">
.welcome {
> .title {
font-weight: 600;
letter-spacing: 2px;
color: #222222;
font-size: 24px;
margin-bottom: 10px;
}
> .tip {
color: #333;
margin-bottom: 20px;
}
> .buttons {
display: flex;
align-items: center;
justify-content: center;
> .link {
margin: 0 4px;
flex: 1;
text-decoration: none;
}
}
}
</style>

View File

@@ -3,18 +3,18 @@ import AboutView from './pages/about-us/index.vue'
import ContactView from './pages/ContactView.vue'
import HomeView from './pages/home/index.vue'
import ProductsView from './pages/ProductsView.vue'
import { LANGS } from './lang'
export const routes: RouteRecordRaw[] = [
{
path: '/:lang?',
path: `/:lang(${LANGS.join('|')})?`,
children: [
{
path: '',
component: HomeView,
alias: ['/:lang?', '/:lang?/home']
},
{
path: 'about',
path: 'about-us',
name: 'about-us',
component: AboutView
},
{
@@ -23,7 +23,7 @@ export const routes: RouteRecordRaw[] = [
component: ProductsView
},
{
path: 'contact',
path: 'contact-us',
name: 'contact',
component: ContactView
},
@@ -31,7 +31,27 @@ export const routes: RouteRecordRaw[] = [
path: 'aida',
name: 'Aida',
component: () => import('./pages/aida/index.vue')
}
},
{
path: 'my-account',
name: 'MyAccount',
component: () => import('./pages/my-account/index.vue'),
children: [
{
path: '',
component: () => import('./pages/my-account/welcome.vue'),
},
{
path: 'orders',
component: () => import('./pages/my-account/orders.vue'),
},
{
path: ':pathMatch(.*)*',
component: () => import('./pages/my-account/welcome.vue'),
},
]
},
]
}
]

14
src/stores/global.ts Normal file
View File

@@ -0,0 +1,14 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useGlobalStore = defineStore('global', () => {
const state = ref({
loading: false,// 全局loading
})
const setLoading = (v: boolean) => { state.value.loading = v }
return {
state,
setLoading,
}
})

9
src/stores/index.ts Normal file
View File

@@ -0,0 +1,9 @@
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-persistedstate-plugin'
// 创建store实例
const store = createPinia()
// 使用持久化插件(全局持久化)
store.use(createPersistedState())
export default store
export * from './global'
export * from './userInfo'

30
src/stores/userInfo.ts Normal file
View File

@@ -0,0 +1,30 @@
// 每一个存储的模块命名规则use开头store结尾
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserInfoStore = defineStore('userInfo', () => {
const state = ref({
userInfo: {},
token: '',
})
// actions
const setUserInfo = (data: any) => {
state.value.userInfo = data
}
const setToken = (data: string) => {
state.value.token = data
}
const logOut = async () => {
}
return {
state,
setToken,
setUserInfo,
logOut,
}
})

View File

@@ -1,7 +1,26 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
"files": [],
"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/types/**/*.d.ts"],
"compilerOptions": {
"forceConsistentCasingInFileNames": false, // ⚠️ 禁用大小写检查
"allowJs": true,
"baseUrl": ".",
"types": ["node", "unplugin-vue-define-options/macros-global"],
"paths": {
"@/*": ["./src/*"],
"_c/*": ["./src/components/*"]
},
"skipLibCheck": true,
"strict": false,
"noEmit": true,
"noImplicitAny": false,
"noEmitOnError": false
},
"references": [
{ "path": "./tsconfig.app.json" },
{
"path": "./tsconfig.node.json"
}
]
}