• 发文章

  • 发资料

  • 发帖

  • 提问

  • 发视频

创作活动
0
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
返回

电子发烧友 电子发烧友

  • 全文搜索
    • 全文搜索
    • 标题搜索
  • 全部时间
    • 全部时间
    • 1小时内
    • 1天内
    • 1周内
    • 1个月内
  • 默认排序
    • 默认排序
    • 按时间排序
大家还在搜
  • 鲜生“出事”了?鲜生拒收现金,央行称此行为涉嫌违法,阿里这样回应

    之所以火爆,是因为它真正的解决了消费者的痛点,在物流配送、体验互动、品质把控等方面做到了世界顶尖水平。在卖场拥有3000个SKU大约是MUJI的十倍;利用高科技

    2017-08-16 09:14

  • 智能机器人餐厅问世!

    首届中国国际进口博览会将在上海开幕,带来了首次面世的2.0版的机器人餐厅。顾客在店内可以体验到机器人送餐的服务,你要不要来尝试一下?

    2018-10-19 10:23

  • 成阿里应对美团、京东、拼多多挑战的棋子?

    2015年底,在上海世纪公园旁的一家酒店,一位曾经在阿里任职多年的人严肃地说:不是老菜(侯毅)的,而是逍遥子(张勇)的,这是理解

    2020-12-18 16:41

  • 《仿》app开发技术分享-- 首页活动配置(5)

    技术栈 Appgallery connect 开发准备 上一篇文章中我们实现了项目端云一体化首页部分模块动态配置,实现了对模块模块的后端控制显示和隐藏,这能让我们的app更加的灵活,也能应对更多的情况。现在我们来对配置模块进行完善,除了已有的模块以外,我们还有一些banner ,活动入口等模块,这些模块的数据并不多,所以我们也归纳到配置中去实现。并且我们在配置表中添加了一些不同的id,我们只需要根据相对应的id 去查询对应的表就可以了 代码实现 实现横幅海报,商品活动入口 创建海报横幅表 { \"objectTypeName\": \"home_poster\", \"fields\": [ {\"fieldName\": \"id\", \"fieldType\": \"Integer\", \"notNull\": true, \"belongPrimaryKey\": true}, {\"fieldName\": \"poster_id\", \"fieldType\": \"Integer\", \"notNull\": true, \"defaultValue\": 0}, {\"fieldName\": \"url\", \"fieldType\": \"String\"}, {\"fieldName\": \"router\", \"fieldType\": \"String\"} ], \"indexes\": [ {\"indexName\": \"posterIdIndex\", \"indexList\": [{\"fieldName\":\"poster_id\",\"sortType\":\"ASC\"}]} ], \"permissions\": [ {\"role\": \"World\", \"rights\": [\"Read\"]}, {\"role\": \"Authenticated\", \"rights\": [\"Read\", \"Upsert\"]}, {\"role\": \"Creator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]}, {\"role\": \"Administrator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]} ] } 创建商品活动入口表 { \"objectTypeName\": \"home_good_center\", \"fields\": [ {\"fieldName\": \"id\", \"fieldType\": \"Integer\", \"notNull\": true, \"belongPrimaryKey\": true}, {\"fieldName\": \"good_left_id\", \"fieldType\": \"Integer\", \"notNull\": true, \"defaultValue\": 0}, {\"fieldName\": \"title\", \"fieldType\": \"String\"}, {\"fieldName\": \"url\", \"fieldType\": \"String\"} ], \"indexes\": [ {\"indexName\": \"goodLeftIdIndex\", \"indexList\": [{\"fieldName\":\"good_left_id\",\"sortType\":\"ASC\"}]} ], \"permissions\": [ {\"role\": \"World\", \"rights\": [\"Read\"]}, {\"role\": \"Authenticated\", \"rights\": [\"Read\", \"Upsert\"]}, {\"role\": \"Creator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]}, {\"role\": \"Administrator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]} ] } 分别填充数据 海报 { \"cloudDBZoneName\": \"default\", \"objectTypeName\": \"home_poster\", \"objects\": [ { \"id\": 10, \"poster_id\": 1, \"url\": \"在线图片链接\", \"router\": \"string1\" } ] } 商品活动入口 { \"cloudDBZoneName\": \"default\", \"objectTypeName\": \"home_good_center\", \"objects\": [ { \"id\": 10, \"good_left_id\": 1, \"title\": \"生鲜严选\", \"url\": \"在线图片链接\" }, { \"id\": 20, \"good_left_id\": 1, \"title\": \"西购新品\", \"url\": \"在线图片链接\" }, { \"id\": 30, \"good_left_id\": 1, \"title\": \"今日推荐\", \"url\": \"在线图片链接\" } ] } 都填充完成后,我们把数据提交到云端,然后进行配置类的同步 接下来我们进行数据查询,因为我们在配置表中添加了id ,所以我们要查询出对应id的活动入口。 @State homeActivity:HomeActivitySetting[]=[]//首页活动配置 @State homeGoodCenter:HomeGoodCenter[]=[]//商品活动入口 let listData3 = await databaseZone.query(condition3); let json3 = JSON.stringify(listData3) let data3:HomeActivitySetting[]= JSON.parse(json3) this.homeActivity=data3 hilog.error(0x0000, \'testTag\', Failed to query data, code: ${this.homeActivity}); let list5 = await databaseZone.query(home_good); home_good.equalTo(\"good_left_id\",data3[0].good_left_id); let json5 = JSON.stringify(list5) let data5:HomeGoodCenter[]= JSON.parse(json5) this.homeGoodCenter=data5 hilog.error(0x0000, \'testTag\', Failed to query data, code: ${this.homeGoodCenter}); 然后我们修改一下商品活动入口的内容 import { HomeGoodCenter } from \"../entity/HomeGoodCenter\" @Component @Preview export struct SpecialColumn { @LinkgoodInfo: HomeGoodCenter[] build() { Column(){ List({space:10}){ ForEach(this.goodInfo,(data:HomeGoodCenter)=>{ ListItem(){ Column(){ Text(data.title) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor(Color.Black) Blank() Image(data.url) .width(\'28%\') .height(90) .margin({ bottom: 8 }) .objectFit(ImageFit.Cover) } .borderRadius(5) .backgroundColor(\"#ffeedeb8\") .padding(5) } }) } .listDirection(Axis.Horizontal) } .margin({top:10}) } } 在首页进行调用 SpecialColumn({goodInfo:this.homeGoodCenter}) 到这里我们就实现了活动配置相关的内容

    2025-06-28 16:31

  • 《仿》app开发技术分享-- 首页商品流(7)

    技术栈 Appgallery connect 开发准备 上一节我们实现了首页banner模块的功能,现在我们的首页还需要添加商品列表,作为一个购物类应用,商品列表是非常重要的一个模块,所以我们尽量把它设计的足够完善,参数能更好的支持我们后期复杂的逻辑,它需要有图片的展示,适配的优惠券列表,限购,立减,划线价等,但他实际的参数还要更多,因为我们的列表是比较紧凑的,更多的数据需要从点击后的商品详情页展示出来。 代码实现 创建商品表 { \"objectTypeName\": \"home_product_list\", \"fields\": [ {\"fieldName\": \"id\", \"fieldType\": \"Integer\", \"notNull\": true, \"belongPrimaryKey\": true}, {\"fieldName\": \"goods_list_id\", \"fieldType\": \"Integer\", \"notNull\": true, \"defaultValue\": 0}, {\"fieldName\": \"url\", \"fieldType\": \"String\"}, {\"fieldName\": \"name\", \"fieldType\": \"Text\"}, {\"fieldName\": \"price\", \"fieldType\": \"Double\"}, {\"fieldName\": \"original_price\", \"fieldType\": \"Double\"}, {\"fieldName\": \"amount\", \"fieldType\": \"Integer\"}, {\"fieldName\": \"text_message\", \"fieldType\": \"String\"}, {\"fieldName\": \"parameter\", \"fieldType\": \"String\"}, {\"fieldName\": \"delivery_time\", \"fieldType\": \"String\"}, {\"fieldName\": \"endTime\", \"fieldType\": \"String\"}, {\"fieldName\": \"sales_volume\", \"fieldType\": \"Integer\"}, {\"fieldName\": \"space_id\", \"fieldType\": \"Integer\"}, {\"fieldName\": \"max_loop_amount\", \"fieldType\": \"Integer\"}, {\"fieldName\": \"promotion_spread_price\", \"fieldType\": \"Double\"}, {\"fieldName\": \"coupon_id\", \"fieldType\": \"Integer\"} ], \"indexes\": [ {\"indexName\": \"field1IndexId\", \"indexList\": [{\"fieldName\":\"id\",\"sortType\":\"ASC\"}]} ], \"permissions\": [ {\"role\": \"World\", \"rights\": [\"Read\"]}, {\"role\": \"Authenticated\", \"rights\": [\"Read\", \"Upsert\"]}, {\"role\": \"Creator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]}, {\"role\": \"Administrator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]} ] } 填充数据 { \"cloudDBZoneName\": \"default\", \"objectTypeName\": \"home_product_list\", \"objects\": [ { \"id\": 10, \"goods_list_id\": 1, \"url\": \"在线图片链接\", \"name\": \"红颜草莓\", \"price\": 10.5, \"original_price\": 18.5, \"amount\": 10, \"text_message\": \"特价\", \"parameter\": \"冷藏\", \"delivery_time\": \"付款后24小时内发货\", \"endTime\": \"直降 | 结束时间2025年5月18日 10:00\", \"sales_volume\": 9812, \"space_id\": 10, \"max_loop_amount\": 10, \"promotion_spread_price\": 5, \"coupon_id\": 10 }, { \"id\": 20, \"goods_list_id\": 1, \"url\": \"在线图片链接\", \"name\": \"麒麟瓜\", \"price\": 2.8, \"original_price\": 5.9, \"amount\": 1, \"text_message\": \"当季新品\", \"parameter\": \"冷藏\", \"delivery_time\": \"付款后24小时内发货\", \"endTime\": \"直降 | 结束时间2025年5月18日 10:00\", \"sales_volume\": 9812, \"space_id\": 11, \"max_loop_amount\": 10, \"promotion_spread_price\": 0, \"coupon_id\": 10 } ] } 我们接下来进行数据的查询 @State homeProduct:HomeProductList[]=[]//商品流数据 let databaseZone = cloudDatabase.zone(\'default\'); let home_product=new cloudDatabase.DatabaseQuery(home_product_list); let list7 = await databaseZone.query(home_product); let json7 = JSON.stringify(list7) let data7:HomeProductList[]= JSON.parse(json7) this.homeProduct=data7 数据查出完成后,完善商品流的页面 import { HomeProductList } from \"../entity/home_product_list\" @Component @Preview export struct WaterFlowGoods { @Link goodsList: Array @State columns: number = 2 build() { WaterFlow() { ForEach(this.goodsList, (item:HomeProductList, index) => { FlowItem() { Column() { Image(item.url) .width(\'100%\') .aspectRatio(1) .objectFit(ImageFit.Cover) .borderRadius({topLeft:10,topRight:10}) Column() { Text(item.name) .fontSize(16) .fontColor(\'#333\') .margin({ bottom: 4 }) Text(item.text_message) .fontSize(12) .fontColor(\'#666\') .margin({ bottom: 8 }) Text(\"最高立减\"+item.promotion_spread_price) .fontSize(12) .fontColor(\'#ffffff\') .visibility(item.promotion_spread_price>0?Visibility.Visible:Visibility.None) .margin({ bottom: 8 }) .padding({left:5,right:5,top:2,bottom:2}) .linearGradient({ angle:90, colors: [[0xff0000, 0], [0xff6666, 0.2], [0xff6666, 1]] }) Row(){ Text(\"限购\") .width(40) .fontSize(12) .borderRadius(20) .backgroundColor(\"#FB424C\") .padding(3) .textAlign(TextAlign.Center) Text(\"每人限购\"+item.max_loop_amount+\"件\") .margin({left:5}) .fontSize(12) .fontColor(\"#FB424C\") } .borderRadius(20) .padding({top:2,bottom:2,right:10}) .backgroundColor(\"#FEE3E3\") .visibility(item.amount>0?Visibility.Visible:Visibility.None) Row() { Text(){ Span(\"¥\") .fontColor(Color.Red) .fontSize(14) Span(String(item.price)) .fontSize(16) .fontColor(Color.Red) } Text(String(item.original_price)) .fontSize(12) .fontColor(\'#999\') .decoration({ type: TextDecorationType.LineThrough, color: Color.Gray }) .margin({left:10}) Blank() Column() { Image($r(\'app.media.cart\')) .width(20) .height(20) } .justifyContent(FlexAlign.Center) .width(36) .height(36) .backgroundColor(\"#ff2bd2fa\") .borderRadius(18) } .margin({top:10}) .width(\'100%\') .justifyContent(FlexAlign.SpaceBetween) } .alignItems(HorizontalAlign.Start) .padding(12) } .backgroundColor(Color.White) .borderRadius(12) .onClick(() => { }) } .margin({ bottom: 12 }) }) } .padding(10) .columnsTemplate(\'1fr 1fr\') .columnsGap(12) .onAreaChange((oldVal, newVal) => { this.columns = newVal.width > 600 ? 2 : 1 }) } } 然后在首页调用,传入参数 WaterFlowGoods({goodsList:this.homeProduct}) 到这里我们就实现了首页商品列表的内容

    2025-06-29 23:42

  • 《仿》app开发技术分享-- 分类左侧列表(17)

    技术栈 Appgallery connect 开发准备 上一节我们实现了分类页面的顶部导航栏全选弹窗列表,并实现了跟顶部列表的点击选中联动效果,这一节我们要实现的功能是,分类模块的左侧列表,它同样也需要跟弹窗列表的点击,顶部列表的点击有联动的效果 功能分析 1.列表展示 列表的数据展示,我们要根据当前选中的顶部列表child_id作为前提条件进行数据的查询,因为我们的顶部列表是一个大的分类,比如酒水饮料,他可能分为 啤酒、白酒、红酒这些细分品类,当我们点击其他品类,左侧的列表同时也要进行切换。这里比较考验我们对联动效果的整体把控,要实现这个功能,我们需要把弹窗选中的id,列表选中的id,首次进入页面默认选中情况下的id利用起来,作为列表查询的条件进行数据的查询,以及后续list列表数据的展示 代码实现 首先我们优先修改弹窗以及列表本身点击后传出的数据 privateonItemClick?: (pos:number,child_id:number) => void 我们只需要在点击事件的回调中把相对应的id返回出去 Classification({selectedIndex:this.pos_check,onItemClick:(pos,child_id)=>{ this.pos_check=pos this.pos_check_id=child_id }}) 在调用页面直接取值即可,其他的弹窗以及列表逻辑没有相应的修改 然后我们把分类页面定义的leftListItemChildId 修改为topListItemChildId,这样更有助于我们理解参数定义的意思 然后添加监听事件 @Link @Watch(\"onChange\") topListItemChildId: number; 在监听事件中我们根据定义的id 来进行左侧列表数据的查询 async onChange(){ let condition = new cloudDatabase.DatabaseQuery(category_left_list); condition.equalTo(\"child_id\",this.topListItemChildId) let listData = await databaseZone.query(condition); let json = JSON.stringify(listData) let data2:CategoryLeftList[]= JSON.parse(json) this.categoryList=data2 hilog.error(0x0000, \'testTag\', Failed to query data, code: ${this.categoryList}); } 这样只要id进行了修改,我们的数据查询就会执行 左侧列表ui逻辑 @Builder LeftList() { List() { ForEach(this.categoryList, (item: SplitLayoutModel, index) => { ListItem() { Row() { Divider() .vertical(true) .color(\"#000000\") .height(40) .width(3) .visibility(this.checkPosition == index ? Visibility.Visible : Visibility.None) Text(item.txt) .fontSize(12) .fontWeight(this.checkPosition == index ? FontWeight.Bold : FontWeight.Normal) .textAlign(TextAlign.Center) .width(75) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(1) .backgroundColor(this.checkPosition == index ? Color.White : \"#f7f7f7\") .fontColor(this.checkPosition == index ? \"#000000\" : \"#999999\") } .backgroundColor(this.checkPosition == index ? Color.White : \"#f7f7f7\") .height(60) .width(80) .onClick(() => { this.checkPosition = index }) } }) } .height(\'100%\') .backgroundColor(\"#f7f7f7\") .listDirection(Axis.Vertical) // 排列方向 .divider({ strokeWidth: 0.5, color: \"#e6e6e6\" }) // 每行之间的分界线 .edgeEffect(EdgeEffect.Spring) // 滑动到边缘无效果 .onScrollIndex((firstIndex: number, lastIndex: number) => { console.info(\'first\' + firstIndex) console.info(\'last\' + lastIndex) }) .scrollBar(BarState.Off) .width(80) } 这样就实现了左侧列表的相关功能,我们点击其他类目对应的左侧列表数据也会发生相应的改变

    2025-06-30 10:55

  • 《仿》app开发技术分享-- 首页banner(6)

    技术栈 Appgallery connect 开发准备 上一篇文章中我们实现了项目端云一体化首页商品活动入口列表,现在我们还差一个banner的模块,banner模块不仅可以用于展示一些信息,还可以在点击之后进行,跳转,弹窗,升级提示,信息提示等作用,我们直接坐的完善一些,因为我们事先在banner表中添加了action,我们通过这个action的值来进行对应的处理,同时通过islogin字段来判断是否需要登陆操作 代码实现 创建banner表 { \"objectTypeName\": \"home_banner\", \"fields\": [ {\"fieldName\": \"id\", \"fieldType\": \"Integer\", \"notNull\": true, \"belongPrimaryKey\": true}, {\"fieldName\": \"banner_id\", \"fieldType\": \"Integer\", \"notNull\": true, \"defaultValue\": 0}, {\"fieldName\": \"url\", \"fieldType\": \"String\"}, {\"fieldName\": \"is_login\", \"fieldType\": \"Boolean\"}, {\"fieldName\": \"router\", \"fieldType\": \"Boolean\"}, {\"fieldName\": \"action_id\", \"fieldType\": \"Integer\"}, {\"fieldName\": \"action\", \"fieldType\": \"String\"} ], \"indexes\": [ {\"indexName\": \"banner_id\", \"indexList\": [{\"fieldName\":\"banner_id\",\"sortType\":\"ASC\"}]} ], \"permissions\": [ {\"role\": \"World\", \"rights\": [\"Read\"]}, {\"role\": \"Authenticated\", \"rights\": [\"Read\", \"Upsert\"]}, {\"role\": \"Creator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]}, {\"role\": \"Administrator\", \"rights\": [\"Read\", \"Upsert\", \"Delete\"]} ] } 填充数据 banner { \"cloudDBZoneName\": \"default\", \"objectTypeName\": \"home_banner\", \"objects\": [ { \"id\": 10, \"banner_id\": 1, \"url\": \"在线图片链接\", \"is_login\": true, \"router\": \"\", \"action_id\": 10, \"action\": \"toast\" }, { \"id\": 20, \"banner_id\": 0, \"url\": \"在线图片链接\", \"is_login\": false, \"router\": \"\", \"action_id\": 20, \"action\": \"dialog\" } ] } 由于我们缺少banner相关的内容,所以我们还需要创建一个banner的页面 import { HomeBanner } from \"../entity/HomeBanner\" import showToast from \"../utils/ToastUtils\" @Component @Preview export struct HomeBannerPage { //数据源 @Link bannerList:HomeBanner[] //tabs 当前数据源的下标 @State swpIndex:number=1 build() { Column() { Swiper(){ ForEach(this.bannerList, (item: HomeBanner) => { Image(item.url) .width(\'100%\') .height(130) .borderRadius(10) .onClick(()=>{ if (item.action==\'toast\') { showToast(\"1111\") } if (item.action==\'dialog\') { } }) }) } .borderRadius(10) .loop(true) .indicator(true) .height(130) .onChange((index: number) => { this.swpIndex=index+1 }) } .padding(10) .margin({top:10}) } } 我们先判断是否需要is_login,然后根据action去判断,到这里我们就实现了banner的内容

    2025-06-29 23:26

  • 《仿》app开发技术分享-- 订单地址修改(31)

    技术栈 Appgallery connect 开发准备 上一节我们实现了订单备注弹窗,订单商品列表的提交,订单列表的提交,提交之后的业务逻辑我们并没有去处理,那么订单提交之后我们需要进入到什么页面呢?这时候我们需要一个过渡页面,它能给我们提供更多的订单相关的入口,帮助用户去确认内容,或者查看订单相关内容 功能分析 要实现这样一个页面,首先我们要做的就是在这个页面我们能拿到用户的信息,对应的订单id,这样的话我们就可以通过一个查询订单的按钮或者入口进入到订单的详情界面,然后我们需要有一个地址确认的页面,这能帮助用户核对地址的准确性,同时我们还需要提供一个地址修改的信息展示,辅助用户进行错误地址的修改 代码实现 首先我们来实现,点击事件的跳转,在提交订单按钮添加要跳转的页面路径和传递过去的值(要在提交成功后跳转) let num = await databaseZone.upsert(orderPush); if (num>0) { router.back({url:\'pages/view/OrderSuccessPage\',params:{status:true}}) } 然后在订单状态页面接收数据,展示查看订单的入口和当前订单的地址信息 import { OrderList } from \'../entity/OrderList\'; import showToast from \'../utils/ToastUtils\'; import { router } from \'@kit.ArkUI\'; import { CommonTopBar } from \'../widget/CommonTopBar\'; @Entry @Component struct OrderSuccessPage { @State orderInfo:OrderList|null=null @State addressSuccess:boolean=false @State isSuccess:boolean=false onPageShow(): void { let params = (this.getUIContext().getRouter().getParams() as Record<string, boolean>)[\'status\'] if (params!=undefined){ this.isSuccess=params } } aboutToAppear(): void { const params = this.getUIContext().getRouter().getParams() as OrderList; if (params!=null) { this.orderInfo=params } } build() { Column() { CommonTopBar({ title: \"订单状态\", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true}) Column({space:15}){ Row({space:10}){ Image($r(\'app.media.order_success\')) .height(30) .width(30) Text(\"下单成功!\") .fontSize(24) .fontColor(Color.Black) .fontWeight(FontWeight.Bold) } Text(\"您的包裹正准备发出,请保持联系通畅哦~~\") .fontSize(16) .fontColor(Color.Black) Text(\"查看订单\") .fontSize(16) .fontColor(Color.Black) .padding(10) .borderRadius(10) .border({width:1,color:Color.Grey}) .onClick(()=>{ showToast(\"订单号是:\"+this.orderInfo!.order_code) }) } .padding(30) Column({space:10}){ Text(\"收货地址\") .fontSize(16) .fontColor(Color.Black) Row(){ Text(this.orderInfo?.nickname) .fontColor(Color.Black) .fontSize(16) .fontWeight(FontWeight.Bold) Text(this.orderInfo?.phone) .fontColor(Color.Black) .fontSize(16) .fontWeight(FontWeight.Bold) .margin({left:20}) } Text(this.orderInfo?.address) .fontColor(Color.Black) .fontSize(16) Row({space:10}){ Text() Blank() Text(\"修改地址\") .fontSize(14) .fontColor(Color.Black) .padding(5) .borderRadius(5) .border({width:1,color:Color.Grey}) .visibility(this.addressSuccess?Visibility.None:Visibility.Visible) .onClick(()=>{ router.pushUrl({url:\'pages/view/EditOrderAddressPage\',params:{info:JSON.stringify(this.orderInfo)}}) }) Text(\"确认地址\") .fontSize(14) .fontColor(Color.Black) .padding(5) .borderRadius(5) .backgroundColor(Color.White) .onClick(()=>{ this.addressSuccess=true }) } .width(\'100%\') .justifyContent(FlexAlign.SpaceBetween) } .backgroundColor(\"#fff6db95\") .padding(20) .width(\'90%\') .borderRadius(10) .alignItems(HorizontalAlign.Start) } .backgroundColor(Color.White) .height(\'100%\') .width(\'100%\') } } 我们执行一下代码,看看效果 订单详情我们到下一节实现,现在我们点击地址修改 这里定义一个变量 @State addressSuccess:boolean=false 当我们不需要修改地址,点击确认地址之后,我们要隐藏对应的修改地址按钮 相关代码: .visibility(this.addressSuccess?Visibility.None:Visibility.Visible) 这时修改地址按钮已经消失了 当我们的地址需要修改,我们点击修改地址按钮,来到订单地址修改页,我们依旧要接收对应的数据集在当前页面加载,我们展示的内容有当前选择的地址,以及要修改的地址,要修改的地址我们从地址列表也重新选择实现 import { OrderList } from \'../entity/OrderList\'; import { router } from \'@kit.ArkUI\'; import { AddressList } from \'../entity/AddressList\'; import { cloudDatabase } from \'@kit.CloudFoundationKit\'; import { order_list } from \'../clouddb/order_list\'; import { CommonTopBar } from \'../widget/CommonTopBar\'; @Entry @Component struct EditOrderAddressPage { @State orderInfo:OrderList|null=null @State addressInfo:AddressList|null=null aboutToAppear(): void { let params = (this.getUIContext().getRouter().getParams() as Record<string, string>)[\'info\'] if (params!=null&&params!=undefined) { this.orderInfo=JSON.parse(params) } } onPageShow(): void { let params = (this.getUIContext().getRouter().getParams() as Record<string, string>)[\'address\'] if (params!=\'\'&&params!=undefined){ this.addressInfo=JSON.parse(params) } } build() { Column() { CommonTopBar({ title: \"订单地址修改\", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true}) Row({space:15}){ Image($r(\'app.media.edit_address_notice\')) .height(15) .width(15) Text(\"提示:地址仅可以修改一次,请谨慎修改!!!\") .fontSize(14) .fontColor(Color.Black) } .width(\'100%\') .height(50) .alignItems(VerticalAlign.Center) .padding(10) .backgroundColor(\"#ffe7bdbd\") Column({space:20}){ Column({space:10}){ Text(\"原地址\") .fontColor(Color.Black) .fontSize(14) Row(){ Text(this.orderInfo?.nickname) .fontColor(Color.Black) .fontSize(14) Text(this.orderInfo?.phone) .fontColor(Color.Black) .fontSize(14) } Text(this.orderInfo?.address) .fontColor(Color.Black) .fontSize(14) } .borderRadius(10) .alignItems(HorizontalAlign.Start) .width(\'80%\') .padding(10) .backgroundColor(Color.Pink) Column({space:10}){ Row(){ Text(\"新地址\") .fontColor(Color.Black) .fontSize(14) Text(\"选择地址 >\") .fontColor(Color.Black) .fontSize(14) .onClick(()=>{ router.pushUrl({url:\'pages/view/AddressListPage\',params:{edit_status:true}}) }) }.width(\'100%\') .justifyContent(FlexAlign.SpaceBetween) Row(){ Text(this.addressInfo?.nikeName) .fontColor(Color.Black) .fontSize(14) Text(this.addressInfo?.phone) .fontColor(Color.Black) .fontSize(14) } Text(this.addressInfo?.address) .fontColor(Color.Black) .fontSize(14) } .alignItems(HorizontalAlign.Start) .width(\'80%\') .padding(10) .backgroundColor(Color.Pink) .borderRadius(10) } .margin({top:20}) .layoutWeight(1) Text(\"提交修改\") .fontColor(Color.Black) .width(\'80%\') .height(50) .backgroundColor(Color.Pink) .textAlign(TextAlign.Center) .margin({bottom:20}) .borderRadius(10) } .backgroundColor(Color.White) .height(\'100%\') .width(\'100%\') } } 未选择修改地址的状态,选择了地址之后.我们在提交修改按钮重新提交我们的订单信息,把新地址提交到云数据库 Text(\"提交修改\") .fontColor(Color.Black) .width(\'80%\') .height(50) .backgroundColor(Color.Pink) .textAlign(TextAlign.Center) .margin({bottom:20}) .borderRadius(10) .onClick(async ()=>{ let databaseZone = cloudDatabase.zone(\'default\'); let orderPush = new order_list(); orderPush.id=this.orderInfo!.id orderPush.user_id=this.orderInfo!.user_id orderPush.order_product_id=this.orderInfo!.order_product_id orderPush.order_code=this.orderInfo!.order_code orderPush.order_status=this.orderInfo!.order_status orderPush.order_remark=this.orderInfo!.order_remark orderPush.address=this.addressInfo!.address orderPush.nickname=this.addressInfo!.nikeName orderPush.phone=this.addressInfo!.phone orderPush.order_create_time=this.orderInfo!.order_create_time orderPush.order_pay_time=this.orderInfo!.order_pay_time let num = await databaseZone.upsert(orderPush); if (num>0) { router.back({url:\'pages/view/OrderSuccessPage\',params:{status:true}}) } }) 到这里我们的地址修改主要功能就实现了,后续我们只需要打磨细节即可

    2025-06-30 20:53

  • 《仿》app开发技术分享-- 定位获取(25)

    技术栈 Appgallery connect 开发准备 上一节我们实现了地址管理页面的数据查询和展示,接下来我们要实现的功能是地址添加相关的,我们想实现的功能是地图选点,那么在地图选点之前我们要做的就是先获取用户当前的定位。获取定位后我们拿到经纬度和其他信息,然后在对应的地图上展示。 功能分析 要想实现定位功能,首先我们需要给应用申请定位权限,然后我们每次进入页面之前需要先进行定位功能是否开启的判断,如果没有开启我们要提示用户去开启,之后我们才是对定位请求的开启判断,用户同意之后获取当前的定位,在返回值中拿到经纬度 代码实现 首先我们在model.json5中添加对应的权限 { \"name\": \"ohos.permission.LOCATION\", \"reason\": \"$string:app_location\", \"usedScene\": { \"abilities\": [ \"EntryAbility\" ], \"when\":\"inuse\" } }, { \"name\": \"ohos.permission.APPROXIMATELY_LOCATION\", \"reason\": \"$string:app_reason_location\", \"usedScene\": { \"abilities\": [ \"EntryAbility\" ], \"when\":\"inuse\" } } 添加完成后我们新建一个提交定位管理的页面,在生命周期中先进行手机是否开启定位的判断,并且新增两个变量来控制我们的定位触发 @StatelocationKey:boolean=false @StateaddressSetting:boolean=false aboutToAppear(): void { try { let locationEnabled = geoLocationManager.isLocationEnabled(); if (locationEnabled) { this.addressSetting=true }else { this.addressSetting=false } } catch (err) { console.error(\"errCode:\" + err.code + \", message:\"+ err.message); } } 如果用户开启了定位,并且我们没有开启应用的定位权限,在当前页面的底部提醒用户,去开启定位 build() { Column() { Stack({alignContent:Alignment.Bottom}){ Column(){ } .layoutWeight(1) if (this.addressSetting&&!this.locationKey){ Row(){ Text() .width(40) Text(\"定位未开启\") .fontColor(Color.Black) Text(\"开启定位\") .fontColor(Color.White) .backgroundColor(Color.Pink) .borderRadius(10) .padding(10) .onClick(()=>{ }) } .padding(10) .borderRadius(5) .margin({bottom:30}) .backgroundColor(\'#33000000\') .justifyContent(FlexAlign.SpaceAround) .width(\'90%\') } } .backgroundColor(Color.White) .height(\'100%\') .width(\'100%\') } } 因为在隐私合规的情况下,我们已经不能进入页面就执行权限的请求了,这一点很重要 当我们点击开启定位 .onClick(()=>{ this.reqPermissionsFromUser(permissions); this.permissionController.open(); }) 这里我们同步创建一个弹窗,当然你可以有多种选择来实现权限的同步说明,在这里我们两种方式都实现了 创建弹窗 @CustomDialog exportdefaultstruct PermissionDialogWidget{ @State titleText:string=\'\'; @State contentText:string=\'\'; controller: CustomDialogController build(){ Column(){ Text(this.titleText).margin({top:10}) Text(this.contentText).margin({top:20,bottom:10}) }.justifyContent(FlexAlign.Start).padding({left:20,right:20}) } } 引用弹窗 permissionController:CustomDialogController=new CustomDialogController({ builder:PermissionDialogWidget({ titleText:\"权限说明\", contentText: \'xxx想要申请位置权限,用于地址选择等功能。同意该权限后,选择地址时会复用此权限,不会重新申请,不授权上述权限,不影响APP其他功能使用。\', }), alignment: DialogAlignment.Top, }) 执行权限请求 reqPermissionsFromUser(permissions: Array): void { let context = getContext(this) as common.UIAbilityContext; let atManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(context, permissions).then((data) => { let grantStatus: Array = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { this.locationKey=true this.permissionController.close() let request: geoLocationManager.SingleLocationRequest = { \'locatingPriority\': geoLocationManager.LocatingPriority.PRIORITY_LOCATING_SPEED, \'locatingTimeoutMs\': 10000 } try { geoLocationManager.getCurrentLocation(request).then((result) => { console.log(\'current location: \' + JSON.stringify(result)); let locationInfo:geoLocationManager.ReverseGeoCodeRequest=result; let reverseGeocodeRequest:geoLocationManager.ReverseGeoCodeRequest = {\"latitude\": locationInfo.latitude, \"longitude\": locationInfo.longitude, \"maxItems\": 1}; try { geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, (err, data) => { if (err) { console.error(\'getAddressesFromLocation: err=\' + JSON.stringify(err)); } if (data) { console.info(\'地址打印\' + JSON.stringify(data)); } }); } catch (err) { console.error(\"errCode:\" + err.code + \", message:\"+ err.message); } }) .catch((error:BusinessError) => { console.error(\'promise, getCurrentLocation: error=\' + JSON.stringify(error)); }); } catch (err) { console.error(\"errCode:\" + JSON.stringify(err)); } } else { this.locationKey=false this.permissionController.close() return; } } }).catch((err:Error) => { console.error(requestPermissionsFromUser failed, code is ${err.name}, message is ${err.message}); }) } 在这里我们既实现了自定义弹窗的同步说明,同时也在model.json5中配置了reason进行说明,可以按需进行实现。 在请求定位的返回信息中我们拿到了经纬度的信息,到这里我们实现了定位获取功能

    2025-06-30 16:00

  • 《仿》app开发技术分享-- 订单详情页(32)

    技术栈 Appgallery connect 开发准备 在之前的章节中我们实现了订单的提交,以及提交之后跳转到确认订单页面,在确认订单页面我们添加了一个入口,这个入口是查询订单,当我们点击入口时,我们需要跳转到一个新的界面,这个界面通过接收上个界面的订单id或者订单code 等信息,进行订单的详细内容展示 功能分析 要想实现订单内容的展示,首先我们要解决订单查询的问题,之前的订单提交页面,因为我们做了一张关联表,把提交的商品放置到了一张单独的表中,通过order_product_id去做关联查询,所以我们还需要根据id 把对应的商品列表查出来,然后我们再查出对应order_code 对应的订单,展示到页面上,同时展示出更多的信息给到用户 代码实现 首先在确认订单页面实现数据的传递 Text(\"查看订单\") .fontSize(16) .fontColor(Color.Black) .padding(10) .borderRadius(10) .border({width:1,color:Color.Grey}) .onClick(()=>{ router.pushUrl({url:\'pages/view/OrderDetailsPage\',params:{code:this.orderInfo!.order_code}}) }) 然后我们回到订单详情页面进行传递数据的接收 @State orderCode:string=\'\' let params = (this.getUIContext().getRouter().getParams() as Record<string, string>)[\'code\'] if (params!=undefined&& params!=\'\'){ this.orderCode=params } 接收到数据之后我们首先根据ordercode进行表数据的查询 let databaseZone = cloudDatabase.zone(\'default\'); let condition = new cloudDatabase.DatabaseQuery(order_list); condition.equalTo(\"order_code\",this.orderCode!) let listData = await databaseZone.query(condition); let json = JSON.stringify(listData) let data1:OrderList[]= JSON.parse(json) this.orderInfo=data1[0] 查询出来数据之后,我们拿到返回值中的order_product_id字段,根据它再次进行查询,拿到对应的商品列表 @State orderInfo:OrderList|null=null let condition1 = new cloudDatabase.DatabaseQuery(order_product_list); condition1.equalTo(\"order_product_id\",data1[0].order_product_id) let listData1 = await databaseZone.query(condition1); let json1 = JSON.stringify(listData1) this.productList=JSON.parse(json1) 都查询出来之后我们开始进行页面数据的绘制和数据的填充 build() { if (this.flag){ Column(){ CommonTopBar({ title: \"订单详情\", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true}) Scroll(){ Column({space:10}) { Column({space:15}){ Text(\"买家已付款\") .fontSize(20) .width(\'100%\') .textAlign(TextAlign.Center) .fontColor(Color.Black) .fontWeight(FontWeight.Bold) Text(\"您买的商品已经安排了,商家即将发货\") .fontSize(16) .fontColor(Color.Black) .width(\'100%\') .textAlign(TextAlign.Center) }.width(\'100%\') .padding(15) .backgroundColor(\"#fff3574a\") Divider().width(\'100%\').height(5) .color(\"#e6e6e6\") Column(){ Row({space:20}){ Image($r(\'app.media.order_location\')) .height(20) .width(20) Column(){ Row(){ Text(this.orderInfo?.nickname) .fontColor(Color.Black) .fontSize(16) .fontWeight(FontWeight.Bold) Text(this.orderInfo?.phone) .fontColor(Color.Black) .fontSize(16) .fontWeight(FontWeight.Bold) .margin({left:20}) } Text(this.orderInfo?.address) .fontColor(Color.Black) .fontSize(16) .margin({top:10}) } .padding(10) .alignItems(HorizontalAlign.Start) .width(\'100%\') } } .padding(10) .alignItems(HorizontalAlign.Start) .width(\'100%\') Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") List({scroller:this.scroller}){ ForEach(this.productList,(item:OrderProductList,index:number)=>{ ListItem(){ Column(){ Row() { Row({ space: 10 }) { Image(item.img) .height(70) .width(70) .margin({ left: 10 }) .borderRadius(10) Column({ space: 5 }) { Text(item.name) .fontColor(Color.Black) .fontSize(14) Text(item.spec) .fontColor(Color.Grey) .fontSize(14) Row() { Text() { Span(\"¥ \") .fontSize(14) .fontColor(Color.Red) Span(item.price + \"\") .fontSize(16) .fontColor(Color.Red) } Text(\"¥\" + item.originalPrice + \"\") .fontColor(\'#999\') .decoration({ type: TextDecorationType.LineThrough, color: Color.Gray }) .fontSize(14) .margin({ left: 10 }) } .alignItems(VerticalAlign.Bottom) Text(\"已选:\" + item.buyAmount) .fontColor(Color.Black) .fontColor(Color.Gray) .fontSize(12) } .alignItems(HorizontalAlign.Start) } .justifyContent(FlexAlign.Start) .alignItems(VerticalAlign.Top) Blank() Text(\"¥ \" + item.price*item.buyAmount) .fontColor(Color.Black) .fontSize(14) } .padding(10) .width(\'100%\') .alignItems(VerticalAlign.Top) .justifyContent(FlexAlign.SpaceBetween) Divider() .width(\'100%\') .height(1) .backgroundColor(\"#f7f7f7\") } } }) } .height(\'auto\') Row(){ Text() Blank() Text() { Span(\"合计:\") .fontSize(16) .fontColor(Color.Black) Span(\"¥ \") .fontSize(10) .fontColor(Color.Red) Span(this.price()+\"\") .fontSize(16) .fontColor(Color.Red) } } .padding(10) .width(\'100%\') .justifyContent(FlexAlign.SpaceBetween) Divider().width(\'100%\').height(5) .color(\"#e6e6e6\") Text(\"订单信息\") .fontSize(18) .fontColor(Color.Black) .fontWeight(FontWeight.Bold) .margin({left:15}) Divider().width(\'100%\').height(5) .color(\"#e6e6e6\") Row(){ Text(\"订单编号:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(this.orderInfo?.order_code) .fontColor(Color.Black) .fontSize(14) } .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") Row(){ Text(\"订单备注:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(this.orderInfo?.order_remark!=\'\'&&this.orderInfo?.order_remark!=null?this.orderInfo?.order_remark:\"无\") .fontColor(Color.Black) .fontSize(14) } .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") Row(){ Text(\"付款方式:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(\"线上支付\") .fontSize(16) .fontColor(Color.Black) } .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") Row(){ Text(\"创建时间:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(this.orderInfo?.order_create_time) .fontColor(Color.Black) .fontSize(14) } .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") Row(){ Text(\"付款时间:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(this.orderInfo?.order_pay_time) .fontColor(Color.Black) .fontSize(14) } .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) Divider().width(\'100%\').height(0.8) .color(\"#e6e6e6\") .visibility(this.orderInfo?.order_over_time!=\'\'?Visibility.Visible:Visibility.None) Row(){ Text(\"完成时间:\") .fontSize(16) .fontColor(Color.Black) Blank() Text(this.orderInfo?.order_over_time) .fontColor(Color.Black) .fontSize(14) } .visibility(this.orderInfo?.order_over_time!=null&&this.orderInfo.order_over_time!=\'\'?Visibility.Visible:Visibility.None) .justifyContent(FlexAlign.SpaceBetween) .width(\'100%\') .padding(10) } .margin({bottom:50}) .backgroundColor(Color.White) .alignItems(HorizontalAlign.Start) } .height(\'100%\') .width(\'100%\') } } } price():number{ letnumber=0 for (let i = 0; i <this.productList.length ; i++) { number+=this.productList[i].buyAmount*this.productList[i].price } returnnumber } 到这里我们就实现了订单详情的展示

    2025-06-30 20:56