yangchenggong1_wd

desc:搜索联想和 串联逻辑处理

@@ -180,6 +180,11 @@ export class HttpUrlUtils { @@ -180,6 +180,11 @@ export class HttpUrlUtils {
180 * 搜索主页 热词 180 * 搜索主页 热词
181 */ 181 */
182 static readonly SEARCH_HOTS_DATA_PATH: string = "/api/rmrb-search-api/zh/c/hots"; 182 static readonly SEARCH_HOTS_DATA_PATH: string = "/api/rmrb-search-api/zh/c/hots";
  183 +
  184 + /**
  185 + * 搜索联想词
  186 + */
  187 + static readonly RELATED_SEARCH_CONTENT_DATA_PATH: string = "/api/rmrb-search-api/zh/c/suggestions/";
183 /** 188 /**
184 * 早晚报列表 189 * 早晚报列表
185 * 根据页面id获取页面楼层列表 190 * 根据页面id获取页面楼层列表
@@ -536,6 +541,10 @@ export class HttpUrlUtils { @@ -536,6 +541,10 @@ export class HttpUrlUtils {
536 return url 541 return url
537 } 542 }
538 543
  544 + static getRelatedSearchContentDataUrl() {
  545 + let url = HttpUrlUtils._hostUrl + HttpUrlUtils.RELATED_SEARCH_CONTENT_DATA_PATH
  546 + return url
  547 + }
539 548
540 549
541 // static getYcgCommonHeaders(): HashMap<string, string> { 550 // static getYcgCommonHeaders(): HashMap<string, string> {
@@ -39,6 +39,7 @@ export struct FirstTabTopSearchComponent { @@ -39,6 +39,7 @@ export struct FirstTabTopSearchComponent {
39 Image($r('app.media.icon_search')) 39 Image($r('app.media.icon_search'))
40 .width(18) 40 .width(18)
41 .height(18) 41 .height(18)
  42 + .margin({right:'10lpx'})
42 43
43 if (this.searchTextData != null && this.searchTextData.length > 0) { 44 if (this.searchTextData != null && this.searchTextData.length > 0) {
44 Swiper(this.swiperController) { 45 Swiper(this.swiperController) {
@@ -58,6 +59,8 @@ export struct FirstTabTopSearchComponent { @@ -58,6 +59,8 @@ export struct FirstTabTopSearchComponent {
58 .indicator(false) 59 .indicator(false)
59 .vertical(true) 60 .vertical(true)
60 .height(30) 61 .height(30)
  62 + .enabled(false)
  63 + .focusable(false)
61 } 64 }
62 } 65 }
63 .height(30) 66 .height(30)
@@ -2,8 +2,10 @@ import router from '@ohos.router' @@ -2,8 +2,10 @@ import router from '@ohos.router'
2 import { StringUtils, ToastUtils } from 'wdKit' 2 import { StringUtils, ToastUtils } from 'wdKit'
3 import SearcherAboutDataModel from '../../model/SearcherAboutDataModel' 3 import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
4 import { SearchHistoryItem } from '../../viewmodel/SearchHistoryItem' 4 import { SearchHistoryItem } from '../../viewmodel/SearchHistoryItem'
  5 +import { SearchRelatedItem } from '../../viewmodel/SearchRelatedItem'
5 import { SearchHistoryComponent } from './SearchHistoryComponent' 6 import { SearchHistoryComponent } from './SearchHistoryComponent'
6 import { SearchHotsComponent } from './SearchHotsComponent' 7 import { SearchHotsComponent } from './SearchHotsComponent'
  8 +import { SearchRelatedComponent } from './SearchRelatedComponent'
7 9
8 const TAG = "SearchComponent" 10 const TAG = "SearchComponent"
9 11
@@ -12,10 +14,14 @@ export struct SearchComponent { @@ -12,10 +14,14 @@ export struct SearchComponent {
12 @State searchTextData: string[] = [] 14 @State searchTextData: string[] = []
13 @State hasInputContent: boolean = false 15 @State hasInputContent: boolean = false
14 @State hasChooseSearch: boolean = false 16 @State hasChooseSearch: boolean = false
  17 + @State isClickedHistory: boolean = false
  18 + @State isClickedHot: boolean = false
  19 + @State isClickedRelated: boolean = false
15 private swiperController: SwiperController = new SwiperController() 20 private swiperController: SwiperController = new SwiperController()
16 @State searchText: string = '' 21 @State searchText: string = ''
17 controller: TextInputController = new TextInputController() 22 controller: TextInputController = new TextInputController()
18 @State searchHistoryData: SearchHistoryItem[] = [] 23 @State searchHistoryData: SearchHistoryItem[] = []
  24 + @State relatedSearchContentsData: SearchRelatedItem[] = []
19 scroller: Scroller = new Scroller() 25 scroller: Scroller = new Scroller()
20 26
21 aboutToAppear() { 27 aboutToAppear() {
@@ -25,7 +31,41 @@ export struct SearchComponent { @@ -25,7 +31,41 @@ export struct SearchComponent {
25 this.getSearchHistoryData() 31 this.getSearchHistoryData()
26 } 32 }
27 33
28 - 34 + getRelatedSearchContent() {
  35 + if(StringUtils.isNotEmpty(this.searchText)){
  36 + SearcherAboutDataModel.getRelatedSearchContentData(encodeURI(this.searchText),getContext(this)).then((value) => {
  37 + if (value != null) {
  38 + this.relatedSearchContentsData = []
  39 + value.forEach(item=>{
  40 + let tempValue:string = item
  41 + let tempArr: string[] = []
  42 + if (tempValue.indexOf(this.searchText) === -1) {
  43 + tempArr.push(item)
  44 + this.relatedSearchContentsData.push(new SearchRelatedItem(item,tempArr))
  45 + }else {
  46 + while (tempValue.indexOf(this.searchText) != -1){
  47 + let index = tempValue.indexOf(this.searchText)
  48 + if(index === 0){
  49 + tempArr.push(this.searchText)
  50 + tempValue = tempValue.substring(this.searchText.length,tempValue.length)
  51 + }else {
  52 + tempArr.push(tempValue.substring(0,index))
  53 + tempArr.push(this.searchText)
  54 + tempValue = tempValue.substring(index+this.searchText.length,tempValue.length)
  55 + }
  56 + }
  57 + if(StringUtils.isNotEmpty(tempValue)){
  58 + tempArr.push(tempValue)
  59 + }
  60 + this.relatedSearchContentsData.push(new SearchRelatedItem(item,tempArr))
  61 + }
  62 + })
  63 + }
  64 + }).catch((err: Error) => {
  65 + console.log(TAG, JSON.stringify(err))
  66 + })
  67 + }
  68 + }
29 69
30 getSearchHint() { 70 getSearchHint() {
31 SearcherAboutDataModel.getSearchHintData(getContext(this)).then((value) => { 71 SearcherAboutDataModel.getSearchHintData(getContext(this)).then((value) => {
@@ -48,7 +88,7 @@ export struct SearchComponent { @@ -48,7 +88,7 @@ export struct SearchComponent {
48 Scroll(this.scroller) { 88 Scroll(this.scroller) {
49 Column() { 89 Column() {
50 if(this.searchHistoryData!=null && this.searchHistoryData.length>0){ 90 if(this.searchHistoryData!=null && this.searchHistoryData.length>0){
51 - SearchHistoryComponent({ searchHistoryData: $searchHistoryData, onDelHistory: (): void => this.getSearchHistoryData() }) 91 + SearchHistoryComponent({ searchHistoryData: $searchHistoryData, onDelHistory: (): void => this.getSearchHistoryData(),onGetSearchRes: (item,index): void => this.getSearchHistoryResData(item,index) })
52 } 92 }
53 93
54 //分隔符 94 //分隔符
@@ -58,7 +98,7 @@ export struct SearchComponent { @@ -58,7 +98,7 @@ export struct SearchComponent {
58 .color($r('app.color.color_EDEDED')) 98 .color($r('app.color.color_EDEDED'))
59 .strokeWidth('1lpx') 99 .strokeWidth('1lpx')
60 100
61 - SearchHotsComponent() 101 + SearchHotsComponent({onGetSearchRes: (item): void => this.getSearchHotResData(item)})
62 } 102 }
63 } 103 }
64 .scrollable(ScrollDirection.Vertical) 104 .scrollable(ScrollDirection.Vertical)
@@ -66,19 +106,68 @@ export struct SearchComponent { @@ -66,19 +106,68 @@ export struct SearchComponent {
66 .width('100%') 106 .width('100%')
67 .height('100%') 107 .height('100%')
68 .padding({ left: '31lpx', right: '31lpx' }) 108 .padding({ left: '31lpx', right: '31lpx' })
  109 + .margin({ top: '36lpx' })
69 } else { 110 } else {
70 if (this.hasChooseSearch) { 111 if (this.hasChooseSearch) {
71 //搜索结果 112 //搜索结果
72 113
73 //搜索结果为null(空布局 + 为你推荐) 114 //搜索结果为null(空布局 + 为你推荐)
  115 +
74 } else { 116 } else {
75 //联想搜索 117 //联想搜索
  118 + SearchRelatedComponent({relatedSearchContentData:$relatedSearchContentsData,onGetSearchRes: (item): void => this.getSearchRelatedResData(item),searchText:this.searchText})
76 } 119 }
77 } 120 }
78 }.height('100%') 121 }.height('100%')
79 .width('100%') 122 .width('100%')
80 } 123 }
81 124
  125 +
  126 + /**
  127 + * 点击搜索记录列表回调
  128 + * @param content
  129 + */
  130 + getSearchHistoryResData(content:string,index:number){
  131 + //删除单挑记录
  132 + SearcherAboutDataModel.delSearchSingleHistoryData(index)
  133 + this.isClickedHistory = true
  134 + this.searchResData(content)
  135 + }
  136 +
  137 + searchResData(content:string){
  138 + //赋值
  139 + this.searchText = content
  140 + //保存搜索记录
  141 + SearcherAboutDataModel.putSearchHistoryData(this.searchText)
  142 + //获取搜索记录
  143 + this.getSearchHistoryData()
  144 + //清空 联想记录
  145 + this.relatedSearchContentsData = []
  146 +
  147 + //查询 操作 TODO
  148 +
  149 + }
  150 +
  151 +
  152 + /**
  153 + * 点击联想搜索列表回调
  154 + * @param content
  155 + */
  156 + getSearchRelatedResData(content:string){
  157 + this.isClickedRelated = true
  158 + this.searchResData(content)
  159 + }
  160 +
  161 + /**
  162 + * 点击热词搜索列表回调
  163 + * @param content
  164 + */
  165 + getSearchHotResData(content:string){
  166 + this.isClickedHot = true
  167 + this.searchResData(content)
  168 + }
  169 +
  170 +
82 //搜索框 171 //搜索框
83 @Builder searchInputComponent() { 172 @Builder searchInputComponent() {
84 Row() { 173 Row() {
@@ -119,6 +208,13 @@ export struct SearchComponent { @@ -119,6 +208,13 @@ export struct SearchComponent {
119 } else { 208 } else {
120 this.hasInputContent = false 209 this.hasInputContent = false
121 } 210 }
  211 + if(this.isClickedHistory || this.isClickedHot || this.isClickedRelated){
  212 + this.isClickedHistory = false
  213 + this.isClickedHot = false
  214 + this.isClickedRelated = false
  215 + }else{
  216 + this.getRelatedSearchContent()
  217 + }
122 }) 218 })
123 .backgroundColor($r('app.color.color_transparent')) 219 .backgroundColor($r('app.color.color_transparent'))
124 .defaultFocus(true) 220 .defaultFocus(true)
@@ -166,6 +262,5 @@ export struct SearchComponent { @@ -166,6 +262,5 @@ export struct SearchComponent {
166 .height('85lpx') 262 .height('85lpx')
167 .padding({ left: '31lpx' }) 263 .padding({ left: '31lpx' })
168 .alignItems(VerticalAlign.Center) 264 .alignItems(VerticalAlign.Center)
169 - .margin({ bottom: '36lpx' })  
170 } 265 }
171 } 266 }
@@ -9,6 +9,7 @@ import { MyCustomDialog } from '../reusable/MyCustomDialog' @@ -9,6 +9,7 @@ import { MyCustomDialog } from '../reusable/MyCustomDialog'
9 export struct SearchHistoryComponent{ 9 export struct SearchHistoryComponent{
10 @Link searchHistoryData:SearchHistoryItem[] 10 @Link searchHistoryData:SearchHistoryItem[]
11 onDelHistory?: () => void; 11 onDelHistory?: () => void;
  12 + onGetSearchRes?: (item:string,index:number) => void;
12 dialogController: CustomDialogController = new CustomDialogController({ 13 dialogController: CustomDialogController = new CustomDialogController({
13 builder: MyCustomDialog({ 14 builder: MyCustomDialog({
14 cancel: this.onCancel, 15 cancel: this.onCancel,
@@ -70,16 +71,22 @@ export struct SearchHistoryComponent{ @@ -70,16 +71,22 @@ export struct SearchHistoryComponent{
70 .fontWeight('400lpx') 71 .fontWeight('400lpx')
71 .lineHeight('46lpx') 72 .lineHeight('46lpx')
72 .maxLines(1) 73 .maxLines(1)
73 - .constraintSize({maxWidth:index%2 === 0?'270lpx':'250lpx'}) 74 + .constraintSize({maxWidth:index%2 === 0?'270lpx':'230lpx'})
74 .textOverflow({ overflow: TextOverflow.Ellipsis }) 75 .textOverflow({ overflow: TextOverflow.Ellipsis })
75 .textAlign(TextAlign.Start) 76 .textAlign(TextAlign.Start)
  77 + .margin({left:index%2 === 0?'0lpx':'23lpx'})
  78 + .onClick(()=>{
  79 + if (this.onGetSearchRes !== undefined) {
  80 + this.onGetSearchRes(item.searchContent,index)
  81 + }
  82 + })
76 83
77 Image($r('app.media.search_item_delete_icon')) 84 Image($r('app.media.search_item_delete_icon'))
78 - .width('46lpx')  
79 - .height('46lpx')  
80 - .margin({right:'31lpx',left:'4lpx'})  
81 - .interpolation(ImageInterpolation.High)  
82 - .objectFit(ImageFit.Cover) 85 + .width('23lpx')
  86 + .height('23lpx')
  87 + .margin({left:'4lpx'})
  88 + .interpolation(ImageInterpolation.Medium)
  89 + .objectFit(ImageFit.Auto)
83 .onClick(()=>{ 90 .onClick(()=>{
84 SearcherAboutDataModel.delSearchSingleHistoryData(index) 91 SearcherAboutDataModel.delSearchSingleHistoryData(index)
85 if (this.onDelHistory !== undefined) { 92 if (this.onDelHistory !== undefined) {
@@ -101,9 +108,11 @@ export struct SearchHistoryComponent{ @@ -101,9 +108,11 @@ export struct SearchHistoryComponent{
101 .alignItems(VerticalAlign.Center) 108 .alignItems(VerticalAlign.Center)
102 .width('100%') 109 .width('100%')
103 .margin({left:index%2 === 1?'23lpx':'0lpx'}) 110 .margin({left:index%2 === 1?'23lpx':'0lpx'})
104 - }.onClick(()=>{  
105 - }) 111 +
  112 + }
106 .height('46lpx') 113 .height('46lpx')
  114 + .alignSelf(ItemAlign.Center)
  115 +
107 }) 116 })
108 } 117 }
109 .height(this.getCategoryViewHeight()) 118 .height(this.getCategoryViewHeight())
@@ -9,6 +9,7 @@ const TAG = "SearchHotsComponent" @@ -9,6 +9,7 @@ const TAG = "SearchHotsComponent"
9 @Component 9 @Component
10 export struct SearchHotsComponent{ 10 export struct SearchHotsComponent{
11 @State searchHotsData:SearchHotContentItem[] = [] 11 @State searchHotsData:SearchHotContentItem[] = []
  12 + onGetSearchRes?: (item:string) => void;
12 13
13 aboutToAppear(){ 14 aboutToAppear(){
14 //获取搜索热词 15 //获取搜索热词
@@ -101,6 +102,9 @@ export struct SearchHotsComponent{ @@ -101,6 +102,9 @@ export struct SearchHotsComponent{
101 } 102 }
102 } 103 }
103 .onClick(()=>{ 104 .onClick(()=>{
  105 + if (this.onGetSearchRes !== undefined) {
  106 + this.onGetSearchRes(item.hotEntry)
  107 + }
104 }) 108 })
105 .height('117lpx') 109 .height('117lpx')
106 }) 110 })
  1 +import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
  2 +import { SearchHotContentItem } from '../../viewmodel/SearchHotContentItem'
  3 +import { SearchRelatedItem } from '../../viewmodel/SearchRelatedItem'
  4 +
  5 +const TAG = "SearchRelatedComponent"
  6 +
  7 +/**
  8 + * 热门搜索
  9 + */
  10 +@Component
  11 +export struct SearchRelatedComponent {
  12 + @Link relatedSearchContentData: SearchRelatedItem[]
  13 + onGetSearchRes?: (item:string) => void;
  14 + @Prop searchText: string
  15 +
  16 + build() {
  17 + Column() {
  18 + List() {
  19 + ForEach(this.relatedSearchContentData, (item: SearchRelatedItem, index: number) => {
  20 + ListItem() {
  21 + Column(){
  22 + Row() {
  23 + Image($r('app.media.search_related_item_icon'))
  24 + .width('31lpx')
  25 + .height('31lpx')
  26 + .objectFit(ImageFit.Auto)
  27 + .margin({ right: '10lpx' })
  28 + .interpolation(ImageInterpolation.High)
  29 +
  30 + Text(){
  31 + ForEach(item.data_arr,(item:string)=>{
  32 + Span(item)
  33 + .fontColor(item===this.searchText?$r('app.color.color_ED2800'):$r('app.color.color_000000'))
  34 + .fontSize('31lpx')
  35 + .fontWeight('400lpx')
  36 + .lineHeight('50lpx')
  37 + })
  38 + }
  39 + .maxLines(1)
  40 + .textOverflow({ overflow: TextOverflow.Ellipsis })
  41 + .layoutWeight(1)
  42 +
  43 + }.alignItems(VerticalAlign.Center)
  44 + .justifyContent(FlexAlign.Start)
  45 + .height('95lpx')
  46 +
  47 + if (index != this.relatedSearchContentData.length - 1) {
  48 + Divider()
  49 + .width('100%')
  50 + .height('1lpx')
  51 + .color($r('app.color.color_F5F5F5'))
  52 + .strokeWidth('1lpx')
  53 + }
  54 + }
  55 + }.width('100%')
  56 + .onClick(()=>{
  57 + if (this.onGetSearchRes !== undefined) {
  58 + this.onGetSearchRes(item.data_string)
  59 + }
  60 + })
  61 + })
  62 + }.width('100%')
  63 + }.width('100%')
  64 + .margin({ top: '8lpx' })
  65 + .padding({ left: '31lpx', right: '31lpx' })
  66 + }
  67 +
  68 + test(){
  69 + let c = "12121212121"
  70 +
  71 + }
  72 +}
@@ -156,6 +156,46 @@ class SearcherAboutDataModel{ @@ -156,6 +156,46 @@ class SearcherAboutDataModel{
156 return compRes.data 156 return compRes.data
157 } 157 }
158 158
  159 +
  160 + /**
  161 + * 搜索 联想词
  162 + */
  163 + getRelatedSearchContentData(keyword:string,context: Context): Promise<string[]> {
  164 + return new Promise<string[]>((success, error) => {
  165 + Logger.info(TAG, `getSearchHintData start`);
  166 + this.fetchRelatedSearchContentData(keyword).then((navResDTO: ResponseDTO<string[]>) => {
  167 + if (!navResDTO || navResDTO.code != 0) {
  168 + success(this.getRelatedSearchContentDataLocal(context))
  169 + return
  170 + }
  171 + Logger.info(TAG, "getSearchHintData then,SearchHintDataResDTO.timeStamp:" + navResDTO.timestamp);
  172 + let navigationBean = navResDTO.data as string[]
  173 + success(navigationBean);
  174 + }).catch((err: Error) => {
  175 + Logger.error(TAG, `fetchSearchHintData catch, error.name : ${err.name}, error.message:${err.message}`);
  176 + success(this.getRelatedSearchContentDataLocal(context))
  177 + })
  178 + })
  179 + }
  180 +
  181 + fetchRelatedSearchContentData(keyword:string) {
  182 + let url = HttpUrlUtils.getRelatedSearchContentDataUrl()+ keyword
  183 + let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
  184 + return WDHttp.get<ResponseDTO<string[]>>(url, headers)
  185 + };
  186 +
  187 + async getRelatedSearchContentDataLocal(context: Context): Promise<string[]> {
  188 + Logger.info(TAG, `getSearchHintDataLocal start`);
  189 + let compRes: ResponseDTO<string[]> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<string[]>>(context,'search_related_data_nimen.json' );
  190 + if (!compRes || !compRes.data) {
  191 + Logger.info(TAG, `getSearchHintDataLocal compRes is empty`);
  192 + return []
  193 + }
  194 + Logger.info(TAG, `getSearchHintDataLocal compRes : ${JSON.stringify(compRes)}`);
  195 + return compRes.data
  196 + }
  197 +
  198 +
159 } 199 }
160 200
161 const searcherAboutDataModel = SearcherAboutDataModel.getInstance() 201 const searcherAboutDataModel = SearcherAboutDataModel.getInstance()
  1 +export class SearchRelatedItem{
  2 + data_arr: string[] = []
  3 + data_string: string = ""
  4 +
  5 + constructor(data_string: string,data_arr: string[]) {
  6 + this.data_arr = data_arr
  7 + this.data_string = data_string
  8 + }
  9 +}
@@ -135,6 +135,10 @@ @@ -135,6 +135,10 @@
135 { 135 {
136 "name": "color_48505A", 136 "name": "color_48505A",
137 "value": "#48505A" 137 "value": "#48505A"
  138 + },
  139 + {
  140 + "name": "color_000000",
  141 + "value": "#000000"
138 } 142 }
139 ] 143 ]
140 } 144 }
  1 +{
  2 + "code": "0",
  3 + "data": [
  4 + "你们到底喜欢什么颜色的包包?说红色难搭配黑色没特点绿色又觉得",
  5 + "你们太帅了!货车起火6辆车紧急停下帮忙",
  6 + "你们家的除螨仪真的能除螨吗?听听专业人士怎么说",
  7 + "你们辛苦了!85岁 老奶奶亲手缝300双鞋垫送消防员",
  8 + "你们都是最棒的!中国队88枚奖牌收官",
  9 + "你们平安我们放心!广西玉林地震,中学生操场避险集体大合唱",
  10 + "你们也要保护好自己!男孩花掉多年攒的压岁钱,买口罩送民警",
  11 + "你们“灰头土脸”的样子,真帅!",
  12 + "你们的样子真美!路遇老人身体不适 五名女大学生护送就医",
  13 + "你们都在看Mate 30,我却被老干妈洗脑了:这广告比华为还"
  14 +
  15 + ],
  16 + "message": "Success",
  17 + "success": true,
  18 + "timestamp": 1712803812695
  19 +}