yangchenggong1_wd

desc:同步 搜索主页(4.0)

Showing 21 changed files with 554 additions and 2 deletions
... ... @@ -177,6 +177,10 @@ export class HttpUrlUtils {
*/
static readonly SEARCH_HINT_DATA_PATH: string = "/api/rmrb-search-api/zh/c/hints";
/**
* 搜索主页 热词
*/
static readonly SEARCH_HOTS_DATA_PATH: string = "/api/rmrb-search-api/zh/c/hots";
/**
* 早晚报列表
* 根据页面id获取页面楼层列表
* https://pdapis.pdnews.cn/api/rmrb-bff-display-zh/display/zh/c/pageInfo?pageId=28927
... ... @@ -527,6 +531,11 @@ export class HttpUrlUtils {
return url
}
static getSearchHotsDataUrl() {
let url = HttpUrlUtils.HOST_SIT + HttpUrlUtils.SEARCH_HOTS_DATA_PATH
return url
}
// static getYcgCommonHeaders(): HashMap<string, string> {
... ...
... ... @@ -86,4 +86,6 @@ export class WDRouterPage {
//播报页面
static broadcastPage = new WDRouterPage("phone", "ets/pages/broadcast/BroadcastPage");
//搜索主页
static searchPage = new WDRouterPage("wdComponent", "ets/pages/SearchPage");
}
... ...
... ... @@ -4,6 +4,7 @@
* 方案一 使用动画 + 定时器
* 方案二 使用容器组件Swiper(当前)
*/
import { WDRouterPage, WDRouterRule } from 'wdRouter'
import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
const TAG = "FirstTabTopSearchComponent"
... ... @@ -56,6 +57,9 @@ export struct FirstTabTopSearchComponent{
.padding({left:15})
.backgroundImage($r('app.media.background_search'))
.backgroundImageSize(ImageSize.Cover)
.onClick(()=>{
WDRouterRule.jumpWithPage(WDRouterPage.searchPage)
})
}
}
\ No newline at end of file
... ...
import router from '@ohos.router'
import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
import { SearchHistoryItem } from '../../viewmodel/SearchHistoryItem'
import { SearchHistoryComponent } from './SearchHistoryComponent'
import { SearchHotsComponent } from './SearchHotsComponent'
const TAG = "SearchComponent"
@Component
export struct SearchComponent {
@State searchTextData: string[] = []
@State hasInputContent: boolean = false
@State hasChooseSearch: boolean = false
private swiperController: SwiperController = new SwiperController()
@State searchText: string = ''
controller: TextInputController = new TextInputController()
@State searchHistoryData: SearchHistoryItem[] = []
scroller: Scroller = new Scroller()
aboutToAppear() {
//获取提示滚动
this.getSearchHint()
//获取搜索历史
this.getSearchHistoryData()
}
getSearchHint() {
SearcherAboutDataModel.getSearchHintData(getContext(this)).then((value) => {
if (value != null) {
this.searchTextData = value
}
}).catch((err: Error) => {
console.log(TAG, JSON.stringify(err))
})
}
getSearchHistoryData() {
this.searchHistoryData = SearcherAboutDataModel.getSearchHistoryData()
}
build() {
Column() {
this.searchInputComponent()
if (!this.hasInputContent) {
Scroll(this.scroller) {
Column() {
SearchHistoryComponent({ searchHistoryData: $searchHistoryData })
//分隔符
Divider()
.width('100%')
.height('1lpx')
.color($r('app.color.color_EDEDED'))
.strokeWidth('1lpx')
SearchHotsComponent()
}
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
.padding({ left: '31lpx', right: '31lpx' })
} else {
if (this.hasChooseSearch) {
//搜索结果
//搜索结果为null(空布局 + 为你推荐)
} else {
//联想搜索
}
}
}.height('100%')
.width('100%')
}
//搜索框
@Builder searchInputComponent() {
Row() {
//左
Stack({ alignContent: Alignment.Start }) {
if (this.searchTextData != null && this.searchTextData.length > 0 && !this.hasInputContent) {
Swiper(this.swiperController) {
ForEach(this.searchTextData, (item: string, index: number) => {
Text(item)
.fontWeight('400lpx')
.fontSize('25lpx')
.fontColor($r('app.color.color_666666'))
.lineHeight('35lpx')
.textAlign(TextAlign.Start)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Clip })
.margin({ left: '40lpx' })
})
}
.loop(true)
.autoPlay(true)
.interval(3000)
.indicator(false)
.vertical(true)
.enabled(false)
.focusable(false)
}
TextInput({ text: this.searchText, placeholder: '', controller: this.controller })
.caretColor(Color.Pink)
.fontSize('27lpx')
.fontColor(Color.Black)
.onChange((value: string) => {
this.searchText = value
if (this.searchText.length > 0) {
this.hasInputContent = true
} else {
this.hasInputContent = false
}
})
.backgroundColor($r('app.color.color_transparent'))
}
.backgroundImage($r('app.media.search_page_input_bg'))
.backgroundImageSize(ImageSize.Cover)
.layoutWeight(1)
.height('69lpx')
//右
Text("取消")
.textAlign(TextAlign.Center)
.fontWeight('400lpx')
.fontSize('31lpx')
.lineHeight('58lpx')
.fontColor($r('app.color.color_222222'))
.width('125lpx')
.height('58lpx')
.onClick(() => {
router.back()
// SearcherAboutDataModel.putSearchHistoryData(this.searchText)
// if(StringUtils.isNotEmpty(this.searchText)){
// if(this.searchHistoryData.length===10){
// this.searchHistoryData.pop()
// }
// this.searchHistoryData.push(new SearchHistoryItem(this.searchText))
// }
})
}
.height('85lpx')
.padding({ left: '31lpx' })
.alignItems(VerticalAlign.Center)
.margin({ bottom: '36lpx' })
}
}
\ No newline at end of file
... ...
import { SearchHistoryItem } from '../../viewmodel/SearchHistoryItem'
/**
* 搜索历史
*/
@Component
export struct SearchHistoryComponent{
@Link searchHistoryData:SearchHistoryItem[]
build(){
Column(){
Row(){
Text("搜索历史")
.textAlign(TextAlign.Center)
.fontWeight('400lpx')
.fontSize('27lpx')
.lineHeight('38lpx')
.fontColor($r('app.color.color_999999'))
.height('38lpx')
Image($r('app.media.search_delete_icon'))
.height('31lpx')
.width('31lpx')
.interpolation(ImageInterpolation.High)
.objectFit(ImageFit.Cover)
.onClick(()=>{
//清空记录
})
}.justifyContent(FlexAlign.SpaceBetween)
.margin({bottom:'17lpx'})
.width('100%')
Grid(){
ForEach(this.searchHistoryData,(item:SearchHistoryItem,index:number)=>{
GridItem(){
Row(){
Text(`${item.searchContent}`)
.height('23lpx')
.fontColor($r('app.color.color_222222'))
.fontSize('23lpx')
.maxLines(1)
.constraintSize({maxWidth:index%2 === 0?'270lpx':'250lpx'})
.textOverflow({ overflow: TextOverflow.Ellipsis })
.textAlign(TextAlign.Start)
Image($r('app.media.search_item_delete_icon'))
.width('46lpx')
.height('46lpx')
.margin({right:'31lpx',left:'4lpx'})
.interpolation(ImageInterpolation.High)
.objectFit(ImageFit.Cover)
Blank()
if(index%2 === 0 && index != this.searchHistoryData.length-1 ){
Divider()
.width('2lpx')
.height('23lpx')
.color($r('app.color.color_CCCCCC'))
.strokeWidth('2lpx')
.vertical(true)
}
}.height('100%')
.alignItems(VerticalAlign.Center)
.width('100%')
.margin({left:index%2 === 1?'23lpx':'0lpx'})
}.onClick(()=>{
})
.height('46lpx')
})
}
.height(this.getCategoryViewHeight())
.rowsTemplate(this.getCategoryRowTmpl())
.columnsTemplate('1fr 1fr')
.rowsGap('23lpx')
}
.margin({bottom:'46lpx'})
}
getCategoryRowCount() {
return Math.ceil(this.searchHistoryData.length / 2);
}
getCategoryRowTmpl() {
const count = this.getCategoryRowCount();
const arr: string[] = new Array(count || 1).fill('1fr');
console.log('tmpl ', arr.join(' '))
return arr.join(' ');
}
getCategoryViewHeight() {
return `${46 * this.getCategoryRowCount()}lpx`;
}
}
\ No newline at end of file
... ...
import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
import { SearchHotContentItem } from '../../viewmodel/SearchHotContentItem'
const TAG = "SearchHotsComponent"
/**
* 热门搜索
*/
@Component
export struct SearchHotsComponent{
@State searchHotsData:SearchHotContentItem[] = []
aboutToAppear(){
//获取搜索热词
this.getSearchHotsData()
}
getSearchHotsData(){
SearcherAboutDataModel.getSearchHotsData(getContext(this)).then((value)=>{
if(value!=null){
this.searchHotsData = value
}
}).catch((err:Error)=>{
console.log(TAG,JSON.stringify(err))
})
}
build(){
Column(){
Row() {
Image($r('app.media.search_hot_icon'))
.width('46lpx')
.height('46lpx')
.objectFit(ImageFit.Auto)
.margin({right:'8lpx'})
.interpolation(ImageInterpolation.Medium)
Text("热门搜索")
.textAlign(TextAlign.Center)
.fontWeight('600lpx')
.fontSize('33lpx')
.lineHeight('46lpx')
.fontColor($r('app.color.color_222222'))
.height('38lpx')
}
.width('100%')
List(){
ForEach(this.searchHotsData,(item:SearchHotContentItem,index:number)=>{
ListItem(){
Column(){
Column(){
Row(){
Row(){
if(item.sequence <=3){
Image(item.sequence===1?$r('app.media.search_hot_num1'):item.sequence===2?$r('app.media.search_hot_num2'):$r('app.media.search_hot_num3'))
.width('27lpx')
.height('35lpx')
.objectFit(ImageFit.Auto)
.margin({right:'12lpx'})
.interpolation(ImageInterpolation.High)
}else {
Text(`${item.sequence}`)
.height('31lpx')
.fontColor($r('app.color.color_666666'))
.fontSize('27lpx')
.fontWeight('400lpx')
.lineHeight('31lpx')
.margin({right:'12lpx'})
}
Text(`${item.hotEntry}`)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.fontColor($r('app.color.color_222222'))
.fontSize('31lpx')
.maxLines(1)
.fontWeight('400lpx')
.lineHeight('42lpx')
}.layoutWeight(1)
if(item.mark!=0){
Image(item.mark===1?$r('app.media.search_hots_mark1'):$r('app.media.search_hots_mark2'))
.width('42lpx')
.height('31lpx')
.objectFit(ImageFit.Auto)
.interpolation(ImageInterpolation.High)
}
}.alignItems(VerticalAlign.Center)
.height('84lpx')
.justifyContent(FlexAlign.SpaceBetween)
if(index != this.searchHotsData.length-1 ){
Divider()
.width('100%')
.height('1lpx')
.color($r('app.color.color_F5F5F5'))
.strokeWidth('1lpx')
}
}.height('108lpx')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
.padding({left:'27lpx'})
}
}
.onClick(()=>{
})
.height('117lpx')
})
}.onScrollFrameBegin((offset, state) => {
return { offsetRemain: 0 }
}).layoutWeight(1)
}.width('100%')
.height('100%')
.margin({top:'46lpx'})
}
}
\ No newline at end of file
... ...
import { Logger, ResourcesUtils } from 'wdKit';
import { Logger, ResourcesUtils, UserDataLocal } from 'wdKit';
import { HttpUrlUtils, ResponseDTO, WDHttp } from 'wdNetwork';
import HashMap from '@ohos.util.HashMap';
import { SearchHistoryItem } from '../viewmodel/SearchHistoryItem';
import { SearchHotContentItem } from '../viewmodel/SearchHotContentItem';
const TAG = "SearcherAboutDataModel"
/**
... ... @@ -9,6 +12,7 @@ const TAG = "SearcherAboutDataModel"
*/
class SearcherAboutDataModel{
private static instance: SearcherAboutDataModel;
searchHistoryData:SearchHistoryItem[] = []
private constructor() { }
... ... @@ -24,6 +28,53 @@ class SearcherAboutDataModel{
}
/**
* 静态搜索历史记录
*/
getSearchHistoryData():SearchHistoryItem[]{
if(this.searchHistoryData.length > 0){
return this.searchHistoryData
}
this.searchHistoryData.push(new SearchHistoryItem("评论",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("关注关注",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("收藏收藏收藏",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("历史",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("消息消息消息消息消息",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("留言板留言板留言板留言板留言板",UserDataLocal.userId,""))
this.searchHistoryData.push(new SearchHistoryItem("预约",UserDataLocal.userId,""))
return this.searchHistoryData
}
// async putSearchHistoryData(content:string){
// let history = await SPHelper.default.get(SearcherAboutDataModel.SEARCH_HISTORY_KEY, '[]') as string;
// this.searchHistoryData = JSON.parse(history)
// this.searchHistoryData.push(new SearchHistoryItem(content))
// await SPHelper.default.save(SearcherAboutDataModel.SEARCH_HISTORY_KEY, JSON.stringify(this.searchHistoryData));
// }
// getSearchHistoryData():Promise<SearchHistoryItem[]>{
// return new Promise<SearchHistoryItem[]>(async (success, error) => {
// if(this.searchHistoryData!=null && this.searchHistoryData.length>0){
// success(this.searchHistoryData)
// return
// }
// try {
// let history = await SPHelper.default.get(SearcherAboutDataModel.SEARCH_HISTORY_KEY, '') as string;
// console.log('ycg',history);
// }catch (error){
// console.log('ycg',"1111");
// }
//
// this.searchHistoryData = JSON.parse(history)
// this.searchHistoryData.push(new SearchHistoryItem("评论"))
// this.searchHistoryData.push(new SearchHistoryItem("关注关注"))
// this.searchHistoryData.push(new SearchHistoryItem("收藏收藏收藏"))
//
// success(this.searchHistoryData)
// })
// }
/**
* 首页 搜索提示滚动内容
*/
getSearchHintData(context: Context): Promise<string[]> {
... ... @@ -62,6 +113,43 @@ class SearcherAboutDataModel{
}
/**
* 搜索主页 热词
*/
getSearchHotsData(context: Context): Promise<SearchHotContentItem[]> {
return new Promise<SearchHotContentItem[]>((success, error) => {
Logger.info(TAG, `getSearchHintData start`);
this.fetchSearchHotsData().then((navResDTO: ResponseDTO<SearchHotContentItem[]>) => {
if (!navResDTO || navResDTO.code != 0) {
success(this.getSearchHotsDataLocal(context))
return
}
Logger.info(TAG, "getSearchHotsData then,getSearchHotsData.timeStamp:" + navResDTO.timestamp);
let navigationBean = navResDTO.data as SearchHotContentItem[]
success(navigationBean);
}).catch((err: Error) => {
Logger.error(TAG, `getSearchHotsData catch, error.name : ${err.name}, error.message:${err.message}`);
success(this.getSearchHotsDataLocal(context))
})
})
}
fetchSearchHotsData() {
let url = HttpUrlUtils.getSearchHotsDataUrl()
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return WDHttp.get<ResponseDTO<SearchHotContentItem[]>>(url, headers)
};
async getSearchHotsDataLocal(context: Context): Promise<SearchHotContentItem[]> {
Logger.info(TAG, `getSearchHotsDataLocal start`);
let compRes: ResponseDTO<SearchHotContentItem[]> | null = await ResourcesUtils.getResourcesJson<ResponseDTO<SearchHotContentItem[]>>(context,'search_hots_data.json' ,);
if (!compRes || !compRes.data) {
Logger.info(TAG, `getSearchHotsDataLocal compRes is empty`);
return []
}
Logger.info(TAG, `getSearchHotsDataLocal compRes : ${JSON.stringify(compRes)}`);
return compRes.data
}
}
... ...
import { SearchComponent } from '../components/search/SearchComponent'
@Entry
@Component
struct SearchPage {
build() {
Column(){
SearchComponent()
}.height('100%')
.width('100%')
}
}
\ No newline at end of file
... ...
export class SearchHistoryItem{
searchContent:string = ""
searchUserId:string = ""
searchTime:string = ""
constructor(searchContent: string,searchUserId:string,searchTime:string) {
this.searchContent = searchContent
this.searchUserId = searchUserId
this.searchTime = searchTime
}
}
\ No newline at end of file
... ...
export class SearchHotContentItem{
hotEntry:string = ""
mark:number = 0 //1 热 2 新
sequence:number = 0//序号
constructor(hotEntry: string , mark: number , sequence: number ) {
this.hotEntry = hotEntry
this.mark = mark
this.sequence = sequence
}
}
\ No newline at end of file
... ...
... ... @@ -12,6 +12,7 @@
"components/page/EditUserIntroductionPage",
"components/page/BrowsingHistoryPage",
"components/page/MyCollectionListPage",
"pages/OtherNormalUserHomePage"
"pages/OtherNormalUserHomePage",
"pages/SearchPage"
]
}
\ No newline at end of file
... ...
{
"code": "0",
"data": [
{
"hotEntry": "习语",
"mark": 1,
"sequence": 1
},
{
"hotEntry": "党史学习教育工作",
"mark": 1,
"sequence": 2
},
{
"hotEntry": "2024年全国两会新闻中心启用",
"mark": 1,
"sequence": 3
},
{
"hotEntry": "第二艘国产大型邮轮后年底交付",
"mark": 0,
"sequence": 4
},
{
"hotEntry": "268名跨境电诈犯罪嫌疑人移交",
"mark": 0,
"sequence": 5
},
{
"hotEntry": "高考倒计时100天",
"mark": 2,
"sequence": 6
},
{
"hotEntry": "日本开始第四轮核污染水排放",
"mark": 0,
"sequence": 7
},
{
"hotEntry": "国台办点名管碧玲",
"mark": 0,
"sequence": 8
},
{
"hotEntry": "美方称不会向乌克兰派兵",
"mark": 2,
"sequence": 9
},
{
"hotEntry": "电动车乱停乱充电",
"mark": 2,
"sequence": 10
}
],
"message": "Success",
"success": true,
"timestamp": 1712631086296
}
\ No newline at end of file
... ...