123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- <template>
- <div class="careers-page bg-stone-950 min-h-screen">
- <div class="relative z-10">
- <!-- 顶部间距 -->
- <div class="w-full h-[55px] sm:h-[72px]"></div>
-
- <!-- 错误边界 -->
- <ErrorBoundary :error="pageError">
- <!-- 页面标题区域 -->
- <section class="hero-section relative overflow-hidden">
- <!-- 面包屑导航 -->
- <div
- class="max-w-full xl:px-2 lg:px-2 md:px-4 px-4 mt-6 mb-1 sm:mb-4"
- >
- <div class="max-w-screen-2xl mx-auto relative z-10">
- <nuxt-link
- :to="`${homepagePath}/`"
- class="justify-start text-white/60 text-base font-normal"
- >{{ t("common.breadcrumb.home") }}</nuxt-link
- >
- <span class="text-white/60 text-base font-normal px-2"> / </span>
- <span class="text-white text-base font-normal">{{
- t("common.careers")
- }}</span>
- </div>
- </div>
- <div class="w-full py-20 md:py-40">
- <!-- 图片背景 -->
- <div class="absolute inset-0 z-0">
- <img
- src="/assets/images/careersbg.webp"
- alt="Background"
- class="w-full h-full object-cover opacity-20"
- />
- </div>
-
- <div
- class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10"
- >
- <!-- 标题 -->
- <div class="text-center space-y-12">
- <h1
- class="text-white text-3xl sm:text-4xl md:text-6xl font-bold tracking-wider leading-tight"
- >
- <span
- class="bg-gradient-to-r from-white to-zinc-300 bg-clip-text text-transparent"
- >
- {{ t("careers.slogan") }}
- </span>
- </h1>
-
- <p
- class="text-zinc-300/80 text-base md:text-xl max-w-4xl mx-auto leading-relaxed"
- >
- {{ t("careers.subtitle") }}
- </p>
- </div>
- </div>
- </div>
- </section>
-
- <!-- 企业文化区域 -->
- <section class="culture-section">
- <div class="section-block w-full py-20 md:py-32 relative">
- <div
- class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10"
- >
- <div class="text-center mb-12 md:mb-20">
- <h3
- class="text-white text-2xl md:text-4xl font-bold mb-6 tracking-wider"
- >
- {{ t("careers.culture.title") }}
- </h3>
- <div class="w-20 h-px bg-indigo-400 mx-auto"></div>
- </div>
-
- <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
- <!-- 创新驱动 -->
- <div class="culture-card group">
- <div
- class="relative p-8 bg-zinc-800/30 backdrop-blur-sm border border-zinc-700/30 rounded-xl transition-all duration-700 hover:border-indigo-400/50 hover:bg-zinc-800/50 hover:shadow-2xl hover:shadow-indigo-500/10 hover:transform hover:scale-105"
- >
- <div
- class="absolute inset-0 bg-gradient-to-br from-indigo-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 rounded-xl"
- ></div>
- <div class="relative">
- <div
- class="w-16 h-16 bg-indigo-500/10 rounded-xl flex items-center justify-center mb-6 group-hover:bg-indigo-500/20 transition-all duration-500 group-hover:rotate-12 group-hover:scale-110"
- >
- <svg
- class="w-8 h-8 text-indigo-400"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M13 10V3L4 14h7v7l9-11h-7z"
- ></path>
- </svg>
- </div>
- <h4
- class="text-white text-xl font-semibold mb-4 group-hover:text-indigo-400 transition-colors duration-500"
- >
- {{ t("careers.culture.innovation.title") }}
- </h4>
- <p class="text-zinc-300/80 text-sm leading-relaxed">
- {{ t("careers.culture.innovation.description") }}
- </p>
- </div>
- </div>
- </div>
-
- <!-- 团队协作 -->
- <div class="culture-card group">
- <div
- class="relative p-8 bg-zinc-800/30 backdrop-blur-sm border border-zinc-700/30 rounded-xl transition-all duration-700 hover:border-indigo-400/50 hover:bg-zinc-800/50 hover:shadow-2xl hover:shadow-indigo-500/10 hover:transform hover:scale-105"
- >
- <div
- class="absolute inset-0 bg-gradient-to-br from-indigo-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 rounded-xl"
- ></div>
- <div class="relative">
- <div
- class="w-16 h-16 bg-indigo-500/10 rounded-xl flex items-center justify-center mb-6 group-hover:bg-indigo-500/20 transition-all duration-500 group-hover:rotate-12 group-hover:scale-110"
- >
- <svg
- class="w-8 h-8 text-indigo-400"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
- ></path>
- </svg>
- </div>
- <h4
- class="text-white text-xl font-semibold mb-4 group-hover:text-indigo-400 transition-colors duration-500"
- >
- {{ t("careers.culture.teamwork.title") }}
- </h4>
- <p class="text-zinc-300/80 text-sm leading-relaxed">
- {{ t("careers.culture.teamwork.description") }}
- </p>
- </div>
- </div>
- </div>
-
- <!-- 品质第一 -->
- <div class="culture-card group">
- <div
- class="relative p-8 bg-zinc-800/30 backdrop-blur-sm border border-zinc-700/30 rounded-xl transition-all duration-700 hover:border-indigo-400/50 hover:bg-zinc-800/50 hover:shadow-2xl hover:shadow-indigo-500/10 hover:transform hover:scale-105"
- >
- <div
- class="absolute inset-0 bg-gradient-to-br from-indigo-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 rounded-xl"
- ></div>
- <div class="relative">
- <div
- class="w-16 h-16 bg-indigo-500/10 rounded-xl flex items-center justify-center mb-6 group-hover:bg-indigo-500/20 transition-all duration-500 group-hover:rotate-12 group-hover:scale-110"
- >
- <svg
- class="w-8 h-8 text-indigo-400"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
- ></path>
- </svg>
- </div>
- <h4
- class="text-white text-xl font-semibold mb-4 group-hover:text-indigo-400 transition-colors duration-500"
- >
- {{ t("careers.culture.quality.title") }}
- </h4>
- <p class="text-zinc-300/80 text-sm leading-relaxed">
- {{ t("careers.culture.quality.description") }}
- </p>
- </div>
- </div>
- </div>
-
- <!-- 共同成长 -->
- <div class="culture-card group">
- <div
- class="relative p-8 bg-zinc-800/30 backdrop-blur-sm border border-zinc-700/30 rounded-xl transition-all duration-700 hover:border-indigo-400/50 hover:bg-zinc-800/50 hover:shadow-2xl hover:shadow-indigo-500/10 hover:transform hover:scale-105"
- >
- <div
- class="absolute inset-0 bg-gradient-to-br from-indigo-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700 rounded-xl"
- ></div>
- <div class="relative">
- <div
- class="w-16 h-16 bg-indigo-500/10 rounded-xl flex items-center justify-center mb-6 group-hover:bg-indigo-500/20 transition-all duration-500 group-hover:rotate-12 group-hover:scale-110"
- >
- <svg
- class="w-8 h-8 text-indigo-400"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"
- ></path>
- </svg>
- </div>
- <h4
- class="text-white text-xl font-semibold mb-4 group-hover:text-indigo-400 transition-colors duration-500"
- >
- {{ t("careers.culture.growth.title") }}
- </h4>
- <p class="text-zinc-300/80 text-sm leading-relaxed">
- {{ t("careers.culture.growth.description") }}
- </p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
-
- <!-- 职位列表区域 -->
- <section class="jobs-section">
- <div class="section-block w-full py-20 md:py-32 relative">
- <!-- 背景网格pattern -->
- <div class="absolute inset-0 opacity-5">
- <div
- class="absolute inset-0 bg-[linear-gradient(rgba(52,211,153,0.1)_1px,transparent_1px),linear-gradient(90deg,rgba(52,211,153,0.1)_1px,transparent_1px)] bg-[size:100px_100px]"
- ></div>
- </div>
-
- <div
- class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10"
- >
- <div class="text-center mb-12 md:mb-20">
- <h3
- class="text-white text-2xl md:text-4xl font-bold mb-6 tracking-wider"
- >
- {{ t("careers.jobs.title") }}
- </h3>
- <div class="w-20 h-px bg-emerald-400 mx-auto mb-8"></div>
- </div>
-
- <!-- 加载状态 -->
- <div v-if="jobsLoading" class="flex justify-center py-20">
- <div
- class="animate-spin h-8 w-8 border-4 border-emerald-400 rounded-full border-t-transparent"
- ></div>
- </div>
-
- <!-- 职位列表 -->
- <div v-else-if="jobsList.length > 0">
- <!-- 职位卡片网格 -->
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
- <JobCard v-for="job in jobsList" :key="job.id" :job="job" />
- </div>
- </div>
-
- <!-- 无职位状态 -->
- <div v-else class="text-center py-20">
- <div
- class="relative inline-flex items-center justify-center w-24 h-24 mb-8"
- >
- <svg
- class="w-12 h-12 text-zinc-500"
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- stroke-width="2"
- d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2-2v2m8 0H8m8 0v2a2 2 0 002 2M8 6V4h8V6M8 6v2a2 2 0 002 2h4a2 2 0 002-2V6"
- ></path>
- </svg>
- </div>
- <h4 class="text-zinc-400 text-xl font-medium mb-3">
- {{ t("careers.jobs.noPositions") }}
- </h4>
- <p
- class="text-zinc-500 text-base max-w-md mx-auto leading-relaxed"
- >
- {{ t("careers.jobs.checkLater") }}
- </p>
- </div>
- </div>
- </div>
- </section>
-
- <!-- 底部CTA区域 -->
- <section class="cta-section">
- <div class="section-block w-full py-20 md:py-32 relative">
- <!-- 图片背景 -->
- <img
- src="/assets/images/careers.webp"
- alt="CTA Background"
- class="absolute inset-0 w-full h-full object-cover opacity-40 z-0"
- />
- <div
- class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10 text-center"
- >
- <div class="max-w-3xl mx-auto space-y-8">
- <h3
- class="text-white text-2xl md:text-4xl font-bold leading-tight"
- >
- {{ t("careers.cta.title") }}
- </h3>
- <p
- class="text-zinc-300/80 text-base md:text-xl leading-relaxed"
- >
- {{ t("careers.cta.description") }}
- </p>
- <div class="pt-4">
- <nuxt-link
- :to="`${homepagePath}/contact`"
- class="inline-flex w-32 h-10 md:w-40 md:h-11 bg-zinc-300/10 rounded-lg outline outline-1 items-center justify-center gap-2 outline-white/20 backdrop-blur-[10px] cursor-pointer hover:bg-zinc-300/20 transition-colors duration-200"
- >
- <span class="text-sm md:text-base font-normal text-white">{{
- t("careers.cta.button")
- }}</span>
- <i
- class="icon-arrow-right text-xs md:text-sm font-normal text-white"
- ></i>
- </nuxt-link>
- </div>
- </div>
- </div>
- </div>
- </section>
- </ErrorBoundary>
- </div>
- </div>
- </template>
-
- <script setup lang="ts">
- import type { Job, JobsApiResponse } from "~/data/jobs";
- import { localJobs } from "~/data/jobs";
-
- const { t, locale } = useI18n();
-
- // 计算首页路径
- const homepagePath = computed(() => {
- return locale.value === "zh" ? "" : `/${locale.value}`;
- });
-
- // SEO和页面元数据
- useSeoMeta({
- title: `${t("careers.title")} - Hanye`,
- description: t("careers.subtitle"),
- keywords: t("careers.keywords"),
- });
-
- // 响应式数据
- const pageError = ref<Error | null>(null);
- const jobsLoading = ref(false);
- const jobsList = ref<Job[]>([]);
- const totalJobs = ref(0);
-
- // API配置
- const API_BASE_URL = "https://digital.sohomall.jp/prod-api/system/workInfo";
-
- /**
- * 从API获取职位数据
- * @param pageNum 页码
- * @param pageSize 页面大小
- * @returns Promise<JobsApiResponse>
- */
- const fetchJobsFromApi = async (
- pageNum: number = 1,
- pageSize: number = 20
- ): Promise<JobsApiResponse> => {
- const response = await $fetch<JobsApiResponse>(
- `${API_BASE_URL}/noVerifyList`,
- {
- params: {
- pageNum,
- pageSize,
- },
- timeout: 10000, // 10秒超时
- }
- );
-
- if (response.code !== 200) {
- throw new Error(response.msg || "获取职位信息失败");
- }
-
- return response;
- };
-
- /**
- * 初始化职位数据
- */
- const initializeJobs = async () => {
- try {
- jobsLoading.value = true;
- pageError.value = null;
-
- // 尝试从API获取数据
- const apiResponse = await fetchJobsFromApi();
-
- console.log(apiResponse);
-
- // 过滤掉已禁用的职位 (isDisabled为"1"表示启用,"0"表示禁用)
- const availableJobs = apiResponse.rows.filter(
- (job: Job) => job.isDisabled === "1"
- );
-
- jobsList.value = availableJobs;
- totalJobs.value = apiResponse.total;
-
- console.log(`成功加载 ${availableJobs.length} 个职位信息`);
- } catch (error) {
- console.warn("API获取失败,使用本地数据:", error);
-
- // API失败时使用本地数据作为fallback
- // 过滤掉已禁用的职位
- const availableLocalJobs = localJobs.filter(
- (job: Job) => job.isDisabled === "0"
- );
-
- jobsList.value = availableLocalJobs;
- totalJobs.value = availableLocalJobs.length;
-
- // 不设置pageError,因为有fallback数据
- console.log(`使用本地数据加载 ${availableLocalJobs.length} 个职位信息`);
- } finally {
- jobsLoading.value = false;
- }
- };
-
- /**
- * 处理联系按钮点击
- */
- const handleContactClick = () => {
- navigateTo("/contact");
- };
-
- /**
- * 刷新职位数据
- */
- const refreshJobs = async () => {
- await initializeJobs();
- };
-
- // 组件挂载时初始化数据
- onMounted(async () => {
- await initializeJobs();
-
- // 添加页面加载动画
- nextTick(() => {
- const cards = document.querySelectorAll(".culture-card, .job-card");
- cards.forEach((card, index) => {
- setTimeout(() => {
- (card as HTMLElement).style.opacity = "1";
- (card as HTMLElement).style.transform = "translateY(0)";
- }, 100 * index);
- });
-
- // 面包屑动画
- const breadcrumb = document.querySelector("nav");
- if (breadcrumb) {
- setTimeout(() => {
- breadcrumb.classList.remove("opacity-0");
- breadcrumb.classList.add("opacity-100");
- }, 200);
- }
- });
- });
- </script>
-
- <style scoped>
- .careers-page {
- scroll-behavior: smooth;
- }
-
- .culture-card,
- .job-card {
- opacity: 0;
- transform: translateY(20px);
- transition: opacity 0.8s ease, transform 0.8s ease;
- }
-
- @keyframes fade-in {
- from {
- opacity: 0;
- transform: translateY(10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
- }
-
- .animate-fade-in {
- animation: fade-in 0.6s ease-out forwards;
- }
-
- /* 自定义滚动条 */
- ::-webkit-scrollbar {
- width: 6px;
- }
-
- ::-webkit-scrollbar-track {
- background: rgba(0, 0, 0, 0.1);
- }
-
- ::-webkit-scrollbar-thumb {
- background: #35f1ff;
- border-radius: 3px;
- }
-
- ::-webkit-scrollbar-thumb:hover {
- background: #35f1ff;
- }
-
- /* 动画关键帧 */
- @keyframes float {
- 0%,
- 100% {
- transform: translateY(0px);
- }
- 50% {
- transform: translateY(-10px);
- }
- }
-
- @keyframes pulse-glow {
- 0%,
- 100% {
- box-shadow: 0 0 5px rgba(53, 241, 255, 0.3);
- }
- 50% {
- box-shadow: 0 0 20px rgba(53, 241, 255, 0.6);
- }
- }
-
- .animate-float {
- animation: float 6s ease-in-out infinite;
- }
-
- .animate-pulse-glow {
- animation: pulse-glow 2s ease-in-out infinite;
- }
-
- /* 蒙层和光泽效果 */
- .section-block {
- position: relative;
- transition: all 0.5s ease;
- overflow: hidden;
- }
-
- .section-block::before {
- content: "";
- position: absolute;
- inset: 0;
- opacity: 0;
- transition: opacity 0.5s ease;
- pointer-events: none;
- z-index: 5;
- }
-
- .section-block:hover::before {
- opacity: 1;
- }
-
- /* 为每个模块单独定义蒙层颜色 */
- .culture-section .section-block::before {
- background: linear-gradient(
- 45deg,
- transparent,
- rgba(99, 102, 241, 0.1),
- /* Indigo */ transparent
- );
- }
-
- .jobs-section .section-block::before {
- background: linear-gradient(
- 45deg,
- transparent,
- rgba(52, 211, 153, 0.1),
- /* Emerald */ transparent
- );
- }
-
- .cta-section .section-block::before {
- background: linear-gradient(
- 45deg,
- transparent,
- rgba(241, 252, 255, 0.021),
- /* Rose */ transparent
- );
- }
- </style>
|