shinnosuke
2 天以前 a9537a9e6a6887d75281fce85b3006844c7ed629
rencaika/pages/index/index.uvue
@@ -1,21 +1,30 @@
<template>
   <view class="page">
      <scroll-view class="scroll-page" scroll-y @scroll="handleScroll">
         <view class="hero">
            <view class="hero-gradient"></view>
            <view v-if="homeVideoUrl != ''" class="play-button" @tap="playVideo"><text>向东看</text></view>
         </view>
         <view class="city-panel">
            <view class="city-heading"><text>才聚东区,共富未来</text><view class="city-label" @tap="openIntro"><text>幸福东区</text><image src="/static/home-assets/arrow-right.svg"></image></view></view>
            <view class="city-grid">
               <view class="city-card city-intro" @tap="openIntro"><text class="intro-name">东区简介</text><view class="intro-button"><text>查看更多</text><image src="/static/home-assets/arrow-right.svg"></image></view></view>
               <view class="city-side"><view class="city-card city-potential"><text>潜力城</text></view><view class="city-card city-golden"><text>黄金城</text></view></view>
               <view class="city-side"><view class="city-card city-industry"><text>兴业城</text></view><view class="city-card city-livable"><text>宜居城</text></view></view>
      <scroll-view :show-scrollbar="false" class="scroll-page" scroll-y @scroll="handleScroll">
         <view class="home-overview">
            <view class="hero">
               <view class="hero-surface">
                  <image class="hero-image" src="/static/home-assets/home-top.png" mode="aspectFit"></image>
                  <view class="hero-gradient"></view>
                  <view class="play-button" @tap="playVideo"><text>向东看</text></view>
               </view>
            </view>
            <view class="city-panel">
               <view class="city-panel-content">
                  <view class="city-heading"><text>才聚东区,共富未来</text><view class="city-label" @tap="openHappyDongqu"><text>幸福东区</text><image src="/static/home-assets/arrow-right.svg"></image></view></view>
                  <view class="city-grid">
                     <view class="city-card city-intro" @tap="openIntro"><image class="city-bg" :src="homeImage('city-intro.jpg')" mode="aspectFill"></image><text class="intro-name">东区简介</text><view class="intro-button"><text>查看更多</text><image src="/static/home-assets/arrow-right.svg"></image></view></view>
                     <view class="city-side"><view class="city-card city-potential"><image class="city-bg" :src="homeImage('city-potential.jpg')" mode="aspectFill"></image><view class="city-card-caption"></view><text>潜力城</text></view><view class="city-card city-golden"><image class="city-bg" :src="homeImage('city-golden.jpg')" mode="aspectFill"></image><view class="city-card-caption"></view><text>黄金城</text></view></view>
                     <view class="city-side"><view class="city-card city-industry"><image class="city-bg" :src="homeImage('city-industry.jpg')" mode="aspectFill"></image><view class="city-card-caption"></view><text>兴业城</text></view><view class="city-card city-livable"><image class="city-bg" :src="homeImage('city-livable.png')" mode="aspectFill"></image><view class="city-card-caption"></view><text>宜居城</text></view></view>
                  </view>
               </view>
               <image class="city-mascot" src="/static/home-assets/mascot-rest.png" mode="aspectFit"></image>
            </view>
            <image class="city-stand" src="/static/home-assets/mascot-stand.png" mode="aspectFit"></image>
         </view>
         <view class="section-head"><view class="section-title"><text>人才资讯</text></view><text class="more" @tap="goNews">查看更多</text></view>
         <view class="section-head"><view class="section-title"><image class="section-icon" src="/static/home-assets/mascot-leap.png" mode="aspectFit"></image><text>人才资讯</text></view><text class="more" @tap="goNews">查看更多</text></view>
         <view v-if="homeLoading" class="news-state"><text>资讯加载中...</text></view>
         <view v-else-if="homeError" class="news-state" @tap="loadHome"><text>{{homeError}}</text><text class="news-retry">点击重试</text></view>
         <view v-else>
@@ -46,6 +55,12 @@
   import { isApiConfigured } from '../../config/api.uts'
   import { getAppHome } from '../../services/portal.uts'
   import { resolveApiUrl } from '../../services/http.uts'
   /**
    * 首页图片放在服务器上(`/uploads/home/…`),代码里只存相对路径:
    * 换图不用改代码、也不用重新上传体验版,和后台域名一起走环境配置。
    */
   const homeImage = (name: string): string => resolveApiUrl('/uploads/home/' + name)
   const navTop = ref(28)
   const navHeight = ref(32)
@@ -122,7 +137,8 @@
      }
      uni.navigateTo({ url: '/pages/home-video/home-video?url=' + encodeURIComponent(resolveApiUrl(homeVideoUrl.value)) })
   }
   const openIntro = () => {
   const openIntro = () => uni.navigateTo({ url: '/city-intro/pages/intro/intro' })
   const openHappyDongqu = () => {
      if (miniProgramAppId.value != '') {
         uni.navigateToMiniProgram({
            appId: miniProgramAppId.value,
@@ -155,28 +171,46 @@
<style>
   .page { height: 100%; background-color: #FFFFFF; }
   .scroll-page { height: calc(100% - 126rpx); height: calc(100% - 126rpx - env(safe-area-inset-bottom)); background-color: #FFFFFF; }
   .hero { height: 468rpx; background-color: #FFFFFF; position: relative; overflow: hidden; }
   .hero-gradient { position: absolute; z-index: 1; top: 0; left: 0; right: 0; bottom: 0; border-bottom-left-radius: 48rpx; border-bottom-right-radius: 48rpx; background-image: linear-gradient(145deg, #F45A2A 0%, #FF9E4B 55%, #FFE0AC 100%); }
   .home-overview { position: relative; overflow: visible; flex-shrink: 0; }
   .hero { height: 462rpx; min-height: 462rpx; flex-shrink: 0; position: relative; z-index: 1; overflow: visible; }
   .hero-surface { position: relative; width: 100%; height: 462rpx; flex-shrink: 0; overflow: hidden; border-bottom-left-radius: 72rpx; border-bottom-right-radius: 72rpx; }
   .hero-image { position: absolute; left: 0; top: 0; width: 100%; height: 462rpx; }
   .hero-gradient { position: absolute; z-index: 1; top: 0; left: 0; right: 0; height: 300rpx; background-image: linear-gradient(180deg, rgba(244,90,42,.88) 0%, rgba(255,130,60,.42) 62%, rgba(255,166,80,0) 100%); }
   .safe-space { height: 28px; position: relative; z-index: 2; }
   .nav-row { height: 32px; padding: 0 32rpx; position: relative; z-index: 2; flex-direction: row; align-items: center; justify-content: space-between; }
   .sticky-nav { position: absolute; z-index: 30; top: 0; left: 0; right: 0; padding-bottom: 20rpx; }
   .sticky-nav-bg { position: absolute; z-index: 0; top: 0; left: 0; right: 0; bottom: 0; opacity: 0; background-image: linear-gradient(180deg, #F26A38 0%, #EE542B 100%); transition: opacity 280ms ease-out; }
   .sticky-nav.is-solid .sticky-nav-bg { opacity: 1; }
   .nav-title { position: absolute; z-index: 1; left: 30rpx; top: 10rpx; height: 100%; flex-direction: row; align-items: center; justify-content: flex-start; }
   .nav-title text { color: #FFFFFF; font-size: 28rpx; font-weight: 700; opacity: .95; }
   .nav-title text { color: #FFFFFF; font-family: 'FoodCalligraphyFull', 'FoodCalligraphy'; font-size: 38rpx; font-weight: 700; opacity: .95; }
   .capsule-reserve { width: 88px; height: 100%; flex-shrink: 0; }
   .play-button { position: absolute; z-index: 2; bottom: 20rpx; left: 50%; margin-left: -78rpx; width: 156rpx; height: 56rpx; border-radius: 28rpx; background-image: linear-gradient(180deg, #FFB75A 0%, #FF6A24 100%); border-width: 2rpx; border-color: rgba(255,255,255,.82); box-shadow: 0 7rpx 14rpx rgba(234,92,26,.26); flex-direction: row; justify-content: center; align-items: center; }
   .play-button { position: absolute; z-index: 2; bottom: 52rpx; left: 50%; margin-left: -78rpx; width: 156rpx; height: 56rpx; border-radius: 28rpx; background-image: linear-gradient(180deg, #FFB75A 0%, #FF6A24 100%); border-width: 2rpx; border-color: rgba(255,255,255,.82); box-shadow: 0 7rpx 14rpx rgba(234,92,26,.26); flex-direction: row; justify-content: center; align-items: center; }
   .play-button text { color: #FFFFFF; font-size: 23rpx; }
   .city-panel { margin: -10rpx 16rpx 38rpx; padding: 22rpx 0 0; overflow: visible; background-color: #FFFFFF; border-radius: 26rpx; position: relative; box-shadow: 0 -8rpx 14rpx rgba(255, 103, 39, .27); }
   .city-heading { height: 58rpx; margin: 0 22rpx; flex-direction: row; justify-content: space-between; align-items: center; }
   /*
    * 顶图按素材原比例显示透明圆角,城市模块置于前面并上移重叠。
    * 外层渐变与内层白色卡片相差 2rpx,形成沿圆角延伸的橙色渐变边框。
    */
   .city-panel { margin: -32rpx 16rpx 60rpx; padding: 2rpx; border-radius: 40rpx; overflow: visible; position: relative; z-index: 2; background-image: linear-gradient(150deg, #FFDDC9 0%, #FF9C5A 52%, #FFD5B7 100%); }
   .city-panel-content { padding-top: 22rpx; border-radius: 38rpx; overflow: visible; position: relative; background-color: #FFFFFF; }
   .city-heading { height: 58rpx; margin: 0 22rpx; position: relative; flex-direction: row; justify-content: space-between; align-items: center; }
   /* Keep the mascot above both cards; the image canvas includes transparent padding. */
   .city-stand { position: absolute; right: 18rpx; top: 341rpx; width: 58rpx; height: 168rpx; z-index: 3; }
   /* 吉祥物随标题恢复位置,草坪底边保持在橙色城市区上沿。 */
   .city-mascot { position: absolute; right: 162rpx; top: 42rpx; width: 128rpx; height: 75rpx; z-index: 3; }
   .city-heading > text { color: #F16624; font-size: 35rpx; font-weight: 700; letter-spacing: 1rpx; background-image: linear-gradient(180deg, #F45A2A 0%, #FFB257 100%); background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
   .city-label { margin-right: 48rpx; padding: 10rpx 13rpx; border-radius: 18rpx; background-image: linear-gradient(180deg, #FFB85E 0%, #FF6726 100%); box-shadow: 0 5rpx 10rpx rgba(239,101,34,.22); flex-direction: row; align-items: center; } .city-label text { color: #FFFFFF; font-size: 20rpx; } .city-label image { width: 20rpx; height: 20rpx; margin-left: 7rpx; }
   .city-grid { box-sizing: border-box; height: 292rpx; margin-top: 18rpx; padding: 22rpx; overflow: visible; background-image: linear-gradient(180deg, #FF5F2D 0%, #FFB36B 100%); border-bottom-left-radius: 26rpx; border-bottom-right-radius: 26rpx; flex-direction: row; } .city-card { overflow: hidden; border-radius: 17rpx; position: relative; justify-content: flex-end; background-image: linear-gradient(135deg, #E96C3D 0%, #F8AA56 100%); }
   /*
    * 「幸福东区」按钮:原型里按钮右边缘距面板右边缘 18px(面板 287px)→ 45rpx;
    * 面板内缩 16rpx、边框 2rpx、标题边距 22rpx,再留 7rpx 对齐右侧按钮。
    */
   .city-label { margin-right: 7rpx; padding: 10rpx 13rpx; border-radius: 18rpx; background-image: linear-gradient(180deg, #FFB85E 0%, #FF6726 100%); box-shadow: 0 5rpx 10rpx rgba(239,101,34,.22); flex-direction: row; align-items: center; } .city-label text { color: #FFFFFF; font-size: 20rpx; } .city-label image { width: 20rpx; height: 20rpx; margin-left: 7rpx; }
   /* Cards extend 22rpx below the background; the panel margin reserves that space. */
   .city-grid { box-sizing: border-box; height: 308rpx; min-height: 308rpx; margin: 18rpx 0 0; padding: 22rpx; overflow: visible; border-bottom-left-radius: 38rpx; border-bottom-right-radius: 38rpx; background-image: linear-gradient(180deg, #FF5F2D 0%, #FFB36B 100%); flex-direction: row; } .city-card { overflow: hidden; border-radius: 17rpx; position: relative; justify-content: flex-end; background-image: linear-gradient(135deg, #E96C3D 0%, #F8AA56 100%); }
   .city-bg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
   .city-intro { width: 242rpx; height: 308rpx; box-sizing: border-box; margin-right: 14rpx; padding: 22rpx; } .intro-name { position: absolute; z-index: 1; top: 50%; left: 0; right: 0; transform: translateY(-50%); color: #FFFFFF; font-size: 37rpx; font-weight: 700; text-align: center; } .intro-button { position: relative; z-index: 1; align-self: center; box-sizing: border-box; width: 146rpx; height: 42rpx; margin-top: 13rpx; padding: 0 12rpx; border-radius: 21rpx; background-image: linear-gradient(90deg, rgba(255,207,138,.92) 0%, rgba(255,101,36,.68) 100%); border-width: 1rpx; border-color: rgba(255,255,255,.42); flex-direction: row; align-items: center; justify-content: space-between; } .intro-button text { color: #FFFFFF; font-size: 19rpx; } .intro-button image { width: 19rpx; height: 19rpx; margin-left: 8rpx; }
   .city-side { height: 308rpx; flex: 1; margin-right: 14rpx; justify-content: space-between; } .city-side:last-child { margin-right: 0; } .city-side .city-card { height: 147rpx; padding: 0; } .city-side .city-card > text { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; padding: 10rpx 12rpx; color: #FFFFFF; font-size: 22rpx; font-weight: 700; }
   .city-side { height: 308rpx; flex: 1; margin-right: 14rpx; justify-content: space-between; } .city-side:last-child { margin-right: 0; } .city-side .city-card { height: 147rpx; padding: 0; } .city-card-caption { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; height: 46rpx; background-image: linear-gradient(90deg, rgba(239,91,117,.9) 0%, rgba(243,102,135,.55) 55%, rgba(243,102,135,0) 100%); } .city-side .city-card > text { position: absolute; z-index: 2; left: 0; right: 0; bottom: 0; padding: 10rpx 12rpx; color: #FFFFFF; font-size: 22rpx; font-weight: 700; text-shadow: 0 2rpx 8rpx rgba(0,0,0,.5); }
   .section-head { height: 93rpx; padding: 0 31rpx; flex-direction: row; align-items: center; justify-content: space-between; } .section-title { flex-direction: row; align-items: center; } .section-title text { color: #353535; font-size: 31rpx; font-weight: 700; } .more { color: #5C5C5C; font-size: 22rpx; }
   .section-head { height: 93rpx; padding: 0 31rpx; flex-direction: row; align-items: center; justify-content: space-between; } .section-title { flex-direction: row; align-items: center; } .section-icon { width: 44rpx; height: 54rpx; margin-right: 10rpx; } .section-title text { color: #353535; font-size: 31rpx; font-weight: 700; } .more { color: #5C5C5C; font-size: 22rpx; }
   .news-state { min-height: 150rpx; margin: 0 31rpx; justify-content: center; align-items: center; color: #8B8B8B; font-size: 24rpx; } .news-retry { margin-top: 12rpx; color: #F16624; }
   .news-featured { height: 205rpx; margin: 0 19rpx; border-radius: 18rpx; overflow: hidden; position: relative; background-image: linear-gradient(135deg, #F26A38 0%, #F9A551 100%); } .news-featured > image { width: 100%; height: 100%; } .news-shade { position: absolute; left: 0; right: 0; bottom: 0; height: 118rpx; background-color: rgba(0,0,0,.44); } .top-badge { position: absolute; left: 20rpx; top: 18rpx; padding: 7rpx 14rpx; border-radius: 12rpx; background-color: #FFF3D4; } .top-badge text { color: #F2722E; font-size: 20rpx; font-weight: 700; } .featured-copy { position: absolute; left: 20rpx; right: 20rpx; bottom: 17rpx; } .featured-copy text:first-child { display: block; color: #FFFFFF; font-size: 24rpx; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .featured-copy text:last-child { display: block; margin-top: 8rpx; color: #FFFFFF; opacity: .85; font-size: 19rpx; }
   .news-list { margin: 0 31rpx; } .news-row { min-height: 116rpx; padding: 22rpx 0 16rpx; border-bottom-width: 1rpx; border-bottom-color: #EEEEEE; } .news-name { color: #363636; font-size: 25rpx; line-height: 36rpx; } .news-meta { margin-top: 12rpx; flex-direction: row; align-items: center; color: #98A2B3; font-size: 19rpx; } .new-badge { margin-right: 14rpx; padding: 4rpx 10rpx; border-radius: 12rpx; background-color: #FFF0D9; color: #FE7930; font-size: 18rpx; }