Explorar el Código

feat: SEO for kaifain

Acathur hace 5 años
padre
commit
6aee79da71

+ 6 - 0
kaifain_v2/components/SolutionCell.vue

@@ -62,6 +62,12 @@ export default Vue.extend({
 
   .tag {
     font-size: 0.6875rem;
+    cursor: default;
+  }
+
+  a.tag {
+    cursor: pointer;
+    text-decoration: none;
   }
 
   .title {

+ 7 - 1
kaifain_v2/components/Toolbar.vue

@@ -50,6 +50,9 @@
                 v-model="isChoiceCache"
                 @input="changeIsChoice"
                 ) 优选服务
+
+        .level-right
+          slot(name="right")
 </template>
 
 <script lang="ts">
@@ -135,7 +138,10 @@ export default Vue.extend({
 .kaifain-view .toolbar {
   background: #f6f6f7;
   height: 36px;
-  margin: 0 -0.75rem;
+
+  .level {
+    margin: 0 -0.75rem;
+  }
 
   .level-item {
     font-size: 0.75rem;

+ 58 - 0
kaifain_v2/helpers/seoHelper.ts

@@ -0,0 +1,58 @@
+import { randomRange } from '../utils/misc'
+
+export const genDocumentHeadData = (input?: {
+  catName?: string
+}) => {
+  const { catName } = input || {}
+  let title: string
+  let keywords: string
+  let descrption: string
+
+  if (catName) {
+    title = `${catName} 软件、网站、APP、小程序开发及SaaS、PaaS、IaaS、API服务平台-开发屋`
+    keywords = `${catName}软件开发,${catName}APP开发,${catName}小程序开发,${catName}SaaS服务商`
+    descrption = `开发屋为${catName}中小型企业企业提供各行业软件、APP、小程序开发服务,并整合开发项目所需的各种SaaS、PaaS,LaaS以及API服务商供选择,全程解决开发需求!`
+  } else {
+    title = '开发屋-提供网站建设、APP软件、小程序开发及SaaS、PasS、IaaS服务'
+    keywords = '网站开发, 软件APP开发, SaaS, PaaS'
+    descrption = '开发屋为企业提供行业内领先的技术解决方案,包括行业定制化SaaS、PasS、API数据接口服务以及技术组织,保障企业在降低人力开发成本的同时,得到优质的项目开发实力。'
+  }
+
+  return {
+    title,
+    keywords,
+    descrption
+  }
+}
+
+const genFooterLinkItem = (name: string, hashId: string) => {
+  return {
+    name: `${name}技术开发`,
+    url: `/c/${hashId}`
+  }
+}
+
+export const genDocumentFooterData = (input: {
+  ctx: any
+  classes: any[]
+}) => {
+  const { ctx, classes } = input || {}
+  const host = (process.server ? ctx.req.headers.host : location.host) || ''
+  const baseLink = host && host.indexOf('local') > -1 ? `http://${host}` : `https://${host}`
+  const link = [{
+    name: '热门领域技术解决方案',
+    data: classes.map(topCat => genFooterLinkItem(topCat.name, topCat.hash_id))
+  }, {
+    name: '细分领域技术解决方案',
+    data: classes
+      .flatMap(topCat => topCat.categories || [])
+      .sort(() => 0.5 - Math.random())
+      .slice(0, randomRange(20, 30))
+      .map(cat => genFooterLinkItem(cat.name, cat.cat_id))
+  }]
+
+  return {
+    baseLink,
+    link
+  }
+}

+ 48 - 15
kaifain_v2/pages/index.vue

@@ -23,6 +23,12 @@
         :sort-type.sync="sortType"
         :is-choice.sync="isChoice"
         )
+        .result-msg(
+          v-if="catName || topCatName"
+          slot="right"
+          )
+          h1 {{(catName || topCatName).replace(/方案$/, '')}}解决方案
+          .total  ({{solutionList.length}})
       #solution-list.list.container.is-content
         SolutionCell(
           v-for="row in solutionList"
@@ -58,10 +64,10 @@ import { listBanners, listSearchKeywords, getInitParameters } from '../apis/comm
 import { listSolutions } from '../apis/solution'
 import { SolutionListMixin } from '../mixins/solution'
 import { parseCatIdAndServiceType, genCatIdSearchSentence, scrollToElement } from '../utils/misc'
+import { genDocumentHeadData, genDocumentFooterData } from '../helpers/seoHelper'
 
 import ConnectUs from '@/components/common/connectUs.vue'
 import KaifainFooter from '@/components/SeoFooter.vue'
-import DealSeoFooter from '@/components/kaifain/dealSeoFooter'
 
 export default SolutionListMixin.extend({
   name: 'Home',
@@ -83,28 +89,29 @@ export default SolutionListMixin.extend({
   data() {
     return {
       topnavFixed: false,
-      connectPopupVisible: false
+      connectPopupVisible: false,
+      topCatName: '',
+      catName: '',
     }
   },
 
   head() {
-    const title = "开发屋-提供网站建设、APP软件、小程序开发及SaaS、PasS、IaaS服务"
-    const keyword = "网站开发,软件APP开发,SaaS,PaaS"
-    const descrption = "开发屋为企业提供行业内领先的技术解决方案,包括行业定制化SaaS、PasS、API数据接口服务以及技术组织,保障企业在降低人力开发成本的同时,得到优质的项目开发实力。"
+    const { title, keywords, descrption } = genDocumentHeadData({
+      catName: this.catName || this.topCatName
+    })
 
     return {
-      title: title,
+      title,
       meta: [
         {
-          name: "keywords",
-          content: keyword,
+          name: 'keywords',
+          content: keywords,
         },
         {
-          name: "descrption",
-          content: descrption,
+          name: 'descrption',
+          content: descrption
         }
-      ],
-      // link: [{ rel: "canonical", href: canonical }],
+      ]
     }
   },
 
@@ -150,7 +157,9 @@ export default SolutionListMixin.extend({
 
     const {
       topCatId,
+      topCatName,
       catId,
+      catName,
       serviceType,
       matchedCatIds
     } = parseCatIdAndServiceType({
@@ -173,14 +182,18 @@ export default SolutionListMixin.extend({
       throw error({ statusCode: 404, message: 'Post not found (no data)' })
     }
 
-    let dealSeoFooterObj = new DealSeoFooter(ctx)
-    let footer = await dealSeoFooterObj.dealData()
+    const footer = genDocumentFooterData({
+      ctx,
+      classes
+    })
 
     return {
       page: ~~page,
       sortType: ~~sort,
       topCatId,
+      topCatName,
       catId,
+      catName,
       serviceType,
       cityId: city_id || null,
       isChoice: !!is_choice || false,
@@ -191,7 +204,7 @@ export default SolutionListMixin.extend({
       serviceTypes,
       solutionList: solutionRes.list || [],
       solutionTotal: ~~solutionRes.total,
-      ...footer
+      footer
     }
   },
 
@@ -221,6 +234,26 @@ export default SolutionListMixin.extend({
   .home {
     .main {
       min-height: 480px;
+
+      .result-msg {
+        color: #777;
+        font-size: 0.75rem;
+        font-weight: 400;
+        margin: 0 1rem 0 0;
+
+        > * {
+          display: inline-block;
+        }
+
+        .total {
+          margin-left: 4px;
+        }
+      }
+
+      h1 {
+        font-size: inherit;
+        font-weight: inherit;
+      }
     }
   }
 }

+ 6 - 4
kaifain_v2/pages/search.vue

@@ -49,10 +49,10 @@ import { listBanners, listSearchKeywords, getInitParameters } from '../apis/comm
 import { listSolutions } from '../apis/solution'
 import { SolutionListMixin } from '../mixins/solution'
 import { scrollToElement } from '../utils/misc'
+import { genDocumentFooterData } from '../helpers/seoHelper'
 
 import ConnectUs from '@/components/common/connectUs.vue'
 import KaifainFooter from '@/components/SeoFooter.vue'
-import DealSeoFooter from '@/components/kaifain/dealSeoFooter'
 
 export default SolutionListMixin.extend({
   name: 'Search',
@@ -126,8 +126,10 @@ export default SolutionListMixin.extend({
       throw error({ statusCode: 404, message: 'Post not found (no data)' })
     }
 
-    let dealSeoFooterObj = new DealSeoFooter(ctx)
-    let footer = await dealSeoFooterObj.dealData()
+    const footer = genDocumentFooterData({
+      ctx,
+      classes
+    })
 
     return {
       q,
@@ -140,7 +142,7 @@ export default SolutionListMixin.extend({
       serviceTypes,
       solutionList: solutionRes.list || [],
       solutionTotal: ~~solutionRes.total,
-      ...footer
+      footer
     }
   },
 

+ 27 - 7
kaifain_v2/utils/misc.ts

@@ -1,3 +1,7 @@
+export const randomRange = (min: number, max: number) => {
+  return Math.random() * (max - min) + min
+}
+
 export const scrollToElement = (selector: string) => {
   const el = document.querySelector(selector)
 
@@ -10,11 +14,17 @@ export const scrollToElement = (selector: string) => {
   }
 }
 
-export const findTopCatBySubCatId = (classes, catId) => {
-  return classes.find((topCat) => {
+export const findTopCatBySubCatId = (classes: any[], catId: string): any[] | null => {
+  for (const topCat of classes) {
     const cats = topCat.categories
-    return cats && cats.length && cats.find((cat) => cat.cat_id === catId)
-  })
+    const matchedCat = cats && cats.length && cats.find((cat) => cat.cat_id === catId)
+
+    if (matchedCat) {
+      return [topCat, matchedCat]
+    }
+  }
+
+  return null
 }
 
 export const getTopCatSubCatIds = (topCat) => {
@@ -38,21 +48,29 @@ export const parseCatIdAndServiceType = (input: {
   let catId = '_'
   let serviceType = '_'
   let matchedCatIds: string[] = []
+  let topCatName!: string
+  let catName!: string
 
   if (cat_id) {
     let topCat
+    let cat
 
     if (cat_id.length === 8) {
       topCat = classes.find((topCat) => topCat.hash_id === cat_id)
       matchedCatIds = getTopCatSubCatIds(topCat)
     } else {
-      catId = cat_id
-      matchedCatIds = [catId]
-      topCat = findTopCatBySubCatId(classes, catId)
+      [topCat, cat] = findTopCatBySubCatId(classes, cat_id) || []
+
+      if (cat) {
+        catId = cat_id
+        catName = cat.name
+        matchedCatIds = [catId]
+      }
     }
 
     if (topCat) {
       topCatId = topCat.hash_id
+      topCatName = topCat.name
     }
   }
 
@@ -66,7 +84,9 @@ export const parseCatIdAndServiceType = (input: {
 
   return {
     topCatId,
+    topCatName,
     catId,
+    catName,
     serviceType,
     matchedCatIds
   }

+ 6 - 0
layouts/kaifain_v2.vue

@@ -100,5 +100,11 @@ export default {
   .el-dropdown-menu__item {
     padding: 0 18px 0 16px;
   }
+
+  #proginn-footer {
+    .item-box {
+      width: 100%;
+    }
+  }
 }
 </style>