Просмотр исходного кода

Improve the search function / 完善搜索功能

star7th 4 лет назад
Родитель
Сommit
40ce2623c9

+ 34 - 0
server/Application/Api/Controller/ItemController.class.php

@@ -622,5 +622,39 @@ class ItemController extends BaseController {
             $this->sendError(10101);
         }
     }
+
+    // 在某个项目中根据内容搜索
+    public function search(){
+        $keyword = I("keyword");
+        $item_id = I("item_id/d");
+        $login_user = $this->checkLogin();
+        $uid = $login_user['uid'] ;
+        if(!$this->checkItemVisit($uid , $item_id)){
+            $this->sendError(10303,"没有权限");
+            return ;
+        }
+        $item = D("Item")->where("item_id = '%d' and is_del = 0 ",array($item_id))->find();
+        $keyword =  \SQLite3::escapeString($keyword) ;
+        $pages = D("Page")->search($item_id,$keyword) ;
+        if($pages){
+            foreach ($pages as $key => $value) {
+                $page_content = htmlspecialchars_decode($value['page_content']) ;
+                $pos = mb_strpos($page_content,$keyword) ;
+                $len = mb_strlen($keyword) ;
+                $start = ( $pos - 100 ) > 0 ? ( $pos - 100 ) : 0  ;
+                $pages[$key]['search_content'] = '...'.mb_substr($page_content,$start , ($len +  200 ) ).'...' ;
+                unset($pages[$key]['page_content']) ;
+                $pages[$key]['item_id'] = $item['item_id'] ;
+                $pages[$key]['item_name'] = $item['item_name'] ;
+            }
+        }
+        $return = array(
+            "item_id"=> $item_id , 
+            "item_name"=> $item['item_name'] ,
+             "pages"=>$pages
+        );
+        $this->sendResult($return);
+
+    }
     
 }

+ 18 - 0
server/Application/Api/Model/PageModel.class.php

@@ -9,6 +9,24 @@ class PageModel extends BaseModel {
 
     protected $cat_name_id = array();
 
+    //搜索某个项目下的页面
+    public function search($item_id,$keyword){
+        $return_pages = array() ;
+        $item = D("Item")->where("item_id = '%d' and is_del = 0 ",array($item_id))->find();
+        $pages = $this->where("item_id = '$item_id' and is_del = 0")->order(" s_number asc  ")->select();
+        if (!empty($pages)) {
+          foreach ($pages as $key => &$value) {
+            $page_content = $value['page_content'];
+            if (strpos( strtolower($item['item_name']."-". $value['page_title']."  ".$page_content) ,strtolower ($keyword) ) !== false) {
+              $value['page_content'] = $page_content ;
+              $return_pages[] = $value;
+            }
+          }
+        }
+        unset($pages);
+        return $return_pages;
+    }  
+
     //根据内容更新页面
     //其中cat_name参数特别说明下,传递各格式如 '二级目录/三级目录/四级目录'
     public function update_by_content($item_id,$page_title,$page_content,$cat_name='',$s_number = 99){

+ 33 - 21
web_src/src/components/item/Index.vue

@@ -104,14 +104,13 @@
 
     <el-container class="container-narrow">
       <div class="container-thumbnails">
-        <div class="search-box-div" v-if="itemList.length > 9">
+        <div class="search-box-div" v-if="itemList.length > 1">
           <div class="search-box el-input el-input--prefix">
-            <input
+            <el-input
               autocomplete="off"
               type="text"
-              rows="2"
               validateevent="true"
-              class="el-input__inner"
+              :clearable="true"
               v-model="keyword"
             />
             <span class="el-input__prefix">
@@ -119,10 +118,14 @@
             </span>
           </div>
         </div>
-
-        <ul class="thumbnails" id="item-list" v-if="itemListByKeyword">
+        <Search
+          v-if="showSearch"
+          :keyword="keyword"
+          :itemList="itemList"
+        ></Search>
+        <ul class="thumbnails" id="item-list" v-if="!showSearch">
           <draggable
-            v-model="itemListByKeyword"
+            v-model="itemList"
             tag="span"
             group="item"
             @end="endMove"
@@ -130,10 +133,10 @@
           >
             <li
               class="text-center"
-              v-for="item in itemListByKeyword"
+              v-for="item in itemList"
               v-dragging="{
                 item: item,
-                list: itemListByKeyword,
+                list: itemList,
                 group: 'item'
               }"
               :key="item.item_id"
@@ -326,13 +329,15 @@ a {
 </style>
 
 <script>
+import Search from './Search'
 import draggable from 'vuedraggable'
 if (typeof window !== 'undefined') {
   var $s = require('scriptjs')
 }
 export default {
   components: {
-    draggable
+    draggable,
+    Search
   },
   data() {
     return {
@@ -341,21 +346,28 @@ export default {
       isAdmin: false,
       keyword: '',
       lang: '',
-      username: ''
+      username: '',
+      showSearch: false
     }
   },
-  computed: {
-    itemListByKeyword: function() {
-      if (!this.keyword) {
-        return this.itemList
-      }
-      let itemListByKeyword = []
-      for (var i = 0; i < this.itemList.length; i++) {
-        if (this.itemList[i]['item_name'].indexOf(this.keyword) > -1) {
-          itemListByKeyword.push(this.itemList[i])
+  watch: {
+    // 监听搜索词的变化
+    keyword: function(val) {
+      if (val) {
+        // 当输入的字符只有一个长度的时候,是中文才会搜索。英文或者数字不会搜索
+        if (val && val.length == 1) {
+          // 验证是否是中文
+          var pattern = new RegExp('[\u4E00-\u9FA5]+')
+          if (pattern.test(val)) {
+            // alert('该字符串是中文')
+            this.showSearch = true
+          }
+        } else {
+          this.showSearch = true
         }
+      } else {
+        this.showSearch = false
       }
-      return itemListByKeyword
     }
   },
   methods: {

+ 116 - 0
web_src/src/components/item/Search.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="page">
+    <div class="resultList" v-for="item in resultList" :key="item.item_id">
+      <div v-for="page in item.pages" :key="page.page_id">
+        <hr />
+        <p class="title">
+          <router-link
+            :to="'/' + page.item_id + '?page_id=' + page.page_id"
+            tag="a"
+            target="_blank"
+            ><text-highlight :queries="queries"
+              >{{ page.item_name }} - {{ page.page_title }}</text-highlight
+            ></router-link
+          >
+        </p>
+        <p class="content">
+          <text-highlight :queries="queries">{{
+            page.search_content
+          }}</text-highlight>
+        </p>
+      </div>
+    </div>
+
+    <div v-if="showLoading" class="loading">
+      <i class="el-icon-loading"></i>
+    </div>
+  </div>
+</template>
+
+<script>
+import TextHighlight from 'vue-text-highlight'
+export default {
+  name: '',
+  components: { TextHighlight },
+  props: {
+    keyword: '',
+    itemList: []
+  },
+  data() {
+    return {
+      searchItemIds: [], // 要搜索的item_id们
+      resultList: [],
+      showLoading: false,
+      queries: []
+    }
+  },
+  watch: {
+    keyword: function(val) {
+      // 如果关键词发生变化,则先清空当前搜索队列,然后用itemList重新填充
+      this.searchItemIds = []
+      this.resultList = []
+      this.queries = []
+      this.queries.push(this.keyword)
+      this.itemList.forEach(element => {
+        this.searchItemIds.push(element.item_id)
+      })
+      this.search()
+    }
+  },
+  methods: {
+    search() {
+      this.showLoading = true
+      let item_id = this.searchItemIds.shift()
+      if (!item_id) {
+        this.showLoading = false
+        return false
+      }
+      this.request('/api/item/search', {
+        keyword: this.keyword,
+        item_id
+      }).then(data => {
+        let json = data.data
+        if (json && json.pages && json.pages.length > 0) {
+          this.resultList.push(json)
+        }
+        this.search()
+      })
+    }
+  },
+  mounted() {
+    this.queries = []
+    this.queries.push(this.keyword)
+    this.itemList.forEach(element => {
+      this.searchItemIds.push(element.item_id)
+    })
+    this.search()
+  },
+  beforeDestroy() {
+    this.searchItemIds = []
+  }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+.page {
+  margin-top: 20px;
+}
+.loading {
+  width: 50px;
+  margin: 0 auto;
+  font-size: 20px;
+}
+.resultList {
+  width: 85%;
+  margin: 0 auto;
+}
+.title {
+  font-size: 16px;
+  font-weight: bold;
+}
+.content {
+  margin-top: 20px;
+  margin-bottom: 20px;
+}
+</style>

+ 1 - 0
web_src/src/components/item/show/show_regular_item/LeftMenu.vue

@@ -33,6 +33,7 @@
           class="search-box"
           :clearable="true"
           @clear="search_item()"
+          size="medium"
           v-model="keyword"
         ></el-input>