2025年8月21日 5个详情页完成

This commit is contained in:
chendi 2025-08-21 16:05:33 +08:00
parent 4e5b99e5d9
commit 8b78ad2b6d
21 changed files with 519 additions and 119 deletions

View File

@ -3,9 +3,12 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="preload" as="image" href="/src/assets/images/hero-bg.jpg" fetchpriority="high">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
</head>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>

View File

@ -1,60 +1,21 @@
<script setup lang="ts">
import BackToTop from './components/common/BackToTop.vue'
import Navbar from './components/common/Navbar.vue'
import AboutUs from './components/company/AboutUs.vue'
import TeamMembers from './components/team/TeamMembers.vue'
import ProjectShowcase from './components/projects/ProjectShowcase.vue'
import ContactForm from './components/contact/ContactForm.vue'
import CompanyTimeline from './components/timeline/CompanyTimeline.vue'
import { useLanguageStore } from './store/language'
// store
const languageStore = useLanguageStore()
// 使使API
import { provide } from 'vue'
//
provide('t', (key: string) => languageStore.t(key))
</script>
<!-- src/App.vue -->
<template>
<div id="app">
<Navbar />
<BackToTop />
<!-- 公共组件 hideHeader false 时显示 -->
<Navbar v-if="!route.meta.hideHeader" />
<BackToTop v-if="!route.meta.hideHeader" />
<!-- 首页横幅 -->
<section id="home" class="hero-section">
<div class="hero-content">
<h1>Professional Software Solutions</h1>
<p>We deliver innovative technology solutions for businesses</p>
<div class="cta-buttons">
<a href="#about" class="btn-primary">{{ languageStore.t('nav.about') }}</a>
<a href="#contact" class="btn-secondary">{{ languageStore.t('nav.contact') }}</a>
</div>
</div>
</section>
<!-- 路由出口根据当前路由渲染对应组件 -->
<!-- 首页路由渲染 HomePage.vue详情页路由渲染 Project3Zh.vue -->
<router-view />
<!-- 工作室介绍 -->
<AboutUs />
<!-- 团队介绍 -->
<TeamMembers />
<!-- 成功案例 -->
<ProjectShowcase />
<!-- 公司历程 -->
<CompanyTimeline />
<!-- 联系我们 -->
<ContactForm />
<!-- 页脚 -->
<footer class="footer">
<!-- 公共页脚 hideHeader false 时显示 -->
<footer class="footer" v-if="!route.meta.hideHeader">
<div class="container">
<div class="footer-content">
<p>&copy; {{ new Date().getFullYear() }} Company Name. All rights reserved.</p>
<div class="social-links">
<!-- 社交图标代码不变 -->
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg></a>
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg></a>
<a href="#"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg></a>
@ -66,6 +27,23 @@ provide('t', (key: string) => languageStore.t(key))
</div>
</template>
<script setup lang="ts">
import BackToTop from './components/common/BackToTop.vue'
import Navbar from './components/common/Navbar.vue'
import { useLanguageStore } from './store/language'
import { provide } from 'vue'
import { useRoute } from 'vue-router';
// store
const languageStore = useLanguageStore()
provide('t', (key: string) => languageStore.t(key))
//
const route = useRoute();
</script>
<style scoped>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
@ -74,41 +52,6 @@ provide('t', (key: string) => languageStore.t(key))
color: #2c3e50;
}
.hero-section {
height: 100vh;
background-color: var(--bg-color);
color: var(--text-color);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url('https://picsum.photos/id/180/1920/1080');
background-size: cover;
background-position: center;
background-attachment: fixed;
position: relative;
overflow: hidden;
}
.hero-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, var(--primary-color) 0%, transparent 70%);
opacity: 0.5;
z-index: 1;
}
.hero-content {
max-width: 800px;
padding: 2rem;
position: relative;
z-index: 2;
animation: fadeInUp 1s ease-out;
}
@keyframes fadeInUp {
from {

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 910 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

View File

@ -10,7 +10,7 @@
<div class="project-info">
<h3>{{ t(project.title) }}</h3>
<p>{{ t(project.description) }}</p>
<button class="view-details-btn">{{ t('projects.viewDetails') }}</button>
<button class="view-details-btn" @click="openDetail(project)">{{ t('projects.viewDetails') }}</button>
</div>
</div>
</div>
@ -20,14 +20,55 @@
<script setup lang="ts">
import { ref, inject } from 'vue'
import { useRouter } from 'vue-router';
import { useLanguageStore } from '../../store/language';
//
const router = useRouter();
const store = useLanguageStore();
const openDetail = (project: Project) => {
if (project.detailLink) {
// detailLink
window.open(project.detailLink, '_blank');
} else if (project.detailPageKey) {
// detailPageKey
const currentLang = store.currentLanguage; //
console.log('当前语言:', currentLang); // 'zh' 'jp'
//
const routeName = currentLang === 'zh'
? `${project.detailPageKey}Detail`
: `${project.detailPageKey}DetailJp`;
console.log('生成的路由名称:', routeName); //
//
const routeExists = router.getRoutes().some(route => route.name === routeName);
console.log('路由是否存在:', routeExists);
// ,push
//router.push({ name: routeName });
//
const url = router.resolve({ name: routeName }).href;
const fullUrl = window.location.origin + url; //
console.log('完整URL:', fullUrl); // http://localhost:5173/project3/zh
window.open(url, '_blank');
}
};
export interface Project {
id: number
title: string
description: string
image: string
detailLink: string
detailLink?: string
details: string
detailPageKey?: string //
}
// src/assets
@ -70,7 +111,7 @@ const projects = ref<Project[]>([
title: "projects.project3.title",
description: "projects.project3.description",
image: imageMap[3], // ID3
detailLink: "project3", // 3
detailPageKey: "project3", // 3
details: 'This project involved creating a healthcare management system that streamlines patient registration, appointment scheduling, medical records management, and billing.',
},
{
@ -78,7 +119,7 @@ const projects = ref<Project[]>([
title: "projects.project4.title",
description: "projects.project4.description",
image: imageMap[4], // ID4
detailLink: "project4", // 4
detailPageKey: "project4", // 4
details: 'We developed an ERP system that integrates various business functions including finance, human resources, supply chain, and customer relationship management.',
},
{
@ -88,7 +129,7 @@ const projects = ref<Project[]>([
image: imageMap[5], // ID5
detailLink: "https://maps.gsi.go.jp/#5/36.104611/140.084556/&base=std&ls=std&disp=1&vs=c1g1j0h0k0l0u0t0z0r0s0m0f1", // 5
details: 'We developed an ERP system that integrates various business functions including finance, human resources, supply chain, and customer relationship management.',
},
}
])

View File

@ -1,6 +1,10 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index.ts' // 确保路径正确
// 引入Pinia
import { createPinia } from 'pinia'
// 引入TDesign UI组件库
@ -8,9 +12,16 @@ import TDesign from 'tdesign-vue-next'
import 'tdesign-vue-next/es/style/index.css'
const app = createApp(App)
// 必须先 use(router),再挂载
app.use(router)
// 使用Pinia
app.use(createPinia())
// 使用TDesign
app.use(TDesign)
app.mount('#app')
// 临时打印路由列表,确认配置是否生效
console.log('已注册的路由:', router.getRoutes().map(r => r.path));

View File

@ -1,29 +1,57 @@
// import { createRouter, createWebHistory } from 'vue-router';
// import { useLanguageStore } from '@/store/language';
// src/router/index.ts
import { createRouter, createWebHistory} from 'vue-router';
import Project3Jp from '@/views/ProjectDetail/Project3Jp.vue';
import Project3Zh from '@/views/ProjectDetail/Project3Zh.vue';
import Project4Jp from '@/views/ProjectDetail/Project4Jp.vue';
import Project4Zh from '@/views/ProjectDetail/Project4Zh.vue';
// const router = createRouter({
// history: createWebHistory(),
// routes: [
// // 其他路由...
// {
// path: '/project3',
// name: 'Project3Detail',
// component: () => {
// const store = useLanguageStore();
// const lang = store.language;
// return import(`@/views/ProjectDetail/Project3${lang.toUpperCase()}.vue`);
// },
// },
// {
// path: '/project4',
// name: 'Project4Detail',
// component: () => {
// const store = useLanguageStore();
// const lang = store.language;
// return import(`@/views/ProjectDetail/Project4${lang.toUpperCase()}.vue`);
// },
// },
// ],
// });
// export default router;
const router = createRouter({
history: createWebHistory(),
routes: [
// 首页路由
{
path: '/',
name: 'Home',
component: () => import('@/views/HomePage.vue'),
meta: { hideHeader: false }, // 主页显示公共组件
},
// ✅ 项目详情页
// 项目3 - 中文
{
path: '/project3/zh',
name: 'project3Detail', // 中文路由名称
component: Project3Zh,
meta: { hideHeader: true },
},
// 项目3 - 日文
{
path: '/project3/jp',
name: 'project3DetailJp', // 日文路由名称
component: Project3Jp,
meta: { hideHeader: true },
},
// 项目4 - 中文
{
path: '/project4/zh',
name: 'project4Detail', // 中文路由名称
component: Project4Zh,
meta: { hideHeader: true },
},
// 项目4 - 日文
{
path: '/project4/jp',
name: 'project4DetailJp', // 日文路由名称
component: Project4Jp,
meta: { hideHeader: true },
},
// 其他路由...
],
});
export default router;

6
src/shims-vue.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
// src/shims-vue.d.ts
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

172
src/views/HomePage.vue Normal file
View File

@ -0,0 +1,172 @@
<!-- src/views/HomePage.vue -->
<template>
<div class="home-page">
<!-- 首页横幅 -->
<section id="home" class="hero-section">
<div class="hero-content">
<h1>Professional Software Solutions</h1>
<p>We deliver innovative technology solutions for businesses</p>
<div class="cta-buttons">
<a href="#about" class="btn-primary">{{ t('nav.about') }}</a>
<a href="#contact" class="btn-secondary">{{ t('nav.contact') }}</a>
</div>
</div>
</section>
<!-- 工作室介绍 -->
<AboutUs />
<!-- 团队介绍 -->
<TeamMembers />
<!-- 成功案例 -->
<ProjectShowcase />
<!-- 公司历程 -->
<CompanyTimeline />
<!-- 联系我们 -->
<ContactForm />
</div>
</template>
<script setup lang="ts">
//
import AboutUs from '@/components/company/AboutUs.vue'
import TeamMembers from '@/components/team/TeamMembers.vue'
import ProjectShowcase from '@/components/projects/ProjectShowcase.vue'
import ContactForm from '@/components/contact/ContactForm.vue'
import CompanyTimeline from '@/components/timeline/CompanyTimeline.vue'
import { inject } from 'vue'
// App.vue
const t = inject<(key: string) => string>('t') || ((key) => key)
</script>
<style scoped>
.hero-section {
height: 100vh;
background-color: var(--bg-color);
color: var(--text-color);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
background-image: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)), url('/src/assets/images/hero-bg.jpg'); /* 绝对路径,基于项目根目录 */
background-size: cover;
background-position: center;
background-attachment: fixed;
position: relative;
overflow: hidden;
}
.hero-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, var(--primary-color) 0%, transparent 70%);
opacity: 0.5;
z-index: 1;
}
.hero-content {
max-width: 800px;
padding: 2rem;
position: relative;
z-index: 2;
animation: fadeInUp 1s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.hero-content h1 {
font-size: 3.5rem;
margin-bottom: 1rem;
background: linear-gradient(90deg, white, var(--primary-light));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
line-height: 1.1;
letter-spacing: -1px;
}
.hero-content p {
font-size: 1.2rem;
margin-bottom: 2.5rem;
color: rgba(255, 255, 255, 0.9);
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.cta-buttons {
display: flex;
justify-content: center;
gap: 1rem;
}
.btn-primary, .btn-secondary {
padding: 0.8rem 2rem;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: var(--transition);
display: inline-block;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.btn-primary {
background-color: var(--primary-color);
color: white;
border: none;
box-shadow: var(--shadow);
}
.btn-primary:hover {
background-color: var(--primary-dark);
transform: translateY(-3px);
box-shadow: var(--shadow-lg);
}
.btn-secondary {
background-color: transparent;
color: white;
border: 2px solid white;
}
.btn-secondary:hover {
background-color: white;
color: var(--bg-color);
transform: translateY(-3px);
}
@media (max-width: 768px) {
.hero-content h1 {
font-size: 2.5rem;
}
.hero-content p {
font-size: 1rem;
}
.footer-content {
flex-direction: column;
text-align: center;
gap: 1rem;
}
}
</style>

View File

@ -0,0 +1,45 @@
<!-- src/views/ProjectDetail/Project3Zh.vue -->
<template>
<div class="container">
<!-- 勤怠登録画面 -->
<h2>勤怠登録画面</h2>
<img :src="img1" alt="勤怠登录页面">
<!-- 休暇申請画面 -->
<h2>休暇申請画面</h2>
<img :src="img2" alt="休假申请页面">
<!-- 勤怠集計画面 -->
<h2>勤怠集計画面</h2>
<img :src="img3" alt="勤怠集计页面">
</div>
</template>
<script setup>
import img1 from '@/assets/project3/project3-1.png'
import img2 from '@/assets/project3/project3-2.png'
import img3 from '@/assets/project3/project3-3.png'
//
defineOptions({
name: 'Project3Zh'
})
</script>
<style scoped>
.container {
padding: 20px;
font-family: Arial, sans-serif;
}
h1, h2, h3 {
color: #333;
}
img {
max-width: 100%;
height: auto;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,45 @@
<!-- src/views/ProjectDetail/Project4Zh.vue -->
<template>
<div class="container">
<!-- 勤怠登录页面 -->
<h2>勤怠登录页面</h2>
<img :src="img1" alt="勤怠登录页面">
<!-- 休假申请页面 -->
<h2>休假申请页面</h2>
<img :src="img2" alt="休假申请页面">
<!-- 勤怠集计页面 -->
<h2>勤怠集计页面</h2>
<img :src="img3" alt="勤怠集计页面">
</div>
</template>
<script setup>
import img1 from '@/assets/project3/project3-1.png'
import img2 from '@/assets/project3/project3-2.png'
import img3 from '@/assets/project3/project3-3.png'
//
defineOptions({
name: 'Project3Zh'
})
</script>
<style scoped>
.container {
padding: 20px;
font-family: Arial, sans-serif;
}
h1, h2, h3 {
color: #333;
}
img {
max-width: 100%;
height: auto;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,50 @@
<!-- src/views/ProjectDetail/Project4Zh.vue -->
<template>
<div class="container">
<!-- 資材管理画面 -->
<h2>資材管理画面</h2>
<img :src="img1" alt="資材管理画面">
<!-- 工程管理画面 -->
<h2>工程管理画面</h2>
<img :src="img2" alt="工程管理画面">
<!-- 設備保全画面 -->
<h2>設備保全画面</h2>
<img :src="img3" alt="設備保全画面">
<!-- 生産管理画面 -->
<h2>生産管理画面</h2>
<img :src="img4" alt="生産管理画面">
</div>
</template>
<script setup>
import img1 from '@/assets/project4/project4-1.png'
import img2 from '@/assets/project4/project4-2.png'
import img3 from '@/assets/project4/project4-3.png'
import img4 from '@/assets/project4/project4-3.png'
//
defineOptions({
name: 'Project3Zh'
})
</script>
<style scoped>
.container {
padding: 20px;
font-family: Arial, sans-serif;
}
h1, h2, h3 {
color: #333;
}
img {
max-width: 100%;
height: auto;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>

View File

@ -0,0 +1,50 @@
<!-- src/views/ProjectDetail/Project4Zh.vue -->
<template>
<div class="container">
<!-- 物料管理页面 -->
<h2>物料管理页面</h2>
<img :src="img1" alt="物料管理页面">
<!-- 工艺管理页面 -->
<h2>工艺管理页面</h2>
<img :src="img2" alt="工艺管理页面">
<!-- 设备保养页面 -->
<h2>设备保养页面</h2>
<img :src="img3" alt="设备保养页面">
<!-- 生产管理页面 -->
<h2>生产管理页面</h2>
<img :src="img4" alt="生产管理页面">
</div>
</template>
<script setup>
import img1 from '@/assets/project4/project4-1.png'
import img2 from '@/assets/project4/project4-2.png'
import img3 from '@/assets/project4/project4-3.png'
import img4 from '@/assets/project4/project4-3.png'
//
defineOptions({
name: 'Project4Zh'
})
</script>
<style scoped>
.container {
padding: 20px;
font-family: Arial, sans-serif;
}
h1, h2, h3 {
color: #333;
}
img {
max-width: 100%;
height: auto;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>

View File

@ -11,5 +11,5 @@
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "src/stores/layout"]
}

View File

@ -1,7 +1,13 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()]
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // 将 @ 指向 src 目录
},
},
})