Merge remote-tracking branch 'refs/remotes/origin/feature/project_dedtail' into main

Conflicts:
	index.html
	src/components/common/Navbar.vue
	src/components/company/AboutUs.vue
	src/components/projects/ProjectShowcase.vue
	src/components/timeline/CompanyTimeline.vue
	src/locales/ja.ts
	src/locales/zh.ts
	src/views/HomePage.vue
This commit is contained in:
lv 2025-08-30 17:00:59 +08:00
commit 86e1a600a7
10 changed files with 1431 additions and 1350 deletions

View File

@ -1,16 +1,17 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="preload" as="image" href="/src/assets/images/hero-bg.jpg" fetchpriority="high"> <!--<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" /> <link rel="preload" as="image" href="images/hero-bg.jpg" fetchpriority="high">
<title>优阅工作室</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>优阅工作室</title>
</head>
<body> </head>
<div id="app"></div> <body>
<script type="module" src="/src/main.ts"></script> <div id="app"></div>
</body> <script type="module" src="/src/main.ts"></script>
</html> </body>
</html>

View File

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 197 KiB

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 KiB

View File

@ -1,308 +1,321 @@
<template> <template>
<header class="navbar-container" :class="{ scrolled: isScrolled }"> <header class="navbar-container" :class="{ scrolled: isScrolled }">
<div class="container"> <div class="container">
<div class="logo"> <div class="logo">
<a href="#home">{{ t('nav.home') }}</a> <img src="/images/logo.png" alt="Company Logo" class="logo-image">
</div> <a href="#home">{{ t('nav.name') }}</a>
<nav> </div>
<ul class="nav-links"> <nav>
<li><a href="#home">{{ t('nav.home') }}</a></li> <ul class="nav-links">
<li><a href="#about">{{ t('nav.about') }}</a></li> <li><a href="#home">{{ t('nav.home') }}</a></li>
<li><a href="#team">{{ t('nav.team') }}</a></li> <li><a href="#about">{{ t('nav.about') }}</a></li>
<li><a href="#projects">{{ t('nav.projects') }}</a></li> <li><a href="#team">{{ t('nav.team') }}</a></li>
<li><a href="#contact">{{ t('nav.contact') }}</a></li> <li><a href="#projects">{{ t('nav.projects') }}</a></li>
</ul> <li><a href="#contact">{{ t('nav.contact') }}</a></li>
</nav> </ul>
<div class="language-switcher"> </nav>
<button @click="toggleLanguage" class="language-btn"> <div class="language-switcher">
{{ currentLanguage === 'zh' ? '日本語' : '中文' }} <button @click="toggleLanguage" class="language-btn">
</button> {{ currentLanguage === 'zh' ? '日本語' : '中文' }}
</div> </button>
<div class="mobile-menu-btn"> </div>
<button @click="toggleMobileMenu"> <div class="mobile-menu-btn">
<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"> <button @click="toggleMobileMenu">
<line x1="3" y1="12" x2="21" y2="12"></line> <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">
<line x1="3" y1="6" x2="21" y2="6"></line> <line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="18" x2="21" y2="18"></line> <line x1="3" y1="6" x2="21" y2="6"></line>
</svg> <line x1="3" y1="18" x2="21" y2="18"></line>
</button> </svg>
</div> </button>
</div> </div>
<div class="mobile-menu" v-if="isMobileMenuOpen"> </div>
<ul class="mobile-nav-links"> <div class="mobile-menu" v-if="isMobileMenuOpen">
<li><a href="#home" @click="closeMobileMenu">{{ t('nav.home') }}</a></li> <ul class="mobile-nav-links">
<li><a href="#about" @click="closeMobileMenu">{{ t('nav.about') }}</a></li> <li><a href="#home" @click="closeMobileMenu">{{ t('nav.home') }}</a></li>
<li><a href="#team" @click="closeMobileMenu">{{ t('nav.team') }}</a></li> <li><a href="#about" @click="closeMobileMenu">{{ t('nav.about') }}</a></li>
<li><a href="#projects" @click="closeMobileMenu">{{ t('nav.projects') }}</a></li> <li><a href="#team" @click="closeMobileMenu">{{ t('nav.team') }}</a></li>
<li><a href="#contact" @click="closeMobileMenu">{{ t('nav.contact') }}</a></li> <li><a href="#projects" @click="closeMobileMenu">{{ t('nav.projects') }}</a></li>
<li> <li><a href="#contact" @click="closeMobileMenu">{{ t('nav.contact') }}</a></li>
<button @click="toggleLanguage" class="mobile-language-btn"> <li>
{{ currentLanguage === 'zh' ? '日本語' : '中文' }} <button @click="toggleLanguage" class="mobile-language-btn">
</button> {{ currentLanguage === 'zh' ? '日本語' : '中文' }}
</li> </button>
</ul> </li>
</div> </ul>
</header> </div>
</template> </header>
</template>
<script setup lang="ts">
import { ref, computed, inject, onMounted, onUnmounted } from 'vue' <script setup lang="ts">
import { useLanguageStore } from '../../store/language' import { ref, computed, inject, onMounted, onUnmounted } from 'vue'
import { useLanguageStore } from '../../store/language'
export interface NavbarProps {
// props export interface NavbarProps {
} // props
}
const store = useLanguageStore()
const currentLanguage = computed(() => store.currentLanguage) const store = useLanguageStore()
const isMobileMenuOpen = ref(false) const currentLanguage = computed(() => store.currentLanguage)
const isScrolled = ref(false) const isMobileMenuOpen = ref(false)
// const isScrolled = ref(false)
const t = inject<(key: string) => string>('t') || ((key) => key) //
const t = inject<(key: string) => string>('t') || ((key) => key)
//
const handleScroll = () => { //
isScrolled.value = window.scrollY > 50 const handleScroll = () => {
} isScrolled.value = window.scrollY > 50
}
//
onMounted(() => { //
window.addEventListener('scroll', handleScroll) onMounted(() => {
}) window.addEventListener('scroll', handleScroll)
})
//
onUnmounted(() => { //
window.removeEventListener('scroll', handleScroll) onUnmounted(() => {
}) window.removeEventListener('scroll', handleScroll)
})
const toggleLanguage = () => {
store.toggleLanguage() const toggleLanguage = () => {
} store.toggleLanguage()
}
const toggleMobileMenu = () => {
isMobileMenuOpen.value = !isMobileMenuOpen.value const toggleMobileMenu = () => {
} isMobileMenuOpen.value = !isMobileMenuOpen.value
}
const closeMobileMenu = () => {
isMobileMenuOpen.value = false const closeMobileMenu = () => {
} isMobileMenuOpen.value = false
</script> }
</script>
<style scoped>
.navbar-container { <style scoped>
background-color: var(--bg-color); .navbar-container {
color: var(--text-color); background-color: var(--bg-color);
padding: 1rem 0; color: var(--text-color);
position: fixed; padding: 1rem 0;
top: 0; position: fixed;
left: 0; top: 0;
right: 0; left: 0;
z-index: 1000; right: 0;
box-shadow: var(--shadow); z-index: 1000;
transition: var(--transition); box-shadow: var(--shadow);
} transition: var(--transition);
}
.navbar-container.scrolled {
/* background-color: rgba(26, 26, 46, 0.95); .navbar-container.scrolled {
padding: 0.8rem 0; */ /* background-color: rgba(26, 26, 46, 0.95);
} padding: 0.8rem 0; */
}
.container {
max-width: 1200px; .logo {
margin: 0 auto; display: flex; /* 让Logo和文字横向排列 */
padding: 0 1.5rem; align-items: center; /* 垂直居中对齐 */
display: flex; gap: 0.5rem; /* Logo与文字间距 */
justify-content: space-between; }
align-items: center;
} .logo-image {
width: 60px; /* Logo宽度根据需要调整 */
.logo { height: 55px; /* 自定义高度,不受宽高比限制 */
font-size: 1.5rem; /*height: auto; 保持宽高比 */
font-weight: 700; }
letter-spacing: -0.5px;
} .container {
max-width: 1200px;
.logo a { margin: 0 auto;
color: var(--text-color); padding: 0 1.5rem;
text-decoration: none; display: flex;
display: flex; justify-content: space-between;
align-items: center; align-items: center;
gap: 0.5rem; }
}
.logo {
.nav-links { font-size: 1.5rem;
display: flex; font-weight: 700;
list-style: none; letter-spacing: -0.5px;
margin: 0; }
padding: 0;
} .logo a {
color: var(--text-color);
.nav-links li { text-decoration: none;
margin-left: 2rem; display: flex;
position: relative; align-items: center;
} gap: 0.5rem;
}
.nav-links a {
color: var(--text-color); .nav-links {
text-decoration: none; display: flex;
transition: var(--transition); list-style: none;
font-weight: 500; margin: 0;
position: relative; padding: 0;
} }
.nav-links a::after { .nav-links li {
content: ''; margin-left: 2rem;
position: absolute; position: relative;
bottom: -4px; }
left: 0;
width: 0; .nav-links a {
height: 2px; color: var(--text-color);
background-color: var(--primary-color); text-decoration: none;
transition: var(--transition); transition: var(--transition);
} font-weight: 500;
position: relative;
.nav-links a:hover { }
color: var(--primary-color);
} .nav-links a::after {
content: '';
.nav-links a:hover::after { position: absolute;
width: 100%; bottom: -4px;
} left: 0;
width: 0;
.language-switcher { height: 2px;
margin-left: 1rem; background-color: var(--primary-color);
} transition: var(--transition);
}
.language-btn {
background-color: transparent; .nav-links a:hover {
color: var(--text-color); color: var(--primary-color);
border: 1px solid var(--border-color); }
padding: 0.5rem 1rem;
cursor: pointer; .nav-links a:hover::after {
transition: var(--transition); width: 100%;
border-radius: 6px; }
font-weight: 500;
} .language-switcher {
margin-left: 1rem;
.language-btn:hover { }
background-color: var(--primary-color);
color: white; .language-btn {
border-color: var(--primary-color); background-color: transparent;
transform: translateY(-2px); color: var(--text-color);
} border: 1px solid var(--border-color);
padding: 0.5rem 1rem;
.mobile-menu-btn { cursor: pointer;
display: none; transition: var(--transition);
background-color: transparent; border-radius: 6px;
border: none; font-weight: 500;
color: var(--text-color); }
cursor: pointer;
padding: 0.5rem; .language-btn:hover {
border-radius: 6px; background-color: var(--primary-color);
transition: var(--transition); color: white;
} border-color: var(--primary-color);
transform: translateY(-2px);
.mobile-menu-btn:hover { }
background-color: var(--bg-card);
} .mobile-menu-btn {
display: none;
.mobile-menu { background-color: transparent;
position: absolute; border: none;
top: 100%; color: var(--text-color);
left: 0; cursor: pointer;
right: 0; padding: 0.5rem;
background-color: var(--bg-color); border-radius: 6px;
padding: 1rem; transition: var(--transition);
display: none; }
box-shadow: var(--shadow-lg);
border-top: 1px solid var(--border-color); .mobile-menu-btn:hover {
animation: fadeIn 0.3s ease; background-color: var(--bg-card);
} }
@keyframes fadeIn { .mobile-menu {
from { position: absolute;
opacity: 0; top: 100%;
transform: translateY(-10px); left: 0;
} right: 0;
to { background-color: var(--bg-color);
opacity: 1; padding: 1rem;
transform: translateY(0); display: none;
} box-shadow: var(--shadow-lg);
} border-top: 1px solid var(--border-color);
animation: fadeIn 0.3s ease;
.mobile-nav-links { }
list-style: none;
padding: 0; @keyframes fadeIn {
margin: 0; from {
} opacity: 0;
transform: translateY(-10px);
.mobile-nav-links li { }
margin-bottom: 1rem; to {
padding-bottom: 1rem; opacity: 1;
border-bottom: 1px solid var(--border-color); transform: translateY(0);
} }
}
.mobile-nav-links li:last-child {
margin-bottom: 0; .mobile-nav-links {
padding-bottom: 0; list-style: none;
border-bottom: none; padding: 0;
} margin: 0;
}
.mobile-nav-links a {
color: var(--text-color); .mobile-nav-links li {
text-decoration: none; margin-bottom: 1rem;
display: block; padding-bottom: 1rem;
padding: 0.5rem 0; border-bottom: 1px solid var(--border-color);
font-weight: 500; }
transition: var(--transition);
} .mobile-nav-links li:last-child {
margin-bottom: 0;
.mobile-nav-links a:hover { padding-bottom: 0;
color: var(--primary-color); border-bottom: none;
padding-left: 5px; }
}
.mobile-nav-links a {
.mobile-language-btn { color: var(--text-color);
background-color: transparent; text-decoration: none;
color: var(--text-color); display: block;
border: 1px solid var(--border-color); padding: 0.5rem 0;
padding: 0.5rem 1rem; font-weight: 500;
cursor: pointer; transition: var(--transition);
width: 100%; }
border-radius: 6px;
font-weight: 500; .mobile-nav-links a:hover {
transition: var(--transition); color: var(--primary-color);
} padding-left: 5px;
}
.mobile-language-btn:hover {
background-color: var(--primary-color); .mobile-language-btn {
color: white; background-color: transparent;
border-color: var(--primary-color); color: var(--text-color);
} border: 1px solid var(--border-color);
padding: 0.5rem 1rem;
@media (max-width: 768px) { cursor: pointer;
.nav-links { width: 100%;
display: none; border-radius: 6px;
} font-weight: 500;
transition: var(--transition);
.language-switcher { }
display: none;
} .mobile-language-btn:hover {
background-color: var(--primary-color);
.mobile-menu-btn { color: white;
display: block; border-color: var(--primary-color);
} }
.mobile-menu { @media (max-width: 768px) {
display: block; .nav-links {
} display: none;
}
.navbar-container.scrolled {
padding: 0; .language-switcher {
} display: none;
}
.navbar-container{
padding: 0; .mobile-menu-btn {
} display: block;
} }
.mobile-menu {
display: block;
}
.navbar-container.scrolled {
padding: 0;
}
.navbar-container{
padding: 0;
}
}
</style> </style>

View File

@ -1,262 +1,264 @@
<template> <template>
<section id="about" class="about-section"> <section id="about" class="about-section">
<div class="container"> <div class="container">
<h2 class="section-title">{{ t('about.title') }}</h2> <h2 class="section-title">{{ t('about.title') }}</h2>
<div class="about-content"> <div class="about-content">
<p class="intro-text">{{ t('about.content') }}</p> <p class="intro-text">{{ t('about.content') }}</p>
<div class="mission-vision"> <div class="mission-vision">
<div class="mission"> <div class="mission">
<h3>{{ t('about.mission') }}</h3> <h3>{{ t('about.mission') }}</h3>
<p>{{ t('about.missionContent') }}</p> <p>{{ t('about.missionContent') }}</p>
</div> </div>
<div class="vision"> <div class="vision">
<h3>{{ t('about.vision') }}</h3> <h3>{{ t('about.vision') }}</h3>
<p>{{ t('about.visionContent') }}</p> <p>{{ t('about.visionContent') }}</p>
</div> </div>
</div> </div>
<div class="advantages"> <div class="advantages">
<h3>{{ t('about.advantages') }}</h3> <h3>{{ t('about.advantages') }}</h3>
<div class="advantages-grid"> <div class="advantages-grid">
<div class="advantage-card"> <div class="advantage-card">
<div class="advantage-icon"> <div class="advantage-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon> <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline> <polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline> <polyline points="2 12 12 17 22 12"></polyline>
</svg> </svg>
</div> </div>
<h4>{{ t('about.advantage1') }}</h4> <h4>{{ t('about.advantage1') }}</h4>
<p>Our team consists of highly skilled professionals with extensive experience in software development.</p> <p>{{ t('about.advantage_explanation1') }}</p>
</div> </div>
<div class="advantage-card"> <div class="advantage-card">
<div class="advantage-icon"> <div class="advantage-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle> <circle cx="12" cy="7" r="4"></circle>
</svg> </svg>
</div> </div>
<h4>{{ t('about.advantage2') }}</h4> <h4>{{ t('about.advantage2') }}</h4>
<p>We prioritize our clients' needs and work closely with them to achieve their business objectives.</p> <p>{{ t('about.advantage_explanation2') }}</p>
</div> </div>
<div class="advantage-card"> <div class="advantage-card">
<div class="advantage-icon"> <div class="advantage-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5z"></path> <path d="M12 2L2 7l10 5 10-5-10-5z"></path>
<path d="M2 17l10 5 10-5"></path> <path d="M2 17l10 5 10-5"></path>
<path d="M2 12l10 5 10-5"></path> <path d="M2 12l10 5 10-5"></path>
</svg> </svg>
</div> </div>
<h4>{{ t('about.advantage3') }}</h4> <h4>{{ t('about.advantage3') }}</h4>
<p>We constantly explore new technologies and methodologies to provide innovative solutions.</p> <p>{{ t('about.advantage_explanation3') }}</p>
</div> </div>
<div class="advantage-card"> <div class="advantage-card">
<div class="advantage-icon"> <div class="advantage-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect> <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path> <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg> </svg>
</div> </div>
<h4>{{ t('about.advantage4') }}</h4> <h4>{{ t('about.advantage4') }}</h4>
<p>We deliver projects on time and within budget, ensuring high quality and reliability.</p> <p>{{ t('about.advantage_explanation4') }}</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject } from 'vue' import { inject } from 'vue'
// import { useLanguageStore } from '../../store/language' // import { useLanguageStore } from '../../store/language'
// //
// const store = useLanguageStore() // const store = useLanguageStore()
// //
const t = inject<(key: string) => string>('t') || ((key) => key) const t = inject<(key: string) => string>('t') || ((key) => key)
</script> </script>
<style scoped> <style scoped>
.about-section { .about-section {
padding: 5rem 0; padding: 5rem 0;
background-color: var(--bg-color); background-color: var(--bg-color);
position: relative; position: relative;
} }
.container { .container {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 0 1.5rem; padding: 0 1.5rem;
} }
.section-title { .section-title {
text-align: center; text-align: center;
font-size: 2.5rem; font-size: 2.5rem;
margin-bottom: 3rem; margin-bottom: 3rem;
color: var(--text-color); color: var(--text-color);
position: relative; position: relative;
display: inline-block; display: inline-block;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
} }
.section-title::after { .section-title::after {
content: ''; content: '';
position: absolute; position: absolute;
bottom: -10px; bottom: -10px;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
width: 80px; width: 80px;
height: 4px; height: 4px;
background-color: var(--primary-color); background-color: var(--primary-color);
border-radius: 2px; border-radius: 2px;
} }
.about-content { .about-content {
max-width: 1000px; max-width: 1000px;
margin: 0 auto; margin: 0 auto;
} }
.intro-text { .intro-text {
font-size: 1.1rem; font-size: 1.1rem;
line-height: 1.8; line-height: 1.8;
margin-bottom: 3rem; margin-bottom: 3rem;
text-align: center; text-align: center;
color: var(--text-muted); color: var(--text-muted);
max-width: 800px; max-width: 800px;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
.mission-vision { .mission-vision {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-bottom: 4rem; margin-bottom: 4rem;
gap: 2rem; gap: 2rem;
} }
.mission, .vision { .mission, .vision {
flex: 1; flex: 1;
background-color: var(--bg-card); background-color: var(--bg-card);
padding: 2.5rem; padding: 2.5rem;
border-radius: 12px; border-radius: 12px;
box-shadow: var(--shadow); box-shadow: var(--shadow);
transition: var(--transition); transition: var(--transition);
} }
.mission:hover, .vision:hover { .mission:hover, .vision:hover {
transform: translateY(-5px); transform: translateY(-5px);
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
} }
.mission h3, .vision h3 { .mission h3, .vision h3 {
color: var(--text-color); color: var(--text-color);
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
font-size: 1.75rem; font-size: 1.75rem;
position: relative; position: relative;
display: inline-block; display: inline-block;
} }
.mission h3::after, .vision h3::after { .mission h3::after, .vision h3::after {
content: ''; content: '';
position: absolute; position: absolute;
bottom: -8px; bottom: -8px;
left: 0; left: 0;
width: 40px; width: 40px;
height: 3px; height: 3px;
background-color: var(--primary-color); background-color: var(--primary-color);
border-radius: 2px; border-radius: 2px;
} }
.mission p, .vision p { .mission p, .vision p {
color: var(--text-muted); color: var(--text-muted);
line-height: 1.7; line-height: 1.7;
} }
.advantages { .advantages {
margin-top: 4rem; margin-top: 4rem;
} }
.advantages h3 { .advantages h3 {
text-align: center; text-align: center;
color: var(--text-color); color: var(--text-color);
margin-bottom: 3rem; margin-bottom: 3rem;
font-size: 1.8rem; font-size: 1.8rem;
} }
.advantages-grid { .advantages-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 2.5rem; gap: 2.5rem;
} }
.advantage-card { .advantage-card {
background-color: var(--bg-card); background-color: var(--bg-card);
padding: 2.5rem; padding: 2.5rem;
border-radius: 12px; border-radius: 12px;
box-shadow: var(--shadow); box-shadow: var(--shadow);
text-align: center; text-align: center;
transition: var(--transition); transition: var(--transition);
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
.advantage-card:hover { .advantage-card:hover {
transform: translateY(-8px); transform: translateY(-8px);
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
} }
.advantage-card::before { .advantage-card::before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 5px; height: 5px;
background: linear-gradient(90deg, var(--primary-color), var(--primary-light)); background: linear-gradient(90deg, var(--primary-color), var(--primary-light));
} }
.advantage-icon { .advantage-icon {
color: var(--primary-color); color: var(--primary-color);
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
font-size: 1.5rem; font-size: 1.5rem;
transition: var(--transition); transition: var(--transition);
} }
.advantage-card:hover .advantage-icon { .advantage-card:hover .advantage-icon {
transform: scale(1.1); transform: scale(1.1);
} }
.advantage-card h4 { .advantage-card h4 {
color: var(--text-color); color: var(--text-color);
margin-bottom: 1rem; margin-bottom: 1rem;
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 600; font-weight: 600;
} }
.advantage-card p { .advantage-card p {
color: var(--text-muted); color: var(--text-muted);
line-height: 1.6; line-height: 1.6;
} text-align: left; /* 文本左对齐 */
margin: 0; /* 可选:移除默认外边距,使对齐更精确 */
@media (max-width: 768px) { }
.mission-vision {
flex-direction: column; @media (max-width: 768px) {
} .mission-vision {
flex-direction: column;
.section-title { }
font-size: 2rem;
} .section-title {
font-size: 2rem;
.mission, .vision { }
padding: 2rem;
} .mission, .vision {
padding: 2rem;
.advantages-grid { }
gap: 1.5rem;
} .advantages-grid {
} gap: 1.5rem;
}
}
</style> </style>

View File

@ -1,230 +1,234 @@
<template> <template>
<section id="projects" class="projects-section"> <section id="projects" class="projects-section">
<div class="container"> <div class="container">
<h2 class="section-title">{{ t('projects.title') }}</h2> <h2 class="section-title">{{ t('projects.title') }}</h2>
<div class="projects-grid"> <div class="projects-grid">
<div v-for="project in projects" :key="project.id" class="project-card"> <div v-for="project in projects" :key="project.id" class="project-card">
<div class="project-image"> <div class="project-image">
<img :src="project.image" alt="t(project.title)" /> <img :src="project.image" alt="t(project.title)" />
</div> </div>
<div class="project-info"> <div class="project-info">
<h3>{{ t(project.title) }}</h3> <h3>{{ t(project.title) }}</h3>
<p>{{ t(project.description) }}</p> <p>{{ t(project.description) }}</p>
<button class="view-details-btn" @click="openDetail(project)">{{ t('projects.viewDetails') }}</button> <button class="view-details-btn" @click="openDetail(project)">{{ t('projects.viewDetails') }}</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject } from 'vue' import { ref, inject } from 'vue'
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useLanguageStore } from '../../store/language'; import { useLanguageStore } from '../../store/language';
// //
const router = useRouter(); const router = useRouter();
const store = useLanguageStore(); const store = useLanguageStore();
const openDetail = (project: Project) => { const openDetail = (project: Project) => {
if (project.detailLink) { if (project.detailLink) {
// detailLink // detailLink
window.open(project.detailLink, '_blank'); window.open(project.detailLink, '_blank');
} else if (project.detailPageKey) { } else if (project.detailPageKey) {
// detailPageKey // detailPageKey
const currentLang = store.currentLanguage; // const currentLang = store.currentLanguage; //
console.log('当前语言:', currentLang); // 'zh' 'jp' //console.log(':', currentLang); // 'zh' 'jp'
// //
const routeName = currentLang === 'zh' const routeName = currentLang === 'zh'
? `${project.detailPageKey}Detail` ? `${project.detailPageKey}Detail`
: `${project.detailPageKey}DetailJp`; : `${project.detailPageKey}DetailJp`;
console.log('生成的路由名称:', routeName); // //console.log(':', routeName); //
// //
const routeExists = router.getRoutes().some(route => route.name === routeName); //const routeExists = router.getRoutes().some(route => route.name === routeName);
console.log('路由是否存在:', routeExists); //console.log(':', routeExists);
// ,push
//router.push({ name: routeName }); // 1
const url = router.resolve({ name: routeName }).href;
// window.open(url, '_blank');
const url = router.resolve({ name: routeName }).href;
const fullUrl = window.location.origin + url; // // 2window.open
console.log('完整URL:', fullUrl); // http://localhost:5173/project3/zh //router.push({
window.open(url, '_blank'); //name: routeName,
// ID
} // params: { id: project.id }
}; // });
}
};
export interface Project {
id: number
title: string
description: string
image: string export interface Project {
detailLink?: string id: number
details: string title: string
detailPageKey?: string // description: string
} image: string
detailLink?: string
// src/assets details: string
// 1@src* detailPageKey?: string //
// 2{ eager: true } }
const imageModules = import.meta.glob('../../assets/project*.png', { eager: true })
// src/assets
// { ID: } // 1@src*
const imageMap: Record<number, string> = {} // 2{ eager: true }
for (const path in imageModules) { const imageModules = import.meta.glob('../../assets/project*.png', { eager: true })
// ID project1.pngproject2.png...
const match = path.match(/project(\d+)\.png/) // { ID: }
if (match) { const imageMap: Record<number, string> = {}
const id = Number(match[1]) for (const path in imageModules) {
// Vite default // ID project1.pngproject2.png...
imageMap[id] = (imageModules[path] as { default: string }).default const match = path.match(/project(\d+)\.png/)
} if (match) {
} const id = Number(match[1])
// Vite default
// imageMap[id] = (imageModules[path] as { default: string }).default
const projects = ref<Project[]>([ }
{ }
id: 1,
title: "projects.project1.title", //
description: "projects.project1.description", const projects = ref<Project[]>([
image: imageMap[1], // ID1 {
detailLink: "https://www.jal.co.jp/jp/ja/?city=TYO", // 1 id: 1,
details: 'This project involved developing a full-featured e-commerce platform with payment integration, inventory management, and customer relationship management.', title: "projects.project1.title",
}, description: "projects.project1.description",
{ image: imageMap[1], // ID1
id: 2, detailLink: "https://www.jal.co.jp/jp/ja/?city=TYO", // 1
title: "projects.project2.title", details: 'This project involved developing a full-featured e-commerce platform with payment integration, inventory management, and customer relationship management.',
description: "projects.project2.description", },
image: imageMap[2], // ID2 {
detailLink: "https://agmiru.com/", // 2 id: 2,
details: 'We developed a secure mobile banking app with features like account management, fund transfers, bill payments, and financial analytics.', title: "projects.project2.title",
}, description: "projects.project2.description",
{ image: imageMap[2], // ID2
id: 3, detailLink: "https://agmiru.com/", // 2
title: "projects.project3.title", details: 'We developed a secure mobile banking app with features like account management, fund transfers, bill payments, and financial analytics.',
description: "projects.project3.description", },
image: imageMap[3], // ID3 {
detailPageKey: "project3", // 3 id: 3,
details: 'This project involved creating a healthcare management system that streamlines patient registration, appointment scheduling, medical records management, and billing.', title: "projects.project3.title",
}, description: "projects.project3.description",
{ image: imageMap[3], // ID3
id: 4, detailPageKey: "project3", // 3
title: "projects.project4.title", details: 'This project involved creating a healthcare management system that streamlines patient registration, appointment scheduling, medical records management, and billing.',
description: "projects.project4.description", },
image: imageMap[4], // ID4 {
detailPageKey: "project4", // 4 id: 4,
details: 'We developed an ERP system that integrates various business functions including finance, human resources, supply chain, and customer relationship management.', title: "projects.project4.title",
}, description: "projects.project4.description",
{ image: imageMap[4], // ID4
id: 5, detailPageKey: "project4", // 4
title: "projects.project5.title", details: 'We developed an ERP system that integrates various business functions including finance, human resources, supply chain, and customer relationship management.',
description: "projects.project5.description", },
image: imageMap[5], // ID5 {
detailLink: "https://maps.gsi.go.jp/#5/36.104611/140.084556/&base=std&ls=std&disp=1&vs=c1g1j0h0k0l0u0t0z0r0s0m0f1", // 5 id: 5,
details: 'We developed an ERP system that integrates various business functions including finance, human resources, supply chain, and customer relationship management.', title: "projects.project5.title",
} description: "projects.project5.description",
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.',
// }
const t = inject<(key: string) => string>('t') || ((key) => key)
</script> ])
<style scoped> //
.projects-section { const t = inject<(key: string) => string>('t') || ((key) => key)
padding: 5rem 0; </script>
background-color: #f8f9fa;
} <style scoped>
.projects-section {
.container { padding: 5rem 0;
max-width: 1200px; background-color: #f8f9fa;
margin: 0 auto; }
padding: 0 1.5rem;
} .container {
max-width: 1200px;
.section-title { margin: 0 auto;
text-align: center; padding: 0 1.5rem;
font-size: 2.5rem; }
margin-bottom: 3rem;
color: #1a1a2e; .section-title {
} text-align: center;
font-size: 2.5rem;
.projects-grid { margin-bottom: 3rem;
display: grid; color: #1a1a2e;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
gap: 2rem;
} .projects-grid {
display: grid;
.project-card { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
background-color: white; gap: 2rem;
border-radius: 8px; }
overflow: hidden;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); .project-card {
transition: transform 0.3s; background-color: white;
} border-radius: 8px;
overflow: hidden;
.project-card:hover { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transform: translateY(-5px); transition: transform 0.3s;
} }
.project-image { .project-card:hover {
width: 100%; transform: translateY(-5px);
height: 200px; }
overflow: hidden;
} .project-image {
width: 100%;
.project-image img { height: 200px;
width: 100%; overflow: hidden;
height: 100%; }
object-fit: cover;
transition: transform 0.3s; .project-image img {
} width: 100%;
height: 100%;
.project-card:hover .project-image img { object-fit: cover;
transform: scale(1.05); transition: transform 0.3s;
} }
.project-info { .project-card:hover .project-image img {
padding: 1.5rem; transform: scale(1.05);
} }
.project-info h3 { .project-info {
color: #1a1a2e; padding: 1.5rem;
margin-bottom: 1rem; }
font-size: 1.5rem;
} .project-info h3 {
color: #1a1a2e;
.project-info p { margin-bottom: 1rem;
color: #666; font-size: 1.5rem;
line-height: 1.6; }
margin-bottom: 1.5rem;
text-align: left; /* 添加此属性,强制内容左对齐 */ .project-info p {
} color: #666;
line-height: 1.6;
.view-details-btn { margin-bottom: 1.5rem;
background-color: #4cc9f0; text-align: left; /* 添加此属性,强制内容左对齐 */
color: white; }
border: none;
padding: 0.8rem 1.5rem; .view-details-btn {
border-radius: 4px; background-color: #4cc9f0;
cursor: pointer; color: white;
transition: background-color 0.3s; border: none;
} padding: 0.8rem 1.5rem;
border-radius: 4px;
.view-details-btn:hover { cursor: pointer;
background-color: #4361ee; transition: background-color 0.3s;
} }
@media (max-width: 768px) { .view-details-btn:hover {
.section-title { background-color: #4361ee;
font-size: 2rem; }
}
} @media (max-width: 768px) {
.section-title {
font-size: 2rem;
}
}
</style> </style>

View File

@ -1,188 +1,188 @@
<template> <template>
<section id="timeline" class="timeline-section"> <section id="timeline" class="timeline-section">
<div class="container"> <div class="container">
<h2 class="section-title">{{ t('timeline.title') }}</h2> <h2 class="section-title">{{ t('timeline.title') }}</h2>
<div class="timeline"> <div class="timeline">
<div v-for="(event, index) in timelineEvents" :key="event.id" class="timeline-item" :class="{ 'timeline-item-right': index % 2 === 1 }"> <div v-for="(timelineEvent,index) in timelineEvents" :key="timelineEvent.id" class="timeline-item" :class="{ 'timeline-item-right': index % 2 === 1 }">
<div class="timeline-content"> <div class="timeline-content">
<div class="timeline-date">{{ event.date }}</div> <div class="timeline-date">{{ t(timelineEvent.date) }}</div>
<h3>{{ event.title }}</h3> <h3>{{ t(timelineEvent.title) }}</h3>
<p>{{ event.description }}</p> <p>{{ t(timelineEvent.description) }}</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, inject } from 'vue' import { ref, inject } from 'vue'
export interface TimelineEvent { export interface TimelineEvent {
id: number id: number
date: string date: string
title: string title: string
description: string description: string
} }
// 线 // 线
const timelineEvents = ref<TimelineEvent[]>([ const timelineEvents = ref<TimelineEvent[]>([
{ {
id: 1, id: 1,
date: '2015', date: '2022',
title: 'Company Founded', title: "timelineEvents.timelineEvent1.title",
description: 'Our company was founded with a vision to provide innovative software solutions.', description: "timelineEvents.timelineEvent1.description",
}, },
{ {
id: 2, id: 2,
date: '2016', date: '2022',
title: 'First Project', title: "timelineEvents.timelineEvent2.title",
description: 'We successfully completed our first major project for a leading client.', description: "timelineEvents.timelineEvent2.description",
}, },
{ {
id: 3, id: 3,
date: '2018', date: '2023',
title: 'Team Expansion', title: "timelineEvents.timelineEvent3.title",
description: 'Our team grew to 20 employees with expertise in various technologies.', description: "timelineEvents.timelineEvent3.description",
}, },
{ {
id: 4, id: 4,
date: '2020', date: '2024',
title: 'Product Launch', title: "timelineEvents.timelineEvent4.title",
description: 'We launched our first proprietary software product.', description: "timelineEvents.timelineEvent4.description",
}, },
{ {
id: 5, id: 5,
date: '2022', date: '2025',
title: 'International Expansion', title: "timelineEvents.timelineEvent5.title",
description: 'We expanded our operations to serve clients worldwide.', description: "timelineEvents.timelineEvent5.description",
}, },
{ {
id: 6, id: 6,
date: '2023', date: '2025',
title: 'Industry Recognition', title: "timelineEvents.timelineEvent6.title",
description: 'Our company received multiple awards for excellence in software development.', description: "timelineEvents.timelineEvent6.description",
}, },
]) ])
// //
const t = inject<(key: string) => string>('t') || ((key) => key) const t = inject<(key: string) => string>('t') || ((key) => key)
</script> </script>
<style scoped> <style scoped>
.timeline-section { .timeline-section {
padding: 5rem 0; padding: 5rem 0;
background-color: #f8f9fa; background-color: #f8f9fa;
} }
.container { .container {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 0 1.5rem; padding: 0 1.5rem;
} }
.section-title { .section-title {
text-align: center; text-align: center;
font-size: 2.5rem; font-size: 2.5rem;
margin-bottom: 3rem; margin-bottom: 3rem;
color: #1a1a2e; color: #1a1a2e;
} }
.timeline { .timeline {
position: relative; position: relative;
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
} }
.timeline::after { .timeline::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 6px; width: 6px;
background-color: #4cc9f0; background-color: #4cc9f0;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 50%; left: 50%;
margin-left: -3px; margin-left: -3px;
} }
.timeline-item { .timeline-item {
padding: 10px 40px; padding: 10px 40px;
position: relative; position: relative;
width: 50%; width: 50%;
box-sizing: border-box; box-sizing: border-box;
} }
.timeline-item-right { .timeline-item-right {
left: 50%; left: 50%;
} }
.timeline-content { .timeline-content {
padding: 20px 30px; padding: 20px 30px;
background-color: white; background-color: white;
position: relative; position: relative;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
} }
.timeline-date { .timeline-date {
color: #4cc9f0; color: #4cc9f0;
font-weight: bold; font-weight: bold;
margin-bottom: 10px; margin-bottom: 10px;
} }
.timeline-content h3 { .timeline-content h3 {
color: #1a1a2e; color: #1a1a2e;
margin-bottom: 10px; margin-bottom: 10px;
} }
.timeline-content p { .timeline-content p {
color: #666; color: #666;
line-height: 1.6; line-height: 1.6;
} }
/* 时间线节点样式 */ /* 时间线节点样式 */
.timeline-item::after { .timeline-item::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 25px; width: 25px;
height: 25px; height: 25px;
background-color: white; background-color: white;
border: 4px solid #4cc9f0; border: 4px solid #4cc9f0;
top: 15px; top: 15px;
border-radius: 50%; border-radius: 50%;
z-index: 1; z-index: 1;
} }
.timeline-item-right::after { .timeline-item-right::after {
left: -17px; left: -17px;
} }
.timeline-item::after { .timeline-item::after {
right: -16px; right: -16px;
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.section-title { .section-title {
font-size: 2rem; font-size: 2rem;
} }
.timeline::after { .timeline::after {
left: 31px; left: 31px;
} }
.timeline-item { .timeline-item {
width: 100%; width: 100%;
padding-left: 70px; padding-left: 70px;
padding-right: 25px; padding-right: 25px;
} }
.timeline-item-right { .timeline-item-right {
left: 0; left: 0;
} }
.timeline-item::after, .timeline-item::after,
.timeline-item-right::after { .timeline-item-right::after {
left: 15px; left: 15px;
} }
} }
</style> </style>

View File

@ -1,91 +1,122 @@
export default { export default {
nav: { nav: {
home: 'ホーム', name:'優閲スタジオ',
about: '会社概要', home: 'ホーム',
team: 'チーム紹介', about: '私たちについて',
projects: 'プロジェクト', team: 'メンバー',
contact: 'お問い合わせ', projects: '開発実績',
}, contact: 'お問い合わせ',
about: { },
title: '会社概要', about: {
mission: '私たちの使命', title: '私たちについて',
vision: '私たちのビジョン', mission: 'チーム理念',
advantages: '私たちの強み', vision: 'ビジョン',
content: '私たちは、お客様に高品質なソリューションを提供することに専念するプロフェッショナルなソフトウェア開発会社です。', advantages: '私たちの強み',
missionContent: 'ビジネスの成長とデジタル変革を推進する革新的な技術ソリューションを提供します。', content: '私たちは、ソフトウェア開発をはじめ、翻訳・BPOなどの業務を手がける専門サービスチームです',
visionContent: '技術的卓越性と顧客満足度で認められる、世界をリードするソフトウェア開発サービスプロバイダーになること。', missionContent: '「お客様のビジネス成長とデジタル変革を実現するために、革新的な技術ソリューションを創造します」',
advantage1: '技術的卓越性', visionContent: '「小さくとも優れた技術チームとして、技術の匠心でお客様の成功を支えます」',
advantage2: '顧客中心のアプローチ', advantage1: '低コスト',
advantage3: '革新', advantage2: '迅速な判断',
advantage4: '信頼性', advantage3: '柔軟な対応',
}, advantage4: '実績と信頼',
team: { advantage_explanation1:'大手企業のように固定費(高額な賃料・管理部門人件費・ブランド広告費など)の負担がありません。このコスト優位性を最大限に活かし、業界でも類を見ない低価格水準を実現しております。',
title: 'チーム紹介', advantage_explanation2:'小規模なチーム体制のため、複雑な稟議・承認プロセスが一切ありません。責任者や技術責任者などの中核メンバーが直接迅速に判断するため、お客様のご要望に素早く応えます。',
memberRole: '役職', advantage_explanation3:'小規模な個人のお客様から大規模な法人案件まで、あらゆるデータ処理に対応できるプロフェッショナルです。小ロットから大量発注、緊急のご依頼まで、状況に応じて臨機応変に対応いたします。',
memberBio: 'プロフィール', advantage_explanation4:'大手企業から官公庁、個人事業主の方まで、多岐にわたるお取引実績がございます。特に金融・保険・製造・商社・物流など多様な業界のお客様から厚い信頼をいただいております。',
member1: {name: "陳 迪",role: "スタジオ代表", },
bio:`日本での留学及び職務経験があります。秋田大学・名古屋大学大学院に学び、卒業後は日本の大手商社に入社し、国際的なビジネス環境の中で team: {
BPO title: 'メンバー',
SEBSEPM memberRole: '役職',
Web `}, memberBio: 'プロフィール',
member2: {name: "梁 偉",role: "技術統括責任者", member1: {name: "陳 迪",role: "スタジオ代表",
bio:`10 年以上の Web 開発経験を持ち、長年にわたり対日プロジェクトに専念しています。フロントエンドの Vue、React、JavaScript 及び HTML5、 bio:`日本での留学及び職務経験があります。秋田大学・名古屋大学大学院に学び、卒業後は日本の大手商社に入社し、国際的なビジネス環境の中で
JavaPython Spring BootDjango BPO
ECサイト SEBSEPM
`}, Web `},
member3: {name: "趙元博",role: "開発エンジニア", member2: {name: "梁 偉",role: "技術統括責任者",
bio:`8 年以上の Web 開発経験を持ち、長年にわたり対日プロジェクトのバックエンド開発を専門としてきました。。Java、PHP、Python、Node.js などのバックエンド bio:`10 年以上の Web 開発経験を持ち、長年にわたり対日プロジェクトに専念しています。フロントエンドの Vue、React、JavaScript 及び HTML5、
Spring BootDjangoExpress 使 JavaPython Spring BootDjango
EC 調 MOM API開発 ECサイト
`}, `},
member4: {name: "張世超",role: "開発エンジニア", member3: {name: "趙元博",role: "開発エンジニア",
bio:`長年にわたり Web フロントエンド開発に深く携わり、対日プロジェクトを専門として参画してきました。H5、CSS3、Flex を駆使した画面実装から、jQuery と JS を組み合わせた動的処理開発までを得意とし、 bio:`8 年以上の Web 開発経験を持ち、長年にわたり対日プロジェクトのバックエンド開発を専門としてきました。。Java、PHP、Python、Node.js などのバックエンド
TypeScriptEs6 node.js Vue2.0/Vue3.0 + ElementUI Spring BootDjangoExpress 使
Flutter使用UIコンポーネントライブラリの活用やSVN/Gitによるバージョン管理を徹底することで`}, EC 調 MOM API開発
member5: {name: "張志華",role: "開発エンジニア", `},
bio:`長年のWebフルスタック開発経験を持ち、一貫して対日プロジェクトに従事してきました。フロントエンド領域では H5、CSS3、Flex レイアウトを基盤とした堅実な画面実装、jQueryからTypeScript、Es6、node.jsまで幅広く対応、 member4: {name: "張世超",role: "開発エンジニア",
VueReactAngular UIライブラリの実務経験が豊富です bio:`長年にわたり Web フロントエンド開発に深く携わり、対日プロジェクトを専門として参画してきました。H5、CSS3、Flex を駆使した画面実装から、jQuery と JS を組み合わせた動的処理開発までを得意とし、
JavaPython Spring BootDjango SVNGit TypeScriptEs6 node.js Vue2.0/Vue3.0 + ElementUI
`}, Flutter使用UIコンポーネントライブラリの活用やSVN/Gitによるバージョン管理を徹底することで`},
}, member5: {name: "張志華",role: "開発エンジニア",
bio:`長年のWebフルスタック開発経験を持ち、一貫して対日プロジェクトに従事してきました。フロントエンド領域では H5、CSS3、Flex レイアウトを基盤とした堅実な画面実装、jQueryからTypeScript、Es6、node.jsまで幅広く対応、
projects: { VueReactAngular UIライブラリの実務経験が豊富です
title: 'プロジェクト', JavaPython Spring BootDjango SVNGit
viewDetails: '詳細を見る', `},
project1: { },
title: "航空券管理システム",
description: "当システムは、フライト情報の照会、座席予約、オンライン決済、電子チケット管理および変更・払い戻し機能を統合しており、航空会社、旅行代理店および旅行者に効率的で便利なワンストップの航空券サービスを提供します。これにより、航空券販売および管理の自動化と情報化を実現し、業務運営の効率とユーザー体験を向上させます。", projects: {
}, title: '実績概要',
project2: { viewDetails: '詳細を見る',
title: "農作物管理・買取システム", project1: {
description: "本システムは農家と仕入れ業者を結びつけ、農産物の管理、天気予報、病害虫管理、情報発信、オンライン商談、注文管理、品質追跡および電子決済などのサービスを提供します。情報の壁を打破し、取引プロセスを最適化することで、農産物の円滑な流通を促進し、農業の生産性向上と農家の収入増加を支援します。", title: "航空券管理システム",
}, description: "当システムは、フライト情報の照会、座席予約、オンライン決済、電子チケット管理および変更・払い戻し機能を統合しており、航空会社、旅行代理店および旅行者に効率的で便利なワンストップの航空券サービスを提供します。これにより、航空券販売および管理の自動化と情報化を実現し、業務運営の効率とユーザー体験を向上させます。",
project3: { },
title: "勤怠管理システム", project2: {
description: "当システムは、勤怠管理端末やモバイル端末など複数の方法で従業員の出退勤時間、休暇、残業などの情報を記録し、勤怠データを自動的に集計・分析して勤怠レポートを生成します。これにより、人事管理プロセスを簡素化し、勤怠の正確性と公正性を確保し、給与計算および業績評価に信頼性の高い根拠を提供します。", title: "農作物管理・買取システム",
}, description: "本システムは農家と仕入れ業者を結びつけ、農産物の管理、天気予報、病害虫管理、情報発信、オンライン商談、注文管理、品質追跡および電子決済などのサービスを提供します。情報の壁を打破し、取引プロセスを最適化することで、農産物の円滑な流通を促進し、農業の生産性向上と農家の収入増加を支援します。",
project4: { },
title: "工業生産管理システム", project3: {
description: "当システムは、マーケティング管理、生産計画、資材管理、工程管理、設備監視および品質管理などの各工程を統合し、生産プロセスの可視化と細やかな管理を実現します。リソースの最適な配分を図り、生産効率と製品品質を向上させ、運営コストを削減することで、企業のスマート化進展を推進します。", title: "勤怠管理システム",
}, description: "当システムは、勤怠管理端末やモバイル端末など複数の方法で従業員の出退勤時間、休暇、残業などの情報を記録し、勤怠データを自動的に集計・分析して勤怠レポートを生成します。これにより、人事管理プロセスを簡素化し、勤怠の正確性と公正性を確保し、給与計算および業績評価に信頼性の高い根拠を提供します。",
project5: { },
title: "地図拡張システム", project4: {
description: "本システムは、プロフェッショナル向けに設計された地図拡張ツールです。利用者は地図の閲覧や情報検索だけでなく、多彩な操作を地図上で実行可能。特定エリアやルートのマーキング機能に加え、2地点間の正確な距離測定や指定領域の面積計算も可能です。さらに強力な比較機能を搭載し、専門家の業務をサポートする高精度なデータを提供します。", title: "工業生産管理システム",
}, description: "当システムは、国のDX推進に応じて開発されたもので、マーケティング管理、生産計画、資材管理、工程管理、設備監視および品質管理などの各工程を統合し、生産プロセスの可視化と細やかな管理を実現します。リソースの最適な配分を図り、生産効率と製品品質を向上させ、運営コストを削減することで、企業のスマート化進展を推進します。",
}, },
contact: { project5: {
title: 'お問い合わせ', title: "地図拡張システム",
name: 'お名前', description: "本システムは、プロフェッショナル向けに設計された地図拡張ツールです。利用者は地図の閲覧や情報検索だけでなく、多彩な操作を地図上で実行可能。特定エリアやルートのマーキング機能に加え、2地点間の正確な距離測定や指定領域の面積計算も可能です。さらに強力な比較機能を搭載し、専門家の業務をサポートする高精度なデータを提供します。",
email: 'メールアドレス', },
subject: '件名', },
message: 'メッセージ', timelineEvents: {
send: '送信', timelineEvent1: {
success: 'メッセージが正常に送信されました!', title: "スタジオ設立",
error: 'メッセージの送信に失敗しました。もう一度お試しください。', description: "",
}, },
timeline: { timelineEvent2: {
title: '会社の沿革', title: "航空券管理システム",
}, description: "初の日本案件(一部)受注",
},
timelineEvent3: {
title: "地図拡張システム",
description: "大型案件(一部)参画",
},
timelineEvent4: {
title: "農作物管理・買取システム",
description: "機能開発・保守",
},
timelineEvent5: {
title: "勤怠管理システム",
description: "機能開発・保守",
},
timelineEvent6: {
title: "工業生産管理システム",
description: "DX推進、独立開発開発中",
},
},
contact: {
title: 'お問い合わせ',
name: 'お名前',
email: 'メールアドレス',
subject: '件名',
message: 'メッセージ',
send: '送信',
success: 'メッセージが正常に送信されました!',
error: 'メッセージの送信に失敗しました。もう一度お試しください。',
},
timeline: {
title: 'タイムライン',
},
} }

View File

@ -1,86 +1,116 @@
export default { export default {
nav: { nav: {
home: '首页', name:'优阅工作室',
about: '关于我们', home: '首页',
team: '团队介绍', about: '关于我们',
projects: '成功案例', team: '团队介绍',
contact: '联系我们', projects: '成功案例',
}, contact: '联系我们',
about: { },
title: '关于我们', about: {
mission: '我们的使命', title: '关于我们',
vision: '我们的愿景', mission: '团队理念',
advantages: '我们的优势', vision: '我们的愿景',
content: '我们是一家专业的软件开发团队,致力于为客户提供高质量的解决方案。', advantages: '我们的优势',
missionContent: '提供创新的技术解决方案,推动业务增长和数字化转型。', content: '我们是一家从事软件开发以及翻译、BPO等业务的专业服务团队',
visionContent: '成为全球领先的软件开发服务提供商,以技术卓越和客户满意度著称。', missionContent: '用创新技术,助力客户实现业务增长与数字化转型。',
advantage1: '技术卓越', visionContent: '做小而美的技术团队,以技术匠心成就客户成功。',
advantage2: '以客户为中心', advantage1: '低成本',
advantage3: '创新精神', advantage2: '快速决策',
advantage4: '可靠性', advantage3: '灵活应对多样化需求',
}, advantage4: '丰富的业界经验',
team: { advantage_explanation1:'工作室无大型企业的 “固定成本包袱”(如高额房租、行政人员薪资、品牌营销费用等),可以充分发挥工作室运营的成本优势,实现行业的低价格水平。',
title: '我们的团队', advantage_explanation2:'得益于小规模团队架构,我们完全无需复杂的层层汇报与审批流程。由负责人及技术主管等核心成员直接迅速做出判断,及时响应您的各类需求。',
memberRole: '职位', advantage_explanation3:'由专业人士组成的团队,能够处理从个人小规模项目到企业大规模项目在内的各种数据处理业务。无论小批量、大批量还是紧急订单,我们都能灵活应对。',
memberBio: '简介', advantage_explanation4:'我们拥有广泛的合作经验,客户涵盖大型企业、政府机关及个人经营者。尤其深受金融,保险,生产加工、贸易公司、物流等多行业客户的信赖。',
member1: { },
name: "陈迪",role: "工作室总负责人", team: {
bio:`拥有日本留学与职业背景:先后就读于秋田大学及名古屋大学大学院,毕业后入职日本大型商社,在国际化商业环境中积累了宝贵的实战经验, title: '我们的团队',
BPO memberRole: '职位',
SEBSE及 PM Web memberBio: '简介',
`}, member1: {
member2: {name: "梁伟",role: "技术总负责人", name: "陈迪",role: "工作室总负责人",
bio:`拥有 10 年以上 web 开发经验,长期专注对日项目。精通前端 Vue、React、JavaScript 及 HTML5后端 Java、Python 及 Spring Boot、 bio:`先后就读于秋田大学及名古屋大学大学院,毕业后入职日本大型商社,在国际化商业环境中积累了宝贵的实战经验,
Django BPO
`}, SEBSE及 PM Web `},
member3: {name: "赵元博",role: "技术开发者", member2: {name: "梁伟",role: "技术总负责人",
bio:`拥有 8年以上 web 开发经验,长期深耕对日项目后端开发。精通 Java、PHPPython、Node.js 等后端语言,熟练运用 Spring Boot、 bio:`拥有 10 年以上 web 开发经验,长期专注对日项目。精通前端 Vue、React、JavaScript 及 HTML5后端 Java、Python 及 Spring Boot、
DjangoExpress MOM系统等项目的后端架构搭建 Django
`}, `},
member4: {name: "张世超",role: "技术开发者", member3: {name: "赵元博",role: "技术开发者",
bio:`深耕 web 前端开发多年,长期参与对日项目。精通 H5、CSS3、Flex 布局,熟练运用 jQuery 与 JS 配合开发,深谙 TypeScript、Es6 及 node.js。 bio:`拥有 8年以上 web 开发经验,长期深耕对日项目后端开发。精通 Java、PHPPython、Node.js 等后端语言,熟练运用 Spring Boot、
使 Vue2.0~/Vue3.0~+ ElementUI app Flutter UI SVNGit DjangoExpress MOM系统等项目的后端架构搭建
`}, `},
member5: {name: "张志华",role: "技术开发者", member4: {name: "张世超",role: "技术开发者",
bio:`多年 web 全栈开发经验,长期投身对日项目。前端精通 H5、CSS3、Flex 布局,熟练运用 jQuery、TypeScript、Es6 及 node.js掌握 Vue、 bio:`深耕 web 前端开发多年,长期参与对日项目。精通 H5、CSS3、Flex 布局,熟练运用 jQuery 与 JS 配合开发,深谙 TypeScript、Es6 及 node.js。
ReactAngular UI JavaPython Spring BootDjango SVNGit 使 Vue2.0~/Vue3.0~+ ElementUI app Flutter UI SVNGit
`}, `},
}, member5: {name: "张志华",role: "技术开发者",
projects: { bio:`多年 web 全栈开发经验,长期投身对日项目。前端精通 H5、CSS3、Flex 布局,熟练运用 jQuery、TypeScript、Es6 及 node.js掌握 Vue、
title: '成功案例', ReactAngular UI JavaPython Spring BootDjango SVNGit
viewDetails: '查看详情', `},
project1: { },
title: "机票管理系统", projects: {
description: "该系统集成了航班信息查询、座位预订、在线支付、电子客票管理及退改签功能,为航空公司、旅行社和旅客提供高效、便捷的一站式票务服务,实现机票销售与管理的自动化和信息化,提升运营效率与用户体验。", title: '成功案例',
}, viewDetails: '查看详情',
project2: { project1: {
title: "农作物交易系统", title: "机票管理系统",
description: "本系统连接农户与采购商,提供农产品管理,天气预报,病虫害管理,信息发布、在线洽谈、订单管理、质量追溯与电子结算等服务,打破信息壁垒,优化交易流程,促进农产品高效流通,助力农业增效、农户增收。", description: "该系统集成了航班信息查询、座位预订、在线支付、电子客票管理及退改签功能,为航空公司、旅行社和旅客提供高效、便捷的一站式票务服务,实现机票销售与管理的自动化和信息化,提升运营效率与用户体验。",
}, },
project3: { project2: {
title: "出勤管理系统", title: "农作物交易系统",
description: "系统通过考勤机、移动端等多方式记录员工上下班时间、请假、加班等信息,自动统计分析出勤数据,生成考勤报表,简化人事管理流程,确保考勤准确公正,为薪资计算和绩效考核提供可靠依据。", description: "本系统连接农户与采购商,提供农产品管理,天气预报,病虫害管理,信息发布、在线洽谈、订单管理、质量追溯与电子结算等服务,打破信息壁垒,优化交易流程,促进农产品高效流通,助力农业增效、农户增收。",
}, },
project4: { project3: {
title: "工业生产管理系统", title: "考勤管理系统",
description: "本系统是一款专业的生产加工行业的数字化系统,整合营销管理,生产计划、物料管理、工艺流程、设备监控与质量控制等环节,实现生产过程的可视化、精细化管理,优化资源配置,提高生产效率与产品质量,降低运营成本,推动企业智能化升级。", description: "系统通过考勤机、移动端等多方式记录员工上下班时间、请假、加班等信息,自动统计分析出勤数据,生成考勤报表,简化人事管理流程,确保考勤准确公正,为薪资计算和绩效考核提供可靠依据。",
}, },
project5: { project4: {
title: "地图扩展系统", title: "工业生产管理系统",
description: "本系统是为专业人士打造的地图扩展工具。操作者不仅能进行地图阅览与信息查询,还可在地图上开展丰富操作;支持对特定区域、线路等进行标记,能够精准测量地图上任意两点间的距离以及特定区域的面积;同时具备强大的对比功能,为专业人士提供精确数据支撑。", description: "本系统是一款为响应国家数字化转型战略而打造的工业数字化系统,整合营销管理,生产计划、物料管理、工艺流程、设备监控与质量控制等环节,实现生产过程的可视化、精细化管理,优化资源配置,提高生产效率与产品质量,降低运营成本,推动企业智能化升级。",
}, },
}, project5: {
contact: { title: "地图扩展系统",
title: '联系我们', description: "本系统是为专业人士打造的地图扩展工具。操作者不仅能进行地图阅览与信息查询,还可在地图上开展丰富操作;支持对特定区域、线路等进行标记,能够精准测量地图上任意两点间的距离以及特定区域的面积;同时具备强大的对比功能,为专业人士提供精确数据支撑。",
name: '您的姓名', },
email: '您的邮箱', },
subject: '主题', timelineEvents: {
message: '您的留言', timelineEvent1: {
send: '发送留言', title: "工作室成立",
success: '留言发送成功!', description: "",
error: '发送留言失败,请重试。', },
}, timelineEvent2: {
timeline: { title: "机票管理系统",
title: '公司历程', description: "首个对日项目(一部分)参与",
}, },
timelineEvent3: {
title: "地图扩展系统",
description: "大型项目(一部分)参与",
},
timelineEvent4: {
title: "农作物交易系统",
description: "功能开发和保守",
},
timelineEvent5: {
title: "考勤管理系统",
description: "功能开发和保守",
},
timelineEvent6: {
title: "工业生产管理系统",
description: "数字化转型项目,独立开发(进行中)",
},
},
contact: {
title: '联系我们',
name: '您的姓名',
email: '您的邮箱',
subject: '主题',
message: '您的留言',
send: '发送留言',
success: '留言发送成功!',
error: '发送留言失败,请重试。',
},
timeline: {
title: '项目经历',
},
} }

View File

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