Przeglądaj źródła

在首页增加银龄岗

yourname 9 miesięcy temu
rodzic
commit
2029b6a19f

+ 245 - 18
src/client/mobile/pages/NewHomePage.tsx

@@ -194,6 +194,11 @@ const NewHomePage: React.FC = () => {
     .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
     .slice(0, 3);
   
+  // 银龄岗数据(使用推荐的岗位中最新发布的3条)
+  const silverPositions = transformJobs(homeData.recommendedJobs || [])
+    .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
+    .slice(0, 3);
+  
   // 模拟银龄库数据
   const silverTalents = [
     {
@@ -516,11 +521,11 @@ const NewHomePage: React.FC = () => {
           </div>
         )}
 
-        {/* 银龄 */}
+        {/* 银龄人才 */}
         {silverTalents.length > 0 && (
           <div className="mt-6 px-4">
             <div className="flex justify-between items-center mb-4">
-              <h2 
+              <h2
                 className={`${FONT_STYLES.sectionTitle}`}
                 style={{ color: COLORS.text.primary }}
               >
@@ -529,7 +534,7 @@ const NewHomePage: React.FC = () => {
               <button
                 onClick={() => navigate('/silver-talents')}
                 className={`${FONT_STYLES.caption} px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md flex items-center space-x-1`}
-                style={{ 
+                style={{
                   color: COLORS.text.primary,
                   borderColor: COLORS.ink.medium,
                   backgroundColor: 'transparent'
@@ -545,7 +550,7 @@ const NewHomePage: React.FC = () => {
                 <div
                   key={talent.id}
                   className="flex items-center p-4 rounded-xl shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer backdrop-blur-sm"
-                  style={{ 
+                  style={{
                     backgroundColor: 'rgba(255,255,255,0.8)',
                     border: `1px solid ${COLORS.ink.medium}`
                   }}
@@ -558,22 +563,22 @@ const NewHomePage: React.FC = () => {
                     style={{ borderColor: COLORS.ink.medium }}
                   />
                   <div className="flex-1">
-                    <h4 
+                    <h4
                       className={`font-medium ${FONT_STYLES.body}`}
                       style={{ color: COLORS.text.primary }}
                     >
                       {talent.name}
                     </h4>
-                    <p 
+                    <p
                       className={`${FONT_STYLES.caption}`}
                       style={{ color: COLORS.text.secondary }}
                     >
                       {talent.specialty || '暂无特长信息'}
                     </p>
                     <div className="flex items-center mt-2 space-x-2">
-                      <span 
+                      <span
                         className={`${FONT_STYLES.small} px-3 py-1 rounded-full flex items-center`}
-                        style={{ 
+                        style={{
                           backgroundColor: COLORS.accent.blue,
                           color: 'white'
                         }}
@@ -581,7 +586,7 @@ const NewHomePage: React.FC = () => {
                         <MapPinIcon className="w-3 h-3 mr-1" />
                         {talent.city || '未知地区'}
                       </span>
-                      <span 
+                      <span
                         className={`${FONT_STYLES.small} flex items-center`}
                         style={{ color: COLORS.text.light }}
                       >
@@ -596,20 +601,242 @@ const NewHomePage: React.FC = () => {
           </div>
         )}
 
+        {/* 银龄岗展示区域 */}
+        <div className="mt-6 px-4">
+          <div className="flex justify-between items-center mb-4">
+            <h2
+              className={`${FONT_STYLES.sectionTitle}`}
+              style={{ color: COLORS.text.primary }}
+            >
+              银龄岗
+            </h2>
+            <button
+              onClick={() => navigate('/silver-jobs')}
+              className={`${FONT_STYLES.caption} px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md flex items-center space-x-1`}
+              style={{
+                color: COLORS.text.primary,
+                borderColor: COLORS.ink.medium,
+                backgroundColor: 'transparent'
+              }}
+            >
+              <span>显示更多</span>
+              <span>→</span>
+            </button>
+          </div>
+          
+          <div className="space-y-3">
+            {silverPositions.map((job) => (
+              <div
+                key={job.id}
+                className="flex items-center p-4 rounded-xl shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer backdrop-blur-sm"
+                style={{
+                  backgroundColor: 'rgba(255,255,255,0.8)',
+                  border: `1px solid ${COLORS.ink.medium}`
+                }}
+                onClick={() => navigate(`/silver-jobs/${job.id}`)}
+              >
+                <img
+                  src={job.image}
+                  alt={job.title}
+                  className="w-16 h-16 rounded-full object-cover mr-4 border-2 shadow-sm"
+                  style={{ borderColor: COLORS.ink.medium }}
+                />
+                <div className="flex-1">
+                  <h4
+                    className={`font-medium ${FONT_STYLES.body}`}
+                    style={{ color: COLORS.text.primary }}
+                  >
+                    {job.title}
+                  </h4>
+                  <p
+                    className={`${FONT_STYLES.caption}`}
+                    style={{ color: COLORS.text.secondary }}
+                  >
+                    {job.company}
+                  </p>
+                  <div className="flex items-center mt-2 space-x-2">
+                    <span
+                      className={`${FONT_STYLES.small} px-3 py-1 rounded-full flex items-center`}
+                      style={{
+                        backgroundColor: COLORS.accent.red,
+                        color: 'white'
+                      }}
+                    >
+                      {job.salary}
+                    </span>
+                    {job.tags.slice(0, 1).map((tag, i) => (
+                      <span
+                        key={i}
+                        className={`${FONT_STYLES.small} px-2 py-1 rounded-full flex items-center`}
+                        style={{
+                          backgroundColor: COLORS.accent.green,
+                          color: 'white'
+                        }}
+                      >
+                        <MapPinIcon className="w-3 h-3 mr-0.5" />
+                        {tag}
+                      </span>
+                    ))}
+                    <span
+                      className={`${FONT_STYLES.small} text-xs px-2 py-1 rounded-full`}
+                      style={{
+                        color: COLORS.text.light,
+                        backgroundColor: COLORS.ink.light
+                      }}
+                    >
+                      最新
+                    </span>
+                  </div>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+
+        {/* 银龄岗招标 */}
+        <div className="mt-6 px-4">
+          <div className="flex justify-between items-center mb-4">
+            <h2
+              className={`${FONT_STYLES.sectionTitle}`}
+              style={{ color: COLORS.text.primary }}
+            >
+              银龄岗招标
+            </h2>
+            <button
+              onClick={() => navigate('/silver-jobs')}
+              className={`${FONT_STYLES.caption} px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md flex items-center space-x-1`}
+              style={{
+                color: COLORS.text.primary,
+                borderColor: COLORS.ink.medium,
+                backgroundColor: 'transparent'
+              }}
+            >
+              <span>查看招标</span>
+              <span>→</span>
+            </button>
+          </div>
+          
+          <div className="space-y-3">
+            {[
+              {
+                id: 1,
+                title: '社区养老服务专员',
+                organization: '北京市朝阳区老龄办',
+                budget: '8-12万/年',
+                deadline: '2024-08-15',
+                location: '北京朝阳',
+                category: '养老服务'
+              },
+              {
+                id: 2,
+                title: '老年大学书法教师',
+                organization: '杭州市西湖区老年大学',
+                budget: '6-8万/年',
+                deadline: '2024-08-10',
+                location: '杭州西湖',
+                category: '文化教育'
+              },
+              {
+                id: 3,
+                title: '银龄健康顾问',
+                organization: '上海市静安区卫健委',
+                budget: '10-15万/年',
+                deadline: '2024-08-20',
+                location: '上海静安',
+                category: '健康管理'
+              }
+            ].sort((a,b) => new Date(b.deadline).getTime() - new Date(a.deadline).getTime()).slice(0, 3).map((bid) => (
+              <div
+                key={bid.id}
+                className="flex items-center justify-between p-4 rounded-xl shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer backdrop-blur-sm"
+                style={{
+                  backgroundColor: 'rgba(255,255,255,0.8)',
+                  border: `1px solid ${COLORS.ink.medium}`
+                }}
+                onClick={() => navigate(`/silver-jobs`)}
+              >
+                <div className="flex items-center flex-1">
+                  <div
+                    className="w-14 h-14 rounded-full flex items-center justify-center mr-4 shadow-sm"
+                    style={{ backgroundColor: COLORS.accent.red, color: 'white' }}
+                  >
+                    招
+                  </div>
+                  <div className="flex-1">
+                    <h4
+                      className={`font-medium ${FONT_STYLES.body}`}
+                      style={{ color: COLORS.text.primary }}
+                    >
+                      {bid.title}
+                    </h4>
+                    <p
+                      className={`${FONT_STYLES.caption}`}
+                      style={{ color: COLORS.text.secondary }}
+                    >
+                      {bid.organization}
+                    </p>
+                    <div className="flex items-center mt-1 space-x-2">
+                      <span
+                        className={`${FONT_STYLES.small} px-2 py-1 rounded-full flex items-center`}
+                        style={{
+                          backgroundColor: COLORS.accent.green,
+                          color: 'white'
+                        }}
+                      >
+                        {bid.budget}
+                      </span>
+                      <span
+                        className={`${FONT_STYLES.small} px-2 py-1 rounded-full flex items-center`}
+                        style={{
+                          backgroundColor: COLORS.accent.blue,
+                          color: 'white'
+                        }}
+                      >
+                        <MapPinIcon className="w-3 h-3 mr-1" />
+                        {bid.location}
+                      </span>
+                    </div>
+                  </div>
+                </div>
+                <div className="text-right flex flex-col items-end">
+                  <span
+                    className={`text-xs px-2 py-1 rounded-full mb-1`}
+                    style={{
+                      color: COLORS.text.light,
+                      backgroundColor: COLORS.ink.light
+                    }}
+                  >
+                    截止: {new Date(bid.deadline).toLocaleDateString()}
+                  </span>
+                  <span
+                    className={`text-xs px-2 py-1 rounded-full`}
+                    style={{
+                      backgroundColor: COLORS.accent.green,
+                      color: 'white'
+                    }}
+                  >
+                    {bid.category}
+                  </span>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+
         {/* 时间银行活动 */}
         {timeBankActivities.length > 0 && (
           <div className="mt-6 px-4">
             <div className="flex justify-between items-center mb-4">
-              <h2 
+              <h2
                 className={`${FONT_STYLES.sectionTitle}`}
                 style={{ color: COLORS.text.primary }}
               >
                 时间银行活动
               </h2>
-              <button 
+              <button
                 onClick={() => navigate('/time-bank')}
                 className={`${FONT_STYLES.caption} px-4 py-2 rounded-full border transition-all duration-300 hover:shadow-md flex items-center space-x-1`}
-                style={{ 
+                style={{
                   color: COLORS.text.primary,
                   borderColor: COLORS.ink.medium,
                   backgroundColor: 'transparent'
@@ -625,19 +852,19 @@ const NewHomePage: React.FC = () => {
                 <div
                   key={activity.id}
                   className="flex items-center justify-between p-4 rounded-xl shadow-sm backdrop-blur-sm"
-                  style={{ 
-                    backgroundColor: 'rgba(255,255,255,0.8)',
+                  style={{
+                    backgroundColor: "rgba(255,255,255,0.8)",
                     border: `1px solid ${COLORS.ink.medium}`
                   }}
                 >
                   <div>
-                    <h4 
+                    <h4
                       className={`font-medium ${FONT_STYLES.body}`}
                       style={{ color: COLORS.text.primary }}
                     >
                       {activity.organization}
                     </h4>
-                    <p 
+                    <p
                       className={`${FONT_STYLES.caption}`}
                       style={{ color: COLORS.text.secondary }}
                     >
@@ -645,7 +872,7 @@ const NewHomePage: React.FC = () => {
                     </p>
                   </div>
                   <div className="text-right">
-                    <div 
+                    <div
                       className={`text-lg font-bold ${FONT_STYLES.body}`}
                       style={{ color: COLORS.accent.blue }}
                     >
@@ -653,7 +880,7 @@ const NewHomePage: React.FC = () => {
                     </div>
                     <div className="flex items-center">
                       <TrophyIcon className="w-3 h-3 mr-1" style={{ color: COLORS.text.light }} />
-                      <div 
+                      <div
                         className={`${FONT_STYLES.small}`}
                         style={{ color: COLORS.text.light }}
                       >

+ 27 - 0
src/server/modules/home/home.service.optimized.ts

@@ -16,6 +16,7 @@ export interface HomeData {
   recommendedJobs: Job[];
   hotKnowledge: SilverKnowledge[];
   timeBankActivities: SilverTimeBank[];
+  latestJobs: Job[]; // 新增:最新银龄岗位
   userStats: {
     pointBalance: number;
     timeBankHours: number;
@@ -81,12 +82,14 @@ export class OptimizedHomeService {
       recommendedJobs,
       hotKnowledge,
       timeBankActivities,
+      latestJobs,
       userStats
     ] = await Promise.all([
       this.getCachedBanners(),
       this.getCachedRecommendedJobs(userId),
       this.getCachedHotKnowledge(userId),
       this.getCachedTimeBankActivities(userId),
+      this.getCachedLatestJobs(3),
       this.getCachedUserStats(userId)
     ]);
 
@@ -95,6 +98,7 @@ export class OptimizedHomeService {
       recommendedJobs,
       hotKnowledge,
       timeBankActivities,
+      latestJobs,
       userStats
     };
 
@@ -214,6 +218,29 @@ export class OptimizedHomeService {
     return activities;
   }
 
+  /**
+   * 获取带缓存的最新银龄岗位
+   */
+  async getCachedLatestJobs(limit: number = 3): Promise<Job[]> {
+    const cacheKey = `${this.cacheConfig.jobs.keyPrefix}:latest:${limit}`;
+    const cached = await this.redis.get(cacheKey);
+    
+    if (cached) {
+      return JSON.parse(cached);
+    }
+
+    const jobs = await this.jobRepo
+      .createQueryBuilder('job')
+      .leftJoinAndSelect('job.company', 'company')
+      .where('job.status = :status', { status: 1 })
+      .orderBy('job.createdAt', 'DESC')
+      .limit(limit)
+      .getMany();
+
+    await this.redis.setex(cacheKey, this.cacheConfig.jobs.ttl, JSON.stringify(jobs));
+    return jobs;
+  }
+
   /**
    * 获取带缓存的用户统计
    */