<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lin</title>
    <description>The latest articles on DEV Community by Lin (@whl15290959515).</description>
    <link>https://dev.to/whl15290959515</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3284786%2Fbf96dc4c-f34a-4be9-ae87-2e3b0f97e114.jpeg</url>
      <title>DEV Community: Lin</title>
      <link>https://dev.to/whl15290959515</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whl15290959515"/>
    <language>en</language>
    <item>
      <title>Imitation Box Horse - Optimization of Unfinished Order List Logic (61)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 17:02:23 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-optimization-of-unfinished-order-list-logic-61-2613</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-optimization-of-unfinished-order-list-logic-61-2613</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Preface&lt;br&gt;
In the previous section, when we implemented the joint submission of orders and coupons, we checked the generated order information on the order list page and found that there were issues with both the information display and price calculations for the orders. Therefore, we need to urgently fix these corresponding issues.&lt;br&gt;
Source of the Problem&lt;/p&gt;

&lt;p&gt;async aboutToAppear(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value != "") {&lt;br&gt;
      this.user = JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
    if (this.currentIndexCheck==this.currentIndex) {&lt;br&gt;
      let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
      let condition = new cloudDatabase.DatabaseQuery(order_list);&lt;br&gt;
      condition.equalTo("user_id",this.user?.user_id).and().equalTo("order_status",0)&lt;br&gt;
      let listData = await databaseZone.query(condition);&lt;br&gt;
      let json = JSON.stringify(listData)&lt;br&gt;
      let data1:OrderList[]= JSON.parse(json)&lt;br&gt;
      this.orderInfo=data1&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  // The problematic code
  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)

  this.flag=true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;As we can see, when entering the "To Be Shipped" page, we request all orders from the orderlist, which is correct. However, when we continue down and query the data with conditions:&lt;/p&gt;

&lt;p&gt;condition1.equalTo("order_product_id",data1[0].order_product_id)&lt;/p&gt;

&lt;p&gt;Here we directly take the first piece of data and use it in the list logic. This causes all items in the list to display the products and prices from the first order. The displayed images and prices are all the same.&lt;br&gt;
Solution&lt;br&gt;
After identifying the problem, we decided to use a Map to store the data corresponding to different order_product_ids. This way, when looping through the orders, we can use the order_product_id as the key to retrieve the corresponding data. Now let's make the modifications:&lt;/p&gt;

&lt;p&gt;// First, define a global Map to receive the content&lt;br&gt;
@State mapList: Map | null = null;&lt;/p&gt;

&lt;p&gt;// Replace the original logic that only requested the first item with code that stores data in the Map&lt;br&gt;
async aboutToAppear(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value != "") {&lt;br&gt;
      this.user = JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
    if (this.currentIndexCheck == this.currentIndex) {&lt;br&gt;
      let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
      let condition = new cloudDatabase.DatabaseQuery(order_list);&lt;br&gt;
      condition.equalTo("user_id", this.user?.user_id).and().equalTo("order_status", 0);&lt;br&gt;
      let listData = await databaseZone.query(condition);&lt;br&gt;
      let json = JSON.stringify(listData);&lt;br&gt;
      let data1: OrderList[] = JSON.parse(json);&lt;br&gt;
      this.orderInfo = data1;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  // New code to populate the Map with product data for each order
  const myMap = new Map&amp;lt;string, OrderProductList[]&amp;gt;();
  for (let i = 0; i &amp;lt; data1.length; i++) {
    let condition1 = new cloudDatabase.DatabaseQuery(order_product_list);
    condition1.equalTo("order_product_id", data1[i].order_product_id);
    let listData1 = await databaseZone.query(condition1);
    let json1 = JSON.stringify(listData1);
    myMap.set(data1[i].order_product_id, JSON.parse(json1));
  }
  this.mapList = myMap;

  this.flag = true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;// Calculate the price for each order by retrieving the correct product data from the Map&lt;br&gt;
price(item: OrderList): number {&lt;br&gt;
  const money = this.mapList!.get(String(item.order_product_id));&lt;br&gt;
  if (!money || money.length === 0) return 0;&lt;br&gt;
  return money[0].buyAmount * money[0].price;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Update the List component to use the correct product data from the Map&lt;br&gt;
List({ space: 10 }) {&lt;br&gt;
  ForEach(this.mapList?.get(item.order_product_id) || [], (pos: OrderProductList) =&amp;gt; {&lt;br&gt;
    ListItem() {&lt;br&gt;
      Column() {&lt;br&gt;
        Image(pos.img)&lt;br&gt;
          .height(60)&lt;br&gt;
          .width(60)&lt;br&gt;
          .borderRadius(5)&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  })&lt;br&gt;
}&lt;br&gt;
.padding({ left: 10 })&lt;br&gt;
.width('100%')&lt;br&gt;
.listDirection(Axis.Horizontal)&lt;br&gt;
.height(80)&lt;/p&gt;

&lt;p&gt;With these changes, the logic on the order list page has been optimized and now functions correctly.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Order Discount Settlement (60)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 17:02:00 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-order-discount-settlement-60-17b1</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-order-discount-settlement-60-17b1</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented coupon selection and successfully displayed the post-coupon price to users. We also informed users in a user-friendly way about coupons that cannot be used. In this section, we will take the next step with coupon functionality, integrating coupon content with order settlement.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
Since our previous order list separated order-related and product-related information, we will similarly separate coupon content, storing only the ID for subsequent querying of the coupon amount. First, we need to modify the order table. When selecting a coupon, we retrieve relevant coupon information and submit it along with the order, facilitating querying of the post-coupon price in order details.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, modify the orderlist table content:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "CloudDBZoneName": "default",&lt;br&gt;
  "objectTypeName": "order_list",&lt;br&gt;
  "fields": [&lt;br&gt;
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},&lt;br&gt;
    {"fieldName": "user_id", "fieldType": "Integer", "notNull": true, "defaultValue": 0},&lt;br&gt;
    {"fieldName": "order_code", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_status", "fieldType": "Integer"},&lt;br&gt;
    {"fieldName": "order_product_id", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "coupon_id", "fieldType": "Integer"},&lt;br&gt;
    {"fieldName": "address", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "nickname", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "phone", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_remark", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "pay_type", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_create_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_pay_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_delivery_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "order_over_time", "fieldType": "String"}&lt;br&gt;
  ],&lt;br&gt;
  "indexes": [&lt;br&gt;
    {"indexName": "field1Index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}&lt;br&gt;
  ],&lt;br&gt;
  "permissions": [&lt;br&gt;
    {"role": "World", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Then, retrieve the coupon ID when selecting a coupon, implemented via callback:&lt;/p&gt;

&lt;p&gt;// Custom pop-up window page&lt;br&gt;
onItemSelected: (coupon_id:number) =&amp;gt; void= () =&amp;gt; {&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;// Checkout page&lt;br&gt;
@State coupon_id:number=0&lt;/p&gt;

&lt;p&gt;couponController: CustomDialogController| null = new CustomDialogController({&lt;br&gt;
  builder: CouponCheckDialog({&lt;br&gt;
    couponPrice:this.couponPrice,&lt;br&gt;
    price:this.price(),&lt;br&gt;
    onItemSelected:(coupon_id:number)=&amp;gt;{&lt;br&gt;
      this.coupon_id=coupon_id&lt;br&gt;
    }&lt;br&gt;
  }),&lt;br&gt;
  alignment: DialogAlignment.Bottom,&lt;br&gt;
  customStyle:true&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Merge and submit information when settling the order:&lt;/p&gt;

&lt;p&gt;Text("Submit Order")&lt;br&gt;
  .fontColor(Color.White)&lt;br&gt;
  .padding(10)&lt;br&gt;
  .borderRadius(10)&lt;br&gt;
  .backgroundColor("#d81e06")&lt;br&gt;
  .fontSize(14)&lt;br&gt;
  .onClick(async ()=&amp;gt;{&lt;br&gt;
    if (this.addressInfo!=null) {&lt;br&gt;
      let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
      try {&lt;br&gt;
        for (let i = 0; i &amp;lt; this.productList.length; i++) {&lt;br&gt;
          let productPush = new order_product_list();&lt;br&gt;
          productPush.id=this.codeId+i&lt;br&gt;
          productPush.order_product_id=this.codeId&lt;br&gt;
          productPush.img=this.productList[i].productImgAddress&lt;br&gt;
          productPush.price=this.productList[i].productPrice&lt;br&gt;
          productPush.name=this.productList[i].productName&lt;br&gt;
          productPush.originalPrice=this.productList[i].productOriginalPrice&lt;br&gt;
          productPush.spec=this.productList[i].productSpecName&lt;br&gt;
          productPush.buyAmount=this.productList[i].buyAmount&lt;br&gt;
          let num = await databaseZone.upsert(productPush);&lt;br&gt;
          hilog.info(0x0000, 'testTag', &lt;code&gt;Succeeded in upserting data, result: ${num}&lt;/code&gt;);&lt;br&gt;
        }&lt;br&gt;
      } catch (e) {&lt;br&gt;
        hilog.info(0x0000, 'testTag', &lt;code&gt;Failed to upsert data, error: ${e}&lt;/code&gt;);&lt;br&gt;
      }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  let orderPush = new order_list();
  orderPush.id=Math.floor(Math.random() * 1000000)
  orderPush.user_id=this.user!.user_id
  orderPush.order_product_id=String(this.codeId)
  orderPush.order_code=this.generateOrderNo(10)
  orderPush.order_status=0
  if (this.remark!='') {
    orderPush.order_remark=this.remark
  }
  orderPush.coupon_id=this.coupon_id
  orderPush.address=this.addressInfo.address
  orderPush.nickname=this.addressInfo.nikeName
  orderPush.phone=this.addressInfo.phone
  orderPush.order_create_time=this.formatCurrentDate()
  orderPush.order_pay_time=this.formatCurrentDate()
  let num = await databaseZone.upsert(orderPush);
  hilog.info(0x0000, 'testTag', `Succeeded in upserting order data, result: ${num}`);
  if (num&amp;gt;0) {
    for (let i = 0; i &amp;lt; this.productList.length; i++) {
      if (this.productList[i].isNeedPay) {
        let item = new cart_product_list();
        item.id=this.productList[i].id
        let listData = await databaseZone.delete(item);
        hilog.info(0x0000, 'testTag', `Succeeded in deleting cart item, result: ${listData}`);
      }
    }
    let eventData: emitter.EventData = {
      data: {}
    };
    let innerEvent: emitter.InnerEvent = {
      eventId: 1012,
      priority: emitter.EventPriority.HIGH
    };
    emitter.emit(innerEvent, eventData);
    router.replaceUrl({url:'pages/view/OrderSuccessPage',params:orderPush})
  }
} else {
  showToast("Please select an address first")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;})&lt;/p&gt;

&lt;p&gt;This implements the association between order settlement and coupons.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Hema - Choose Coupon (59)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 17:00:50 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-hema-choose-coupon-59-74p</link>
      <guid>https://dev.to/whl15290959515/imitation-hema-choose-coupon-59-74p</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented coupon query on the order confirmation page, but lacked other coupon-related logic. Our goal is to use corresponding coupons during order settlement. Now, we need to enable coupon selection on the order confirmation page, presenting it in a pop-up window for user convenience.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
To display coupons in a pop-up window:&lt;/p&gt;

&lt;p&gt;Create a custom pop-up dialog.&lt;br&gt;
Query all coupon data to show both usable and unusable coupons.&lt;br&gt;
Inform users of usable coupon amounts and the remaining amount needed for unusable coupons to be valid.&lt;br&gt;
Allow clicking on usable coupons to modify the settlement amount and display the selected coupon amount.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, create the pop-up window with two-way binding for coupon amount:&lt;/p&gt;

&lt;p&gt;@Preview&lt;br&gt;
@CustomDialog&lt;br&gt;
export struct CouponCheckDialog {&lt;br&gt;
  @State user: User | null = null&lt;br&gt;
  @State couponList: CouponMall[] = []&lt;br&gt;
  controller: CustomDialogController;&lt;br&gt;
  @State lessThanLimit: CouponMall[] = []&lt;br&gt;
  @State greaterOrEqualLimit: CouponMall[] = []&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/prop"&gt;@prop&lt;/a&gt; price: number&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; couponPrice: number&lt;/p&gt;

&lt;p&gt;async aboutToAppear(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value != "") {&lt;br&gt;
      this.user = JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
    let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
    let condition = new cloudDatabase.DatabaseQuery(coupon_mall);&lt;br&gt;
    condition.equalTo("user_id", this.user?.user_id)&lt;br&gt;
    let listData = await databaseZone.query(condition);&lt;br&gt;
    let json = JSON.stringify(listData)&lt;br&gt;
    let data: CouponMall[] = JSON.parse(json)&lt;br&gt;
    this.couponList = data&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.splitCouponsByLimit(data, this.price)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
  Header(type: number) {&lt;br&gt;
    Text(type == 0 ? "Usable Coupons" : "Unusable Coupons")&lt;br&gt;
      .width('100%')&lt;br&gt;
      .padding(10)&lt;br&gt;
      .textAlign(TextAlign.Start)&lt;br&gt;
      .fontColor(Color.Black)&lt;br&gt;
      .fontSize(16)&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
  Item(item: CouponMall) {&lt;br&gt;
    Column({ space: 10 }) {&lt;br&gt;
      Row({ space: 10 }) {&lt;br&gt;
        Column() {&lt;br&gt;
          Text("¥" + item.price)&lt;br&gt;
            .fontSize(30)&lt;br&gt;
            .fontColor(Color.Red)&lt;br&gt;
            .fontWeight(FontWeight.Bold)&lt;br&gt;
          Text("Valid for orders over ¥" + item.limit_amount)&lt;br&gt;
            .fontColor(Color.Red)&lt;br&gt;
            .fontWeight(FontWeight.Bold)&lt;br&gt;
            .fontSize(12)&lt;br&gt;
        }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Column({ space: 10 }) {
      Text(item.type_str)
        .fontColor(Color.Black)
        .fontWeight(FontWeight.Bold)
        .fontSize(16)

      Text(item.txt)
        .fontColor(Color.Grey)
        .fontSize(12)
    }

    Blank()
    Text("Ready to Use")
      .width(80)
      .height(80)
      .borderRadius(40)
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .fontColor(Color.White)
      .backgroundColor(Color.Red)
  }
  .width('100%')
  .justifyContent(FlexAlign.SpaceBetween)

  Divider().width('100%').height(0.8)
    .color("#e6e6e6")
  Text("Valid from " + item.start_time + " to " + item.end_time)
    .fontSize(12)
    .fontColor(Color.Grey)
}
.margin({ top: 10 })
.padding(10)
.backgroundColor(Color.White)
.borderRadius(10)
.onClick(() =&amp;gt; {
  this.couponPrice = item.price
  this.controller.close()
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
  NotItem(item: CouponMall) {&lt;br&gt;
    Column({ space: 10 }) {&lt;br&gt;
      Row({ space: 10 }) {&lt;br&gt;
        Column() {&lt;br&gt;
          Text("¥" + item.price)&lt;br&gt;
            .fontSize(30)&lt;br&gt;
            .fontColor(Color.Grey)&lt;br&gt;
            .fontWeight(FontWeight.Bold)&lt;br&gt;
          Text("Valid for orders over ¥" + item.limit_amount)&lt;br&gt;
            .fontColor(Color.Grey)&lt;br&gt;
            .fontWeight(FontWeight.Bold)&lt;br&gt;
            .fontSize(12)&lt;br&gt;
        }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Column({ space: 10 }) {
      Text(item.type_str)
        .fontColor(Color.Grey)
        .fontWeight(FontWeight.Bold)
        .fontSize(16)

      Text(item.txt)
        .fontColor(Color.Grey)
        .fontSize(12)
    }

    Blank()
    Text("Unusable")
      .width(80)
      .height(80)
      .borderRadius(40)
      .fontSize(14)
      .textAlign(TextAlign.Center)
      .fontColor(Color.White)
      .backgroundColor(Color.Grey)
  }
  .width('100%')
  .justifyContent(FlexAlign.SpaceBetween)

  Divider().width('100%').height(0.8)
    .color("#e6e6e6")

  Text("Valid from " + item.start_time + " to " + item.end_time)
    .fontSize(12)
    .fontColor(Color.Grey)
  Text() {
    Span("Reason for unavailability: ")
      .fontColor(Color.Red)
      .fontSize(12)
    Span("Order amount needs ¥")
      .fontColor(Color.Gray)
      .fontSize(12)
    Span("" + (item.limit_amount - this.price))
      .fontColor(Color.Red)
      .fontSize(12)
    Span(" more to meet the threshold")
      .fontColor(Color.Gray)
      .fontSize(12)
  }
  .backgroundColor("#fffacfcf")
  .padding(5)
  .borderRadius(5)
}
.margin({ top: 10 })
.padding(10)
.backgroundColor(Color.White)
.borderRadius(10)
.onClick(() =&amp;gt; {
  showToast("Coupon is not usable")
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      Text("Select Coupon")&lt;br&gt;
        .fontSize(18)&lt;br&gt;
        .fontColor(Color.Black)&lt;br&gt;
        .fontWeight(FontWeight.Bold)&lt;br&gt;
        .width('100%')&lt;br&gt;
        .textAlign(TextAlign.Center)&lt;br&gt;
        .padding(10)&lt;br&gt;
        .backgroundColor(Color.White)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  List({ space: 10 }) {
    ListItemGroup({ header: this.Header(0) }) {
      ForEach(this.lessThanLimit, (item: CouponMall, index: number) =&amp;gt; {
        ListItem() {
          this.Item(item)
        }
      })
    }
    ListItemGroup({ header: this.Header(1) }) {
      ForEach(this.greaterOrEqualLimit, (item: CouponMall, index: number) =&amp;gt; {
        ListItem() {
          this.NotItem(item)
        }
      })
    }
  }
  .padding(10)

  Button("Confirm Selection", { type: ButtonType.Normal })
    .width('90%')
    .height(50)
    .backgroundColor(Color.Red)
    .fontColor(Color.White)
    .borderRadius(25)
    .margin({ top: 20, bottom: 30 })
    .onClick(() =&amp;gt; {
      this.controller.close()
    })
}
.width('100%')
.backgroundColor(Color.White)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;splitCouponsByLimit(coupons: CouponMall[], price: number) {&lt;br&gt;
    const lessThanLimit = coupons.filter(coupon =&amp;gt;&lt;br&gt;
      coupon.limit_amount &amp;lt;= price&lt;br&gt;
    );&lt;br&gt;
    this.lessThanLimit = lessThanLimit;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const greaterOrEqualLimit = coupons.filter(coupon =&amp;gt;
  coupon.limit_amount &amp;gt; price
);
this.greaterOrEqualLimit = greaterOrEqualLimit;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Reference the pop-up in the order confirmation page:&lt;/p&gt;

&lt;p&gt;couponController: CustomDialogController | null = new CustomDialogController({&lt;br&gt;
  builder: CouponCheckDialog({&lt;br&gt;
    couponPrice: this.couponPrice,&lt;br&gt;
    price: this.price()&lt;br&gt;
  }),&lt;br&gt;
  alignment: DialogAlignment.Bottom,&lt;br&gt;
  customStyle: true&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Modify the coupon display component logic:&lt;/p&gt;

&lt;p&gt;Row() {&lt;br&gt;
  Text("Coupons")&lt;br&gt;
    .fontSize(14)&lt;br&gt;
    .fontColor(Color.Black)&lt;/p&gt;

&lt;p&gt;if (this.getCoupon() &amp;gt; 0) {&lt;br&gt;
    if (this.couponPrice &amp;gt; 0) {&lt;br&gt;
      Text("Selected: -¥" + this.couponPrice + " &amp;gt;")&lt;br&gt;
        .fontSize(14)&lt;br&gt;
        .fontColor(Color.Red)&lt;br&gt;
        .onClick(() =&amp;gt; {&lt;br&gt;
          this.couponController?.open()&lt;br&gt;
        })&lt;br&gt;
    } else {&lt;br&gt;
      Text(this.getCoupon() + " available &amp;gt;")&lt;br&gt;
        .fontSize(14)&lt;br&gt;
        .fontColor(Color.Red)&lt;br&gt;
        .onClick(() =&amp;gt; {&lt;br&gt;
          this.couponController?.open()&lt;br&gt;
        })&lt;br&gt;
    }&lt;br&gt;
  } else {&lt;br&gt;
    Text("No available coupons")&lt;br&gt;
      .fontSize(14)&lt;br&gt;
      .fontColor(Color.Black)&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
.padding(10)&lt;br&gt;
.width('100%')&lt;br&gt;
.justifyContent(FlexAlign.SpaceBetween)&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Hema - Coupon Logic Optimization (58)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:58:42 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-hema-coupon-logic-optimization-58-5bj4</link>
      <guid>https://dev.to/whl15290959515/imitation-hema-coupon-logic-optimization-58-5bj4</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
We have successfully implemented coupon redemption and display features, bringing our application closer to a complete e-commerce platform. However, a new issue arises: after users redeem their new user coupons, the new user coupon module remains visible. Since our data is queried from the cloud database, we need to find a corresponding field to control the visibility of this module. Specifically, the module should hide after the user redeems the coupons, remain hidden when the user is not logged in, and display only when the user is logged in and eligible for new user coupons. Additionally, during checkout, we need to determine how many coupons are applicable based on the order amount.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
Our coupon display uses a component-based approach. When the user is not logged in, the component does not destroy, and the aboutToAppear lifecycle method does not execute again, preventing updates to the user information. To solve this, we need to ensure user information is fetched in real-time. We'll use the isvip field, 预留 during table creation, to determine if a user is a new user. On the order confirmation page, we'll filter applicable coupons based on the minimum spend requirement.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, after redeeming coupons, update the isvip status via callback and receive user information after login:&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; user: User|null&lt;br&gt;
private callback?: () =&amp;gt; void&lt;/p&gt;

&lt;p&gt;Button('Redeem Now', { type: ButtonType.Normal })&lt;br&gt;
  .width(240)&lt;br&gt;
  .height(40)&lt;br&gt;
  .backgroundColor('#FF0000')&lt;br&gt;
  .fontColor(Color.White)&lt;br&gt;
  .borderRadius(20)&lt;br&gt;
  .margin({ bottom: 16 })&lt;br&gt;
  .onClick(async () =&amp;gt; {&lt;br&gt;
    try {&lt;br&gt;
      for (const item of this.couponList) {&lt;br&gt;
        const coupon = new coupon_mall();&lt;br&gt;
        coupon.id = Math.floor(Math.random() * 1000000);&lt;br&gt;
        coupon.user_id = this.user!.user_id;&lt;br&gt;
        coupon.coupon_id = item.coupon_id;&lt;br&gt;
        coupon.price = Number(item.price);&lt;br&gt;
        coupon.type = 0;&lt;br&gt;
        coupon.limit_amount = item.limit_amount;&lt;br&gt;
        coupon.start_time = this.creatTime();&lt;br&gt;
        coupon.end_time = this.endTime();&lt;br&gt;
        coupon.type_str = item.type;&lt;br&gt;
        coupon.txt = "Valid for all products";&lt;br&gt;
        const databaseZone = cloudDatabase.zone('default');&lt;br&gt;
        await databaseZone.upsert(coupon); // Wait for each upsert to complete&lt;br&gt;
      }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  // Execute after all loops complete
  showToast("Coupons redeemed successfully");
  this.callback!();
} catch (error) {
  hilog.error(0x0000, 'testTag', `Insertion failed: ${error}`);
  showToast("Failed to redeem coupons");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;})&lt;/p&gt;

&lt;p&gt;Implement the callback:&lt;/p&gt;

&lt;p&gt;CouponComponent({&lt;br&gt;
  home_activity: this.home_new_people_coupon,&lt;br&gt;
  couponList: this.couponList,&lt;br&gt;
  callback: async () =&amp;gt; {&lt;br&gt;
    let users = new user();&lt;br&gt;
    users.id = this.user!.id;&lt;br&gt;
    users.user_id = this.user!.user_id;&lt;br&gt;
    users.user_name = this.user!.user_name;&lt;br&gt;
    users.psw = this.user!.psw;&lt;br&gt;
    users.is_vip = false;&lt;br&gt;
    users.user_code = this.user!.user_code;&lt;br&gt;
    users.is_log_off = this.user!.is_vip;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let num = await databaseZone.upsert(users);
StorageUtils.set("user", JSON.stringify(users));

if (num &amp;gt; 0) {
  let condition3 = new cloudDatabase.DatabaseQuery(user);
  condition3
    .equalTo("user_name", this.user?.user_name)
    .and()
    .equalTo("psw", this.user?.psw);

  let listData3 = await databaseZone.query(condition3);
  let json3 = JSON.stringify(listData3);
  let data3: User[] = JSON.parse(json3);
  this.user = data3[0];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;},&lt;br&gt;
  user: this.user&lt;br&gt;
})&lt;br&gt;
.visibility(this.user?.is_vip ? Visibility.Visible : Visibility.None)&lt;/p&gt;

&lt;p&gt;Control visibility using isvip and handle post-login user information:&lt;/p&gt;

&lt;p&gt;let innerEvent2: emitter.InnerEvent = {&lt;br&gt;
  eventId: 2001&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;let callback2: Callback = async (eventData: emitter.EventData) =&amp;gt; {&lt;br&gt;
  console.info(&lt;code&gt;eventData: ${JSON.stringify(eventData)}&lt;/code&gt;);&lt;br&gt;
  const value = await StorageUtils.getAll('user');&lt;br&gt;
  if (value != "") {&lt;br&gt;
    this.user = JSON.parse(value);&lt;br&gt;
  } else {&lt;br&gt;
    this.userInfo = null;&lt;br&gt;
    this.user = null;&lt;br&gt;
  }&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;emitter.on(innerEvent2, callback2);&lt;/p&gt;

&lt;p&gt;On the order confirmation page, query available coupons:&lt;/p&gt;

&lt;p&gt;let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
let condition = new cloudDatabase.DatabaseQuery(coupon_mall);&lt;br&gt;
condition&lt;br&gt;
  .equalTo("user_id", this.user?.user_id)&lt;br&gt;
  .and()&lt;br&gt;
  .equalTo("type", 0);&lt;/p&gt;

&lt;p&gt;let listData = await databaseZone.query(condition);&lt;br&gt;
let json = JSON.stringify(listData);&lt;br&gt;
let data: CouponMall[] = JSON.parse(json);&lt;br&gt;
this.couponList = data;&lt;/p&gt;

&lt;p&gt;Filter applicable coupons based on the order amount:&lt;/p&gt;

&lt;p&gt;getCoupon(): number {&lt;br&gt;
  let eligibleCoupons = this.couponList.filter(coupon =&amp;gt;&lt;br&gt;
    coupon.limit_amount &amp;lt;= this.price()&lt;br&gt;
  ).length;&lt;br&gt;
  return eligibleCoupons;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Update the UI:&lt;/p&gt;

&lt;p&gt;Row() {&lt;br&gt;
  Text("Coupons")&lt;br&gt;
    .fontSize(14)&lt;br&gt;
    .fontColor(Color.Black);&lt;/p&gt;

&lt;p&gt;if (this.getCoupon() &amp;gt; 0) {&lt;br&gt;
    Text(&lt;code&gt;${this.getCoupon()} available&lt;/code&gt;)&lt;br&gt;
      .fontSize(14)&lt;br&gt;
      .fontColor(Color.Red);&lt;br&gt;
  } else {&lt;br&gt;
    Text("No available coupons")&lt;br&gt;
      .fontSize(14)&lt;br&gt;
      .fontColor(Color.Black);&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
.padding(10)&lt;br&gt;
.width('100%')&lt;br&gt;
.justifyContent(FlexAlign.SpaceBetween)&lt;/p&gt;

&lt;p&gt;With these changes, our coupon logic is becoming more comprehensive.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Hema - Coupon Display Page (57)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:57:50 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-hema-coupon-display-page-57-5999</link>
      <guid>https://dev.to/whl15290959515/imitation-hema-coupon-display-page-57-5999</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the coupon redemption function and successfully queried coupon information from the cloud. Now we need to create a coupon display page to show users the coupons under their current account, helping them make better purchasing decisions. Since coupons can have multiple statuses, we also need to handle the distinction between different statuses during display.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
To implement the coupon display, we first need to get the currently logged-in user. Since we recorded the user ID when redeeming coupons, we'll query coupons based on this user ID. When the page loads, we'll fetch the corresponding coupon data from the cloud and display it in a list.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, add a top bar to the newly created coupon display page:&lt;/p&gt;

&lt;p&gt;CommonTopBar({ title: "Coupons", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;/p&gt;

&lt;p&gt;Retrieve the currently stored user information:&lt;/p&gt;

&lt;p&gt;@State user: User|null=null&lt;br&gt;
const value = await StorageUtils.getAll('user');&lt;br&gt;
if (value != "") {&lt;br&gt;
  this.user=JSON.parse(value)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Query the corresponding coupon list based on the current user ID:&lt;/p&gt;

&lt;p&gt;@State couponList:CouponMall[]=[]&lt;/p&gt;

&lt;p&gt;let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
let condition = new cloudDatabase.DatabaseQuery(coupon_mall);&lt;br&gt;
condition.equalTo("user_id",this.user?.user_id)&lt;br&gt;
let listData = await databaseZone.query(condition);&lt;br&gt;
let json = JSON.stringify(listData)&lt;br&gt;
let data:CouponMall[]= JSON.parse(json)&lt;br&gt;
this.couponList=data&lt;/p&gt;

&lt;p&gt;After retrieving the data, add a list component:&lt;/p&gt;

&lt;p&gt;List({space:10}){&lt;br&gt;
  ForEach(this.couponList,(item:CouponMall,index:number)=&amp;gt;{&lt;br&gt;
    ListItem(){&lt;br&gt;
      // Item content will be defined using &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
    }&lt;br&gt;
  })&lt;br&gt;
}&lt;br&gt;
.padding(10)&lt;/p&gt;

&lt;p&gt;Define the item layout using &lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
Item(item:CouponMall){&lt;br&gt;
  Column({space:10}){&lt;br&gt;
    Row({space:10}){&lt;br&gt;
      Column(){&lt;br&gt;
        Text("¥"+item.price)&lt;br&gt;
          .fontSize(30)&lt;br&gt;
          .fontColor(Color.Red)&lt;br&gt;
          .fontWeight(FontWeight.Bold)&lt;br&gt;
        Text("Minimum spend: ¥"+item.limit_amount)&lt;br&gt;
          .fontColor(Color.Red)&lt;br&gt;
          .fontWeight(FontWeight.Bold)&lt;br&gt;
          .fontSize(12)&lt;br&gt;
      }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Column({space:10}){
    Text(item.type_str)
      .fontColor(Color.Black)
      .fontWeight(FontWeight.Bold)
      .fontSize(16)

    Text(item.txt)
      .fontColor(Color.Grey)
      .fontSize(12)
  }
  Blank()
  Text(this.getStatusText(item))
    .width(80)
    .height(80)
    .borderRadius(40)
    .fontSize(14)
    .textAlign(TextAlign.Center)
    .fontColor(this.getStatusColor(item))
    .backgroundColor(this.getStatusBgColor(item))
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Divider().width('100%').height(0.8)
  .color("#e6e6e6")
Text("Valid from "+item.start_time+" to "+item.end_time)
  .fontSize(12)
  .fontColor(Color.Grey)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}.padding(10)&lt;br&gt;
  .backgroundColor(Color.White)&lt;br&gt;
  .borderRadius(10)&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Helper methods to determine status text and colors&lt;br&gt;
getStatusText(item: CouponMall): string {&lt;br&gt;
  const now = new Date();&lt;br&gt;
  const endDate = new Date(item.end_time);&lt;br&gt;
  const startDate = new Date(item.start_time);&lt;/p&gt;

&lt;p&gt;if (now &amp;lt; startDate) {&lt;br&gt;
    return "Upcoming";&lt;br&gt;
  } else if (now &amp;gt; endDate) {&lt;br&gt;
    return "Expired";&lt;br&gt;
  } else {&lt;br&gt;
    return "Available";&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;getStatusColor(item: CouponMall): ResourceStr {&lt;br&gt;
  const now = new Date();&lt;br&gt;
  const endDate = new Date(item.end_time);&lt;br&gt;
  const startDate = new Date(item.start_time);&lt;/p&gt;

&lt;p&gt;if (now &amp;lt; startDate) {&lt;br&gt;
    return "#007DFF"; // Blue for upcoming&lt;br&gt;
  } else if (now &amp;gt; endDate) {&lt;br&gt;
    return "#888888"; // Grey for expired&lt;br&gt;
  } else {&lt;br&gt;
    return Color.White; // White for available (on red background)&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;getStatusBgColor(item: CouponMall): ResourceStr {&lt;br&gt;
  const now = new Date();&lt;br&gt;
  const endDate = new Date(item.end_time);&lt;br&gt;
  const startDate = new Date(item.start_time);&lt;/p&gt;

&lt;p&gt;if (now &amp;lt; startDate) {&lt;br&gt;
    return "#E6F4FF"; // Light blue for upcoming&lt;br&gt;
  } else if (now &amp;gt; endDate) {&lt;br&gt;
    return "#F5F5F5"; // Light grey for expired&lt;br&gt;
  } else {&lt;br&gt;
    return Color.Red; // Red for available&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Reference the item layout in the ListItem:&lt;/p&gt;

&lt;p&gt;List({space:10}){&lt;br&gt;
  ForEach(this.couponList,(item:CouponMall,index:number)=&amp;gt;{&lt;br&gt;
    ListItem(){&lt;br&gt;
      this.Item(item)&lt;br&gt;
    }&lt;br&gt;
  })&lt;br&gt;
}&lt;br&gt;
.padding(10)&lt;/p&gt;

&lt;p&gt;Execute the code to view the display effect of the current coupon list.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Hema - Get Coupons (56)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:55:32 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-hema-get-coupons-56-3faf</link>
      <guid>https://dev.to/whl15290959515/imitation-hema-get-coupons-56-3faf</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In previous feature developments, some functions only had display capabilities without any interaction with the cloud. Through subsequent iterations, more functionalities have gained interactive capabilities. In this section, we will start adding business logic to those static display modules, beginning with implementing the new user coupon redemption feature on the home page.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
For new user coupons, we have defined fields during creation, including coupon ID, denomination, minimum applicable amount, etc. Since we need to bind coupons with users, we need to create a new coupon table, populate it with existing coupon data, and add a user ID field to facilitate user-based querying.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, create the corresponding coupon table and define fields:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "objectTypeName": "coupon_mall",&lt;br&gt;
  "fields": [&lt;br&gt;
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},&lt;br&gt;
    {"fieldName": "user_id", "fieldType": "Integer"},&lt;br&gt;
    {"fieldName": "coupon_id", "fieldType": "Integer", "notNull": true, "defaultValue": 0},&lt;br&gt;
    {"fieldName": "price", "fieldType": "Double"},&lt;br&gt;
    {"fieldName": "type", "fieldType": "Integer"},&lt;br&gt;
    {"fieldName": "limit_amount", "fieldType": "Double"},&lt;br&gt;
    {"fieldName": "start_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "end_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "type_str", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "txt", "fieldType": "String"}&lt;br&gt;
  ],&lt;br&gt;
  "indexes": [&lt;br&gt;
    {"indexName": "field1Index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}&lt;br&gt;
  ],&lt;br&gt;
  "permissions": [&lt;br&gt;
    {"role": "World", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After adding the required fields, generate corresponding entities and database classes:&lt;/p&gt;

&lt;p&gt;import { cloudDatabase } from '&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.CloudFoundationKit';&lt;/p&gt;

&lt;p&gt;class coupon_mall extends cloudDatabase.DatabaseObject {&lt;br&gt;
  public id: number;&lt;br&gt;
  public user_id: number;&lt;br&gt;
  public coupon_id = 0;&lt;br&gt;
  public price: number;&lt;br&gt;
  public type: number;&lt;br&gt;
  public limit_amount: number;&lt;br&gt;
  public start_time: string;&lt;br&gt;
  public end_time: string;&lt;br&gt;
  public type_str: string;&lt;br&gt;
  public txt: string;&lt;/p&gt;

&lt;p&gt;public naturalbase_ClassName(): string {&lt;br&gt;
    return 'coupon_mall';&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;export { coupon_mall };&lt;/p&gt;

&lt;p&gt;class CouponMall {&lt;br&gt;
    id: number;&lt;br&gt;
    user_id: number;&lt;br&gt;
    coupon_id: number = 0;&lt;br&gt;
    price: number;&lt;br&gt;
    type: number;&lt;br&gt;
    limit_amount: number;&lt;br&gt;
    start_time: string;&lt;br&gt;
    end_time: string;&lt;br&gt;
    type_str: string;&lt;br&gt;
    txt: string;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor() {
}


setId(id: number): void {
    this.id = id;
}

getId(): number  {
    return this.id;
}

setUser_id(user_id: number): void {
    this.user_id = user_id;
}

getUser_id(): number  {
    return this.user_id;
}

setCoupon_id(coupon_id: number): void {
    this.coupon_id = coupon_id;
}

getCoupon_id(): number  {
    return this.coupon_id;
}

setPrice(price: number): void {
    this.price = price;
}

getPrice(): number  {
    return this.price;
}

setType(type: number): void {
    this.type = type;
}

getType(): number  {
    return this.type;
}

setLimit_amount(limit_amount: number): void {
    this.limit_amount = limit_amount;
}

getLimit_amount(): number  {
    return this.limit_amount;
}

setStart_time(start_time: string): void {
    this.start_time = start_time;
}

getStart_time(): string  {
    return this.start_time;
}

setEnd_time(end_time: string): void {
    this.end_time = end_time;
}

getEnd_time(): string  {
    return this.end_time;
}

setType_str(type_str: string): void {
    this.type_str = type_str;
}

getType_str(): string  {
    return this.type_str;
}

setTxt(txt: string): void {
    this.txt = txt;
}

getTxt(): string  {
    return this.txt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;export { CouponMall };&lt;/p&gt;

&lt;p&gt;After generating the files, add corresponding logic to the "Redeem Now" button in the new user coupon module on the home page. Since there are multiple coupons, we need to loop through and upload them to the cloud database:&lt;/p&gt;

&lt;p&gt;import { coupon_mall } from "../clouddb/coupon_mall"&lt;br&gt;
import { couponInfo } from "../entity/couponInfo"&lt;br&gt;
import { homeNewPeopleCoupon } from "../entity/homeNewPeopleCoupon"&lt;br&gt;
import { cloudDatabase } from "&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.CloudFoundationKit"&lt;br&gt;
import { hilog } from "&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.PerformanceAnalysisKit"&lt;br&gt;
import showToast from "../utils/ToastUtils"&lt;br&gt;
import { StorageUtils } from "../utils/StorageUtils"&lt;br&gt;
import { User } from "../entity/User"&lt;/p&gt;

&lt;p&gt;@Component&lt;br&gt;
@Preview&lt;br&gt;
export struct CouponComponent {&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; home_activity:homeNewPeopleCoupon|null&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; couponList:couponInfo[]&lt;br&gt;
  @State user: User|null=null&lt;/p&gt;

&lt;p&gt;async aboutToAppear(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value!='') {&lt;br&gt;
      this.user=JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      Row() {&lt;br&gt;
        Text(this.home_activity?.title)&lt;br&gt;
          .fontSize(20)&lt;br&gt;
          .fontColor('#FF0000')&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Text(this.home_activity?.msg)
      .fontSize(14)
      .fontColor('#888888')
      .margin({left:10})
  }
  .width('100%')
  .padding(16)

  List({ space: 10 }) {
    ForEach(this.couponList, (item:couponInfo) =&amp;gt; {
      ListItem() {
        Column() {
          Text(item.price)
            .fontSize(22)
            .fontColor('#FF4444')
            .margin({ bottom: 8 })

          Text(item.type)
            .fontSize(12)
            .fontColor('#FF4444')
        }
        .padding(10)
        .backgroundColor("#ffffff")
        .borderRadius(8)
      }
    })
  }
  .margin({left:50})
  .listDirection(Axis.Horizontal)
  .width('100%')
  .height(80)

  Button('Redeem Now', { type: ButtonType.Normal })
    .width(240)
    .height(40)
    .backgroundColor('#FF0000')
    .fontColor(Color.White)
    .borderRadius(20)
    .margin({ bottom: 16 })
    .onClick(async ()=&amp;gt;{
      for (let i = 0; i &amp;lt; this.couponList.length; i++) {
        let coupon=new coupon_mall()
        coupon.id=Math.floor(Math.random() * 1000000);
        coupon.user_id=this.user!.user_id
        coupon.coupon_id=this.couponList[i].coupon_id
        coupon.price=Number(this.couponList[i].price)
        coupon.type=0
        coupon.limit_amount=this.couponList[i].limit_amount
        coupon.start_time=this.creatTime()
        coupon.end_time=this.endTime()
        coupon.type_str=this.couponList[i].type
        coupon.txt="Valid for all products"
        let databaseZone = cloudDatabase.zone('default');
        let num = await databaseZone.upsert(coupon);
        hilog.info(0x0000, 'testTag', `Succeeded in upserting data, result: ${num}`);
        if (num&amp;gt;0) {
          showToast("Coupon redeemed successfully")
        }
      }
    })
}
.backgroundColor("#fffce2be")
.width('95%')
.margin({top:10})
.borderRadius(20)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;creatTime(): string {&lt;br&gt;
    const now = new Date();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');

return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;endTime(): string {&lt;br&gt;
    const now = new Date();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');

return `${year}-${month}-${parseInt(day)+7} ${hours}:${minutes}:${seconds}`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After completing the implementation, execute the code and click the coupon redemption button to test the functionality.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Safety Lock Verification (55)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:54:43 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-safety-lock-verification-55-50ig</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-safety-lock-verification-55-50ig</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the display function for recycling fund withdrawal records, enriching the content related to recycling funds. In the previous business logic, we added a security lock setting function. Although we successfully set up the security lock and submitted the corresponding table information to the cloud, we haven't used the security lock in the withdrawal process. In this section, we will integrate the security lock with the withdrawal process to enhance the security of our functions.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
First, when entering the withdrawal page, we need to check if there is data in the security lock table under the current user ID. If there is data, we obtain the current security lock status. If the security lock is enabled, a pop-up verification will be triggered when the user clicks the withdrawal button. The value drawn by the user in the pop-up will be matched against the security lock value set in the system. If the match is successful, the record addition operation will be executed; if not, the user will be prompted that the security lock verification failed.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, query the corresponding table content on the withdrawal page:&lt;/p&gt;

&lt;p&gt;let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
let condition3 = new cloudDatabase.DatabaseQuery(verify_info);&lt;br&gt;
condition3.equalTo("user_id", this.user?.user_id);&lt;br&gt;
let listData3 = await databaseZone.query(condition3);&lt;br&gt;
let json3 = JSON.stringify(listData3);&lt;br&gt;
let data3: VerifyInfo[] = JSON.parse(json3);&lt;br&gt;
this.verifyInfo = data3;&lt;/p&gt;

&lt;p&gt;Then perform non-null judgment on the data source and check the security lock status:&lt;/p&gt;

&lt;p&gt;if (this.verifyInfo.length &amp;gt; 0) {&lt;br&gt;
  if (this.verifyInfo[0].open_lock) {&lt;br&gt;
    // Security lock is enabled, proceed with withdrawal logic&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After confirming the above checks, we need to create a verification pop-up:&lt;/p&gt;

&lt;p&gt;import showToast from '../utils/ToastUtils';&lt;/p&gt;

&lt;p&gt;@Preview&lt;br&gt;
@CustomDialog&lt;br&gt;
export struct WithdrawalLockDialog {&lt;br&gt;
  @State passwords: Number[] = [];&lt;br&gt;
  public callback: (passwords: string) =&amp;gt; void = (): void =&amp;gt; {};&lt;br&gt;
  private patternLockController: PatternLockController = new PatternLockController();&lt;br&gt;
  controller: CustomDialogController;&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column({ space: 10 }) {&lt;br&gt;
      Text("Please verify your security password!")&lt;br&gt;
        .fontColor(Color.White)&lt;br&gt;
        .fontWeight(FontWeight.Bold)&lt;br&gt;
        .fontSize(16)&lt;br&gt;
        .width('100%')&lt;br&gt;
        .textAlign(TextAlign.Center)&lt;br&gt;
        .padding(10)&lt;br&gt;
        .backgroundColor('#FF6363');&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  PatternLock(this.patternLockController)
    .sideLength(300)
    .circleRadius(9)
    .pathStrokeWidth(5)
    .borderRadius(10)
    .activeColor('#707070')
    .selectedColor('#707070')
    .pathColor('#707070')
    .backgroundColor('#F5F5F5')
    .autoReset(true)
    .onDotConnect((index: number) =&amp;gt; {
      console.log("onDotConnect index: " + index);
    })
    .onPatternComplete((input: Array&amp;lt;number&amp;gt;) =&amp;gt; {
      if (input.length &amp;lt; 5) {
        showToast("Pattern must connect at least 5 dots");
        return;
      }

      const str: string = JSON.stringify(input);
      this.callback(str);
      this.controller.close();
    });
}
.width('100%')
.height(400)
.backgroundColor(Color.White);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Reference the pop-up on the withdrawal page and pass the input value via callback:&lt;/p&gt;

&lt;p&gt;private dialogController: CustomDialogController = new CustomDialogController({&lt;br&gt;
  builder: WithdrawalLockDialog({&lt;br&gt;
    callback: async (str: string) =&amp;gt; {&lt;br&gt;
      // Process security lock verification result&lt;br&gt;
    }&lt;br&gt;
  }),&lt;br&gt;
  alignment: DialogAlignment.Bottom,&lt;br&gt;
  customStyle: false&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Verify the input value against the stored value in the table and submit corresponding records upon successful verification:&lt;/p&gt;

&lt;p&gt;if (str === this.verifyInfo[0].lock_str) {&lt;br&gt;
  showToast("Verification successful");&lt;/p&gt;

&lt;p&gt;let record = new withdrawal_record();&lt;br&gt;
  record.id = Math.floor(Math.random() * 1000000);&lt;br&gt;
  record.user_id = this.user!.user_id;&lt;br&gt;
  record.bank_name = this.bankList[0].bank_name;&lt;br&gt;
  record.bank_num = this.bankList[0].bank_card;&lt;br&gt;
  record.creat_time = this.year + "-" + this.month + "-" + this.day + " " + this.time;&lt;br&gt;
  record.type_str = '0';&lt;br&gt;
  record.money = this.moneyNum;&lt;br&gt;
  let status = await databaseZone.upsert(record);&lt;/p&gt;

&lt;p&gt;let money = new money_info();&lt;br&gt;
  money.id = Math.floor(Math.random() * 1000000);&lt;br&gt;
  money.user_id = this.user!.user_id;&lt;br&gt;
  money.money = String(this.moneyNum);&lt;br&gt;
  money.all_money = '';&lt;br&gt;
  money.money_type = '1';&lt;br&gt;
  money.address = 'Bank card withdrawal';&lt;br&gt;
  money.year = this.year;&lt;br&gt;
  money.month = this.month;&lt;br&gt;
  money.day = this.day;&lt;br&gt;
  money.time = this.time;&lt;br&gt;
  money.create_time = this.year + "-" + this.month + "-" + this.day + " " + this.time;&lt;br&gt;
  let nums = await databaseZone.upsert(money);&lt;/p&gt;

&lt;p&gt;let userData = new user_info();&lt;br&gt;
  userData.id = this.userInfo!.id;&lt;br&gt;
  userData.user_id = this.userInfo!.user_id;&lt;br&gt;
  userData.sex = this.userInfo!.sex;&lt;br&gt;
  userData.bind_phone = this.userInfo!.bind_phone;&lt;br&gt;
  userData.create_time = this.userInfo!.create_time;&lt;br&gt;
  userData.nickname = this.userInfo!.nickname;&lt;br&gt;
  userData.head_img = this.userInfo!.head_img;&lt;/p&gt;

&lt;p&gt;if (this.userInfo?.money != null) {&lt;br&gt;
    userData.money = this.userInfo!.money - this.moneyNum;&lt;br&gt;
  } else {&lt;br&gt;
    userData.money = 0;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;if (this.userInfo?.points != null) {&lt;br&gt;
    userData.points = this.userInfo!.points;&lt;br&gt;
  } else {&lt;br&gt;
    userData.points = 0;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;let s = await databaseZone.upsert(userData);&lt;/p&gt;

&lt;p&gt;if (s &amp;gt; 0) {&lt;br&gt;
    router.pushUrl({ url: 'pages/recycle/money/SuccessPage' });&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;this.dialogController.close();&lt;br&gt;
} else {&lt;br&gt;
  showToast("Security lock verification failed!");&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Execute the code to check the withdrawal effect with the security lock enable&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Retrieval and Withdrawal Record Query (54)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:54:20 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-retrieval-and-withdrawal-record-query-54-lhd</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-retrieval-and-withdrawal-record-query-54-lhd</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the function of recycling fund withdrawal and successfully displayed the current account's expenditure list. However, the withdrawal-related records were not well presented to users. Users only know that their account has been debited for withdrawal but are unaware of where the recycling funds go. In this section, we will implement the query, addition, and display of recycling fund records.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
To implement these functions, we need to create a new table, populate it with corresponding information based on the currently bound user information, including the withdrawal bank card, withdrawal status, withdrawal time, and withdrawal amount. After users enter the withdrawal record page, query the current user's records via their userid and display them in a list.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, create the corresponding withdrawal record table:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "objectTypeName": "withdrawal_record",&lt;br&gt;
  "fields": [&lt;br&gt;
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},&lt;br&gt;
    {"fieldName": "user_id", "fieldType": "Integer", "notNull": true, "defaultValue": 0},&lt;br&gt;
    {"fieldName": "bank_name", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "bank_num", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "creat_time", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "type_str", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "money", "fieldType": "Double"}&lt;br&gt;
  ],&lt;br&gt;
  "indexes": [&lt;br&gt;
    {"indexName": "field1Index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}&lt;br&gt;
  ],&lt;br&gt;
  "permissions": [&lt;br&gt;
    {"role": "World", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After generating the corresponding entity and database classes, add the required information to the table when submitting a successful withdrawal record:&lt;/p&gt;

&lt;p&gt;let record=new withdrawal_record()&lt;br&gt;
record.id=Math.floor(Math.random() * 1000000)&lt;br&gt;
record.user_id=this.user!.user_id&lt;br&gt;
record.bank_name=this.bankList[0].bank_name&lt;br&gt;
record.bank_num=this.bankList[0].bank_card&lt;br&gt;
record.creat_time=this.year+"-"+this.month+"-"+this.day+" "+this.time&lt;br&gt;
record.type_str='0'&lt;br&gt;
record.money=this.moneyNum&lt;br&gt;
let status =  await databaseZone.upsert(record);&lt;/p&gt;

&lt;p&gt;Next, create a new page to display withdrawal records:&lt;/p&gt;

&lt;p&gt;@Entry&lt;br&gt;
@Component&lt;br&gt;
struct WithdrawalRecordPage {&lt;br&gt;
  @State user: User|null=null&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      CommonTopBar({ title: "Withdrawal Records", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;br&gt;
    }&lt;br&gt;
    .backgroundColor("#F1F3F5")&lt;br&gt;
    .height('100%')&lt;br&gt;
    .width('100%')&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;First, query the data:&lt;/p&gt;

&lt;p&gt;@State user: User|null=null&lt;br&gt;
@State withdrawalRecordList:WithdrawalRecord[]=[]&lt;br&gt;
async aboutToAppear(): Promise {&lt;br&gt;
  const value = await StorageUtils.getAll('user');&lt;br&gt;
  if (value != "") {&lt;br&gt;
    this.user = JSON.parse(value)&lt;br&gt;
  }&lt;br&gt;
  let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
  let condition = new cloudDatabase.DatabaseQuery(withdrawal_record);&lt;br&gt;
  condition.equalTo("user_id", this.user?.user_id)&lt;br&gt;
  let listData = await databaseZone.query(condition);&lt;br&gt;
  let json = JSON.stringify(listData)&lt;br&gt;
  let data: WithdrawalRecord[] = JSON.parse(json)&lt;br&gt;
  if (data.length&amp;gt;0) {&lt;br&gt;
    this.withdrawalRecordList=data&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Then, display the queried data in a list component:&lt;/p&gt;

&lt;p&gt;List({space:10}){&lt;br&gt;
  ForEach(this.withdrawalRecordList,(item:WithdrawalRecord,index:number)=&amp;gt;{&lt;br&gt;
    ListItem(){&lt;br&gt;
      Column({space:10}){&lt;br&gt;
        Row(){&lt;br&gt;
          Text(item.type_str=='0'?"Withdrawal Successful":"Processing")&lt;br&gt;
            .fontColor(item.type_str=='0'?Color.Green:Color.Black)&lt;br&gt;
            .fontSize(16)&lt;br&gt;
            .fontWeight(FontWeight.Bold)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      Text("¥"+item.money+"")
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Black)
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    Row(){
      Text(item.bank_name+" ("+item.bank_num+")")
        .fontColor(Color.Black)
        .fontSize(14)
        .fontWeight(FontWeight.Bold)

      Text(item.creat_time+"")
        .fontSize(14)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Grey)
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
  }
  .padding(10)
  .width('100%')
  .borderRadius(10)
  .backgroundColor(Color.White)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;})&lt;br&gt;
}&lt;br&gt;
.padding(10)&lt;/p&gt;

&lt;p&gt;Now, let's run the code to see the results.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Withdrawal of Recycled Gold (53)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:43:27 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-withdrawal-of-recycled-gold-53-4o0k</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-withdrawal-of-recycled-gold-53-4o0k</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the binding and echo of the bank card. In this section, we will truly implement the function of bank card withdrawal. Before that, we need to further optimize the business logic of the withdrawal page. At the same time, to facilitate the interaction between data, we have added amount and points fields in the personal information module to facilitate the display and hiding of other pages.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
To implement these functions, we first need to obtain the total amount of recycling funds under the current account, so that we can judge whether the user overfills the amount based on this when entering the amount, which reduces a request to the cloud database and avoids resource waste. At the same time, when withdrawing, we also need to generate corresponding records, operate the moneyinfo table, and since we have added fields in userinfo, we also need to operate the userinfo table.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, obtain the total account amount in the userinfo table of the current user on the withdrawal page.&lt;/p&gt;

&lt;p&gt;let condition1=new cloudDatabase.DatabaseQuery(user_info)&lt;br&gt;
    condition1.equalTo("user_id", this.user?.user_id)&lt;br&gt;
    let listData1 = await databaseZone.query(condition1)&lt;br&gt;
    let json1=JSON.stringify(listData1)&lt;br&gt;
    let data1:UserInfo[] = JSON.parse(json1)&lt;br&gt;
    this.userInfo=data1[0]&lt;/p&gt;

&lt;p&gt;After obtaining it, pass it to the custom component for amount filling.&lt;/p&gt;

&lt;p&gt;// Define in the component first&lt;br&gt;
&lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; userInfo:UserInfo|null&lt;/p&gt;

&lt;p&gt;// Pass in data&lt;br&gt;
  InputItem({userInfo:this.userInfo})&lt;/p&gt;

&lt;p&gt;Modify the corresponding verification logic to display the total amount of recycling funds in the current account.&lt;/p&gt;

&lt;p&gt;TextInput({ text: this.text, placeholder: 'Enter withdrawal amount', controller: this.controller })&lt;br&gt;
          .placeholderColor("#999999")&lt;br&gt;
          .placeholderFont({ size: 28, weight: 400 })&lt;br&gt;
          .caretColor("#FCDB29")&lt;br&gt;
          .width(400)&lt;br&gt;
          .height(50)&lt;br&gt;
          .backgroundColor(null)&lt;br&gt;
          .type(InputType.Number)&lt;br&gt;
          .margin(20)&lt;br&gt;
          .fontSize(14)&lt;br&gt;
          .fontColor(Color.Black)&lt;br&gt;
          .onChange((value: string) =&amp;gt; {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        this.moneyNum=Number(value)
        this.text = value
        if (this.moneyNum&amp;gt;0&amp;amp;&amp;amp;this.moneyNum&amp;lt;=300) {
          if (this.moneyNum&amp;gt;this.userInfo!.money) {
            this.isPost=false
          }else {
            this.isPost=true
          }
        }else {
          this.isPost=false
        }
      })
  }
  Divider().width('100%').height(1)
  Text("Withdrawable amount ¥" + this.userInfo?.money + " (Maximum single withdrawal amount: 300)")
    .fontSize(15)
    .fontColor("#333333")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Add a reminder to the user at the submit button.&lt;/p&gt;

&lt;p&gt;if (this.moneyNum&amp;gt;this.userInfo!.money) {&lt;br&gt;
                    showToast('Exceeds the maximum withdrawable amount, please re-enter')&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this way, we first handle the logic, and then operate our two tables at the confirm withdrawal button, input the obtained data and the filled withdrawal amount, we need to subtract the current withdrawal amount from the account total and generate a record.&lt;/p&gt;

&lt;p&gt;Text("Confirm Withdrawal")&lt;br&gt;
              .width('100%')&lt;br&gt;
              .fontColor(Color.White)&lt;br&gt;
              .borderRadius(15)&lt;br&gt;
              .padding(10)&lt;br&gt;
              .textAlign(TextAlign.Center)&lt;br&gt;
              .fontColor(this.isPost?Color.Black:Color.White)&lt;br&gt;
              .backgroundColor(this.isPost?"#ffff6363":$r('app.color.color_999'))&lt;br&gt;
              .onClick(async ()=&amp;gt;{&lt;br&gt;
                if (this.isPost) {&lt;br&gt;
                  let money=new money_info()&lt;br&gt;
                  money.id=Math.floor(Math.random() * 1000000)&lt;br&gt;
                  money.user_id=this.user!.user_id&lt;br&gt;
                  money.money=String(this.moneyNum)&lt;br&gt;
                  money.all_money=''&lt;br&gt;
                  money.money_type='1'&lt;br&gt;
                  money.address='Bank card withdrawal'&lt;br&gt;
                  money.year=this.year&lt;br&gt;
                  money.month=this.month&lt;br&gt;
                  money.day=this.day&lt;br&gt;
                  money.time=this.time&lt;br&gt;
                  money.create_time=this.year+"-"+this.month+"-"+this.day+" "+this.time&lt;br&gt;
                  let nums =  await databaseZone.upsert(money);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              let userData=new user_info()
              userData.id=this.userInfo!.id
              userData.user_id=this.userInfo!.user_id
              userData.sex=this.userInfo!.sex
              userData.bind_phone=this.userInfo!.bind_phone
              userData.create_time=this.userInfo!.create_time
              userData.nickname=this.userInfo!.nickname
              userData.head_img=this.userInfo!.head_img
              if (this.userInfo?.money!=null) {
                userData.money=this.userInfo!.money-this.moneyNum
              }else {
                userData.money=0
              }
              if (this.userInfo?.points!=null) {
                userData.points=this.userInfo!.points
              }else {
                userData.points=0
              }
              let s= await databaseZone.upsert(userData);

              if (s&amp;gt;0) {
                router.pushUrl({url:'pages/recycle/money/SuccessPage'})
              }
            }else {
              if (this.moneyNum==0){
                showToast("Minimum withdrawal amount is 1 yuan per transaction")
              }
              if (this.moneyNum&amp;gt;300) {
                showToast('Daily limit is 300 yuan, please re-enter')
              }
              if (this.moneyNum&amp;gt;this.userInfo!.money) {
                showToast('Exceeds the maximum withdrawable amount, please re-enter')

              }
            }
          })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a successful withdrawal, we need to give the user feedback. At this time, we add a simple page to display the status.&lt;/p&gt;

&lt;p&gt;import { CommonTopBar } from '../../widget/CommonTopBar';&lt;br&gt;
import { router } from '&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.ArkUI';&lt;/p&gt;

&lt;p&gt;@Entry&lt;br&gt;
@Component&lt;br&gt;
struct SuccessPage {&lt;br&gt;
  @State message: string = 'Hello World';&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      CommonTopBar({ title: "Withdrawal Status", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;br&gt;
      Text("Withdrawal Successful")&lt;br&gt;
        .textAlign(TextAlign.Center)&lt;br&gt;
        .fontColor(Color.Black)&lt;br&gt;
        .fontSize(20)&lt;br&gt;
        .fontWeight(FontWeight.Bold)&lt;br&gt;
        .margin({top:100})&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Image($r('app.media.success_money'))
    .height(100)
    .width(100)
    .margin({top:20})



  Text("Confirm")
    .textAlign(TextAlign.Center)
    .width('95%')
    .padding(10)
    .fontColor(Color.White)
    .borderRadius(10)
    .backgroundColor("#fffa4444")
    .margin({top:100})
    .onClick(()=&amp;gt;{
      router.back()
    })
}
.backgroundColor(Color.White)
.height('100%')
.width('100%')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;When we execute the code and click the withdrawal button, we can see that the withdrawal is successful. Next, we return to the recycling fund page to view the total amount and withdrawal records, and we can see that both the total amount and records are displayed on the page.&lt;/p&gt;

&lt;p&gt;The complete code is as follows.&lt;/p&gt;

&lt;p&gt;import { BindBank } from "../../entity/BindBank"&lt;br&gt;
import showToast from "../../utils/ToastUtils"&lt;br&gt;
import { CommonTopBar } from "../../widget/CommonTopBar"&lt;br&gt;
import { BindAlipay } from "./BindAlipay"&lt;br&gt;
import { InputItem } from "./InputItem"&lt;br&gt;
import { router } from "&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.ArkUI"&lt;br&gt;
import { StorageUtils } from "../../utils/StorageUtils"&lt;br&gt;
import { cloudDatabase } from "&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.CloudFoundationKit"&lt;br&gt;
import { bind_bank } from "../../clouddb/bind_bank"&lt;br&gt;
import { User } from "../../entity/User"&lt;br&gt;
import { user_info } from "../../clouddb/user_info"&lt;br&gt;
import { UserInfo } from "../../entity/UserInfo"&lt;br&gt;
import { money_info } from "../../clouddb/MoneyInfo"&lt;br&gt;
let databaseZone = cloudDatabase.zone('default');&lt;/p&gt;

&lt;p&gt;@Entry&lt;br&gt;
@Component&lt;br&gt;
export default struct WithdrawMoneyPage {&lt;br&gt;
  @State fontColor: string = '#182431'&lt;br&gt;
  @State selectedFontColor: string = '#007DFF'&lt;br&gt;
  @State currentIndex: number = 0&lt;br&gt;
  @State alipayAcc:string=''&lt;br&gt;
  @State bindAlipayName:string=''&lt;br&gt;
  @State phoneCode:string=''&lt;br&gt;
  @State user: User|null=null&lt;br&gt;
  @State allMoney:number=0&lt;br&gt;
  @Provide&lt;br&gt;
  isPost:boolean=false&lt;/p&gt;

&lt;p&gt;@Provide&lt;br&gt;
  moneyNum:number=0&lt;/p&gt;

&lt;p&gt;@State bankList:BindBank[]=[]&lt;br&gt;
  @State userInfo:UserInfo|null=null&lt;br&gt;
  @State flag:boolean=false&lt;/p&gt;

&lt;p&gt;@State year:string=''&lt;br&gt;
  @State month:string=''&lt;br&gt;
  @State day:string=''&lt;br&gt;
  @State time:string=''&lt;/p&gt;

&lt;p&gt;async onPageShow(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value != "") {&lt;br&gt;
      this.user = JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
    let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
    let condition = new cloudDatabase.DatabaseQuery(bind_bank);&lt;br&gt;
    condition.equalTo("user_id", this.user?.user_id)&lt;br&gt;
    let listData = await databaseZone.query(condition);&lt;br&gt;
    let json = JSON.stringify(listData)&lt;br&gt;
    let data: BindBank[] = JSON.parse(json)&lt;br&gt;
    if (data.length&amp;gt;0) {&lt;br&gt;
      this.bankList=data&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let condition1=new cloudDatabase.DatabaseQuery(user_info)
condition1.equalTo("user_id", this.user?.user_id)
let listData1 = await databaseZone.query(condition1)
let json1=JSON.stringify(listData1)
let data1:UserInfo[] = JSON.parse(json1)
this.userInfo=data1[0]


this.formatCurrent()

this.flag=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    if (this.flag){&lt;br&gt;
      Column() {&lt;br&gt;
        CommonTopBar({ title: "Withdrawal", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;br&gt;
        Column(){&lt;br&gt;
          BindAlipay({bankList:this.bankList,&lt;br&gt;
            callback:()=&amp;gt;{&lt;br&gt;
              router.pushUrl({url:'pages/recycle/card/BindCardPage'})&lt;br&gt;
            },&lt;br&gt;
            postCallback:()=&amp;gt;{&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        }})
      InputItem({userInfo:this.userInfo})

      Column({space:15}){
        Text("Confirm Withdrawal")
          .width('100%')
          .fontColor(Color.White)
          .borderRadius(15)
          .padding(10)
          .textAlign(TextAlign.Center)
          .fontColor(this.isPost?Color.Black:Color.White)
          .backgroundColor(this.isPost?"#ffff6363":$r('app.color.color_999'))
          .onClick(async ()=&amp;gt;{
            if (this.isPost) {
              let money=new money_info()
              money.id=Math.floor(Math.random() * 1000000)
              money.user_id=this.user!.user_id
              money.money=String(this.moneyNum)
              money.all_money=''
              money.money_type='1'
              money.address='Bank card withdrawal'
              money.year=this.year
              money.month=this.month
              money.day=this.day
              money.time=this.time
              money.create_time=this.year+"-"+this.month+"-"+this.day+" "+this.time
              let nums =  await databaseZone.upsert(money);



              let userData=new user_info()
              userData.id=this.userInfo!.id
              userData.user_id=this.userInfo!.user_id
              userData.sex=this.userInfo!.sex
              userData.bind_phone=this.userInfo!.bind_phone
              userData.create_time=this.userInfo!.create_time
              userData.nickname=this.userInfo!.nickname
              userData.head_img=this.userInfo!.head_img
              if (this.userInfo?.money!=null) {
                userData.money=this.userInfo!.money-this.moneyNum
              }else {
                userData.money=0
              }
              if (this.userInfo?.points!=null) {
                userData.points=this.userInfo!.points
              }else {
                userData.points=0
              }
              let s= await databaseZone.upsert(userData);

              if (s&amp;gt;0) {
                router.pushUrl({url:'pages/recycle/money/SuccessPage'})
              }
            }else {
              if (this.moneyNum==0){
                showToast("Minimum withdrawal amount is 1 yuan per transaction")
              }
              if (this.moneyNum&amp;gt;300) {
                showToast('Daily limit is 300 yuan, please re-enter')
              }
              if (this.moneyNum&amp;gt;this.userInfo!.money) {
                showToast('Exceeds the maximum withdrawable amount, please re-enter')

              }
            }
          })
      }
      .margin({top:50})
    }
    .backgroundColor('#F1F3F5')
    .height('100%')
    .justifyContent(FlexAlign.Start)
    .padding(10)
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;formatCurrent() {&lt;br&gt;
    const now = new Date();&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const years = now.getFullYear();
const months = String(now.getMonth() + 1).padStart(2, '0');
const days = String(now.getDate()).padStart(2, '0');
const m_hours = String(now.getHours()).padStart(2, '0');
const m_minutes = String(now.getMinutes()).padStart(2, '0');
const m_seconds = String(now.getSeconds()).padStart(2, '0');
this.year=String(years)
this.month=months
this.day=days
this.time=m_hours+":"+m_minutes+":"+m_seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;}&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Hema - Binding Bank Card Echo (52)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:41:20 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-hema-binding-bank-card-echo-52-1jk1</link>
      <guid>https://dev.to/whl15290959515/imitation-hema-binding-bank-card-echo-52-1jk1</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the binding of the security lock, all aimed at helping users have a better and safer experience in the withdrawal process. Now we start to formally focus on the withdrawal-related process. First, we perform the binding of the withdrawal bank card. After successful binding, we close the page and echo the data to the withdrawal page.&lt;/p&gt;

&lt;p&gt;Functional Analysis&lt;br&gt;
First, we need to implement the entry of corresponding information. We need to create a corresponding bank card binding page to fill in the information. After the information is filled, the bank card data is submitted to the bindbank table in the cloud. Then, we query the corresponding data in the onPageShow method of the withdrawal page and display it in the card information display module. When operating, it must be associated with our userid.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, we create the corresponding card information entry page.&lt;/p&gt;

&lt;p&gt;import { bind_bank } from '../../clouddb/bind_bank';&lt;br&gt;
import { User } from '../../entity/User';&lt;br&gt;
import { StorageUtils } from '../../utils/StorageUtils';&lt;br&gt;
import { cloudDatabase } from '&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.CloudFoundationKit';&lt;br&gt;
import showToast from '../../utils/ToastUtils';&lt;br&gt;
import { router, Router } from '&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.ArkUI';&lt;br&gt;
import { CommonTopBar } from '../../widget/CommonTopBar';&lt;/p&gt;

&lt;p&gt;let databaseZone = cloudDatabase.zone('default');&lt;/p&gt;

&lt;p&gt;@Entry&lt;br&gt;
@Component&lt;br&gt;
struct BindCardPage {&lt;br&gt;
  @State cardNum: string = '';&lt;br&gt;
  @State bankName: string = '';&lt;br&gt;
  @State peopleName: string = '';&lt;br&gt;
  @State user: User|null=null&lt;/p&gt;

&lt;p&gt;async aboutToAppear(): Promise {&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const value = await StorageUtils.getAll('user');
if (value != "") {
  this.user = JSON.parse(value)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column({space:5}) {&lt;br&gt;
      CommonTopBar({ title: "Add Bank Card", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Row() {
    Text("Card Number")
      .fontColor(Color.Black)
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
    TextInput({ text: this.cardNum, placeholder: 'Please enter bank card number' })
      .placeholderColor("#999999")
      .placeholderFont({ size: 16, weight: 400 })
      .caretColor("#FCDB29")
      .width(400)
      .height(50)
      .backgroundColor(null)
      .type(InputType.Number)
      .margin(20)
      .fontSize(14)
      .fontColor(Color.Black)
      .onChange((value: string) =&amp;gt; {
        this.cardNum = value
      })
  }
  Divider().width('100%').height(0.8)
    .color("#e6e6e6")
    .width('100%')
  Row() {
    Text("Bank")
      .fontColor(Color.Black)
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
    TextInput({ text: this.bankName, placeholder: 'Please enter the bank name' })
      .placeholderColor("#999999")
      .placeholderFont({ size: 16, weight: 400 })
      .caretColor("#FCDB29")
      .width(400)
      .height(50)
      .backgroundColor(null)
      .margin(20)
      .fontSize(14)
      .fontColor(Color.Black)
      .onChange((value: string) =&amp;gt; {
        this.bankName = value
      })
  }
  Divider().width('100%').height(0.8)
    .color("#e6e6e6")
    .width('100%')
  Row() {
    Text("Account Name")
      .fontColor(Color.Black)
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
    TextInput({ text: this.peopleName, placeholder: 'Please enter the account name' })
      .placeholderColor("#999999")
      .placeholderFont({ size: 16, weight: 400 })
      .caretColor("#FCDB29")
      .width(400)
      .height(50)
      .backgroundColor(null)
      .margin(20)
      .fontSize(14)
      .fontColor(Color.Black)
      .onChange((value: string) =&amp;gt; {
        this.peopleName = value
      })
  }
  Text("Bind")

    .width('95%')
    .padding(10)
    .borderRadius(10)
    .textAlign(TextAlign.Center)
    .fontColor(Color.White)
    .backgroundColor("#ffe03636")

}
.height('100%')
.backgroundColor(Color.White)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After adding, we write the submission method to the binding event.&lt;/p&gt;

&lt;p&gt;Text("Bind")&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    .width('95%')
    .padding(10)
    .borderRadius(10)
    .textAlign(TextAlign.Center)
    .fontColor(Color.White)
    .backgroundColor("#ffe03636")
    .onClick(async ()=&amp;gt;{
      let cardInfo=new bind_bank()
      cardInfo.id=Math.floor(Math.random() * 1000000)
      cardInfo.user_id=this.user!.user_id
      cardInfo.bank_name=this.bankName
      cardInfo.bank_card=this.cardNum
      cardInfo.bank_people=this.peopleName
      let num = await databaseZone.upsert(cardInfo);
      if (num&amp;gt;0) {
        showToast("Binding successful")
        router.back()
      }
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After successful binding, we close the current page and return to the withdrawal page for data query.&lt;/p&gt;

&lt;p&gt;@State bankList:BindBank[]=[]&lt;/p&gt;

&lt;p&gt;async onPageShow(): Promise {&lt;br&gt;
    const value = await StorageUtils.getAll('user');&lt;br&gt;
    if (value != "") {&lt;br&gt;
      this.user = JSON.parse(value)&lt;br&gt;
    }&lt;br&gt;
    let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
    let condition = new cloudDatabase.DatabaseQuery(bind_bank);&lt;br&gt;
    condition.equalTo("user_id", this.user?.user_id)&lt;br&gt;
    let listData = await databaseZone.query(condition);&lt;br&gt;
    let json = JSON.stringify(listData)&lt;br&gt;
    let data: BindBank[] = JSON.parse(json)&lt;br&gt;
    if (data.length&amp;gt;0) {&lt;br&gt;
      this.bankList=data&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
Here we have implemented the binding and echo of the bank card.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Set Safety Lock (51)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:40:58 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-set-safety-lock-51-138e</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-set-safety-lock-51-138e</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the withdrawal page and business logic for some components. For security reasons, we've added a security lock feature. When enabled, users must verify their locally stored password with the cloud before any withdrawal can proceed. This additional layer of security better protects user assets by ensuring that only authorized users can initiate withdrawals.&lt;/p&gt;

&lt;p&gt;Function Analysis&lt;br&gt;
To implement this feature:&lt;/p&gt;

&lt;p&gt;Add a security entry on the personal profile page.&lt;br&gt;
Create a security lock settings page with an enable/disable toggle.&lt;br&gt;
When enabling the lock for the first time, show a dialog prompting the user to set a pattern password.&lt;br&gt;
Save the encrypted password to the cloud database for future verification.&lt;br&gt;
When disabling the lock, delete the stored password from the cloud.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
Add Security Entry to Personal Profile Page&lt;/p&gt;

&lt;p&gt;new SectionLine("Security",&lt;br&gt;
  "Set Security Lock",&lt;br&gt;
  $r('app.media.anquan'),&lt;br&gt;
  false),&lt;/p&gt;

&lt;p&gt;Add Click Event Handler&lt;/p&gt;

&lt;p&gt;if (item.title === 'Security') {&lt;br&gt;
  if (this.user != null) {&lt;br&gt;
    router.pushUrl({ url: 'pages/view/LockPage' });&lt;br&gt;
  } else {&lt;br&gt;
    showToast("Please log in first");&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Create Security Lock Database Table&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "objectTypeName": "verify_info",&lt;br&gt;
  "fields": [&lt;br&gt;
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},&lt;br&gt;
    {"fieldName": "open_lock", "fieldType": "Boolean"},&lt;br&gt;
    {"fieldName": "lock_str", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "user_id", "fieldType": "Integer"}&lt;br&gt;
  ],&lt;br&gt;
  "indexes": [&lt;br&gt;
    {"indexName": "field1Index", "indexList": [{"fieldName": "id", "sortType": "ASC"}]}&lt;br&gt;
  ],&lt;br&gt;
  "permissions": [&lt;br&gt;
    {"role": "World", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Create Security Lock Page&lt;/p&gt;

&lt;p&gt;@State user: User | null = null;&lt;br&gt;
@State flag: boolean = false;&lt;br&gt;
@State lockInfo: VerifyInfo | null = null;&lt;br&gt;
@State lock_ui_visibility: boolean = false;&lt;/p&gt;

&lt;p&gt;Column({ space: 10 }) {&lt;br&gt;
  CommonTopBar({ title: "Security Lock", alpha: 0, titleAlignment: TextAlign.Center, backButton: true });&lt;br&gt;
  Row() {&lt;br&gt;
    Text("Security Lock")&lt;br&gt;
      .fontColor(Color.Black)&lt;br&gt;
      .fontSize(16);&lt;br&gt;
    Image(this.lock_ui_visibility ? $r('app.media.kai') : $r('app.media.guan'))&lt;br&gt;
      .width(60)&lt;br&gt;
      .height(30)&lt;br&gt;
      .onClick(() =&amp;gt; {&lt;br&gt;
        // Handle toggle logic&lt;br&gt;
      });&lt;br&gt;
  }&lt;br&gt;
  .width('100%')&lt;br&gt;
  .justifyContent(FlexAlign.SpaceBetween)&lt;br&gt;
  .padding({ left: 10, right: 10 });&lt;br&gt;
  Divider().width('100%').height(0.8)&lt;br&gt;
    .color("#e6e6e6")&lt;br&gt;
  .width('100%');&lt;br&gt;
}&lt;br&gt;
.width('100%').height('100%').backgroundColor(Color.White);&lt;/p&gt;

&lt;p&gt;Create Security Lock Dialog&lt;/p&gt;

&lt;p&gt;import { LengthUnit } from '&lt;a class="mentioned-user" href="https://dev.to/kit"&gt;@kit&lt;/a&gt;.ArkUI';&lt;/p&gt;

&lt;p&gt;@Preview&lt;br&gt;
@CustomDialog&lt;br&gt;
export struct LockDialog {&lt;br&gt;
  @State passwords: Number[] = [];&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; lock_ui_visibility: boolean;&lt;br&gt;
  @State message: string = 'Draw your password pattern!';&lt;br&gt;
  public callback: (passwords: string) =&amp;gt; void = (): void =&amp;gt; { };&lt;br&gt;
  private patternLockController: PatternLockController = new PatternLockController();&lt;br&gt;
  controller: CustomDialogController;&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column({ space: 20 }) {&lt;br&gt;
      Text(this.message).textAlign(TextAlign.Center).margin(20).fontSize(20)&lt;br&gt;
        .fontColor(Color.Black);&lt;br&gt;
      PatternLock(this.patternLockController)&lt;br&gt;
        .sideLength(300)&lt;br&gt;
        .circleRadius(9)&lt;br&gt;
        .pathStrokeWidth(5)&lt;br&gt;
        .activeColor('#707070')&lt;br&gt;
        .selectedColor('#707070')&lt;br&gt;
        .pathColor('#707070')&lt;br&gt;
        .backgroundColor('#F5F5F5')&lt;br&gt;
        .autoReset(true)&lt;br&gt;
        .activateCircleStyle({&lt;br&gt;
          color: '#707070',&lt;br&gt;
          radius: { value: 16, unit: LengthUnit.VP },&lt;br&gt;
          enableWaveEffect: true&lt;br&gt;
        })&lt;br&gt;
        .onDotConnect((index: number) =&amp;gt; {&lt;br&gt;
          console.log("onDotConnect index: " + index);&lt;br&gt;
        })&lt;br&gt;
        .onPatternComplete((input: Array) =&amp;gt; {&lt;br&gt;
          if (input.length &amp;lt; 5) {&lt;br&gt;
            this.message = 'Pattern must connect at least 5 dots';&lt;br&gt;
            return;&lt;br&gt;
          }&lt;br&gt;
          if (this.passwords.length &amp;gt; 0) {&lt;br&gt;
            if (this.passwords.toString() === input.toString()) {&lt;br&gt;
              this.passwords = input;&lt;br&gt;
              this.message = 'Pattern password set successfully';&lt;br&gt;
              this.patternLockController.setChallengeResult(PatternLockChallengeResult.CORRECT);&lt;br&gt;
              const str: string = JSON.stringify(this.passwords);&lt;br&gt;
              this.callback(str);&lt;br&gt;
              this.controller.close();&lt;br&gt;
            } else {&lt;br&gt;
              this.message = 'Pattern mismatch. Please try again.';&lt;br&gt;
              this.patternLockController.setChallengeResult(PatternLockChallengeResult.WRONG);&lt;br&gt;
            }&lt;br&gt;
          } else {&lt;br&gt;
            this.passwords = input;&lt;br&gt;
            this.message = "Please redraw the pattern to confirm.";&lt;br&gt;
          }&lt;br&gt;
        });&lt;br&gt;
    }&lt;br&gt;
    .borderRadius({ topLeft: 20, topRight: 20 })&lt;br&gt;
    .justifyContent(FlexAlign.Start)&lt;br&gt;
    .backgroundColor(Color.White)&lt;br&gt;
    .height(500)&lt;br&gt;
    .width('100%');&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Integrate Dialog into Page&lt;/p&gt;

&lt;p&gt;private dialogController: CustomDialogController = new CustomDialogController({&lt;br&gt;
  builder: LockDialog({&lt;br&gt;
    lock_ui_visibility: this.lock_ui_visibility,&lt;br&gt;
    callback: async (str: string) =&amp;gt; {&lt;br&gt;
      let info = new verify_info();&lt;br&gt;
      info.id = Math.floor(Math.random() * 1000000);&lt;br&gt;
      info.open_lock = true;&lt;br&gt;
      info.lock_str = str;&lt;br&gt;
      info.user_id = this.user!.user_id;&lt;br&gt;
      let num = await databaseZone.upsert(info);&lt;br&gt;
      if (num &amp;gt; 0) {&lt;br&gt;
        this.lock_ui_visibility = true;&lt;br&gt;
        this.initLockInfo();&lt;br&gt;
        showToast("Security lock enabled successfully");&lt;br&gt;
      }&lt;br&gt;
    }&lt;br&gt;
  }),&lt;br&gt;
  alignment: DialogAlignment.Bottom,&lt;br&gt;
  customStyle: false&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Load User Data and Security Lock Status&lt;/p&gt;

&lt;p&gt;async initLockInfo() {&lt;br&gt;
  const value = await StorageUtils.getAll('user');&lt;br&gt;
  if (value != "") {&lt;br&gt;
    this.user = JSON.parse(value);&lt;br&gt;
  }&lt;br&gt;
  let databaseZone = cloudDatabase.zone('default');&lt;br&gt;
  let condition = new cloudDatabase.DatabaseQuery(verify_info);&lt;br&gt;
  condition.equalTo("user_id", this.user?.user_id);&lt;br&gt;
  let listData = await databaseZone.query(condition);&lt;br&gt;
  let json = JSON.stringify(listData);&lt;br&gt;
  let data: VerifyInfo[] = JSON.parse(json);&lt;br&gt;
  if (data.length &amp;gt; 0) {&lt;br&gt;
    this.lock_ui_visibility = true;&lt;br&gt;
    this.lockInfo = data[0];&lt;br&gt;
  } else {&lt;br&gt;
    this.lock_ui_visibility = false;&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;async aboutToAppear(): Promise {&lt;br&gt;
  this.initLockInfo();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Implement Toggle Logic&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
  Column({ space: 10 }) {&lt;br&gt;
    CommonTopBar({ title: "Security Lock", alpha: 0, titleAlignment: TextAlign.Center, backButton: true });&lt;br&gt;
    Row() {&lt;br&gt;
      Text("Security Lock")&lt;br&gt;
        .fontColor(Color.Black)&lt;br&gt;
        .fontSize(16);&lt;br&gt;
      Image(this.lock_ui_visibility ? $r('app.media.kai') : $r('app.media.guan'))&lt;br&gt;
        .width(60)&lt;br&gt;
        .height(30)&lt;br&gt;
        .onClick(async () =&amp;gt; {&lt;br&gt;
          if (this.lock_ui_visibility) {&lt;br&gt;
            // Disable lock&lt;br&gt;
            if (this.lockInfo) {&lt;br&gt;
              let info = new verify_info();&lt;br&gt;
              info.id = this.lockInfo.id;&lt;br&gt;
              let num = await databaseZone.delete(info);&lt;br&gt;
              if (num &amp;gt; 0) {&lt;br&gt;
                this.lock_ui_visibility = false;&lt;br&gt;
                showToast("Security lock disabled");&lt;br&gt;
              }&lt;br&gt;
            }&lt;br&gt;
          } else {&lt;br&gt;
            // Enable lock&lt;br&gt;
            this.dialogController.open();&lt;br&gt;
          }&lt;br&gt;
        });&lt;br&gt;
    }&lt;br&gt;
    .width('100%')&lt;br&gt;
    .justifyContent(FlexAlign.SpaceBetween)&lt;br&gt;
    .padding({ left: 10, right: 10 });&lt;br&gt;
    Divider().width('100%').height(0.8)&lt;br&gt;
      .color("#e6e6e6")&lt;br&gt;
    .width('100%');&lt;br&gt;
  }&lt;br&gt;
  .width('100%').height('100%').backgroundColor(Color.White);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Execute the code to test the security lock functionality. Users can now enable/disable the security lock, set a pattern password, and the system will securely store and verify the password during withdrawals.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Imitation Box Horse - Recycling Gold Withdrawal Page (50)</title>
      <dc:creator>Lin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 16:36:32 +0000</pubDate>
      <link>https://dev.to/whl15290959515/imitation-box-horse-recycling-gold-withdrawal-page-50-6on</link>
      <guid>https://dev.to/whl15290959515/imitation-box-horse-recycling-gold-withdrawal-page-50-6on</guid>
      <description>&lt;p&gt;Technical Stack&lt;br&gt;
Appgallery connect&lt;/p&gt;

&lt;p&gt;Development Preparation&lt;br&gt;
In the previous section, we implemented the query for recycling fund income and expenditure records, and successfully created corresponding income and expenditure records after order completion. However, we currently only have income records and no expenditure records. In this section, we will implement the recycling fund withdrawal function for accounts to achieve the positive cycle of the app from a business perspective.&lt;/p&gt;

&lt;p&gt;Function Analysis&lt;br&gt;
To implement the withdrawal function, we first need corresponding bank card information binding, withdrawal amount, and the total recycling fund of the current account. From a business perspective, we should also limit the total amount of recycling funds that can be withdrawn within a day to avoid unnecessary losses in certain situations. First, we need to determine whether the current account has bound corresponding information, then use conditional judgments on input components to restrict incorrect user operations, and finally add confirmation withdrawal and withdrawal record buttons.&lt;/p&gt;

&lt;p&gt;Code Implementation&lt;br&gt;
First, create the corresponding binding information table:&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "objectTypeName": "bind_bank",&lt;br&gt;
  "fields": [&lt;br&gt;
    {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},&lt;br&gt;
    {"fieldName": "user_id", "fieldType": "Integer"},&lt;br&gt;
    {"fieldName": "bank_name", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "bank_card", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "bank_people", "fieldType": "String"},&lt;br&gt;
    {"fieldName": "is_verify", "fieldType": "Boolean"},&lt;br&gt;
    {"fieldName": "verify_id", "fieldType": "Integer"}&lt;br&gt;
  ],&lt;br&gt;
  "indexes": [&lt;br&gt;
    {"indexName": "field1Index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}&lt;br&gt;
  ],&lt;br&gt;
  "permissions": [&lt;br&gt;
    {"role": "World", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},&lt;br&gt;
    {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Implement the bank card binding module using component import, handling the display logic for bound and unbound states:&lt;/p&gt;

&lt;p&gt;import { BindBank } from "../../entity/BindBank"&lt;/p&gt;

&lt;p&gt;@Component&lt;br&gt;
export struct BindAlipay {&lt;br&gt;
  &lt;a class="mentioned-user" href="https://dev.to/link"&gt;@link&lt;/a&gt; bankList:BindBank[]&lt;br&gt;
  public callback:()=&amp;gt;void=():void=&amp;gt;{}&lt;br&gt;
  public postCallback:()=&amp;gt;void=():void=&amp;gt;{}&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt;&lt;br&gt;
  notAlipay(){&lt;br&gt;
    Row(){&lt;br&gt;
      Image($r('app.media.tv_card'))&lt;br&gt;
        .height(17)&lt;br&gt;
        .width(17)&lt;br&gt;
        .margin({left:14})&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Text("You haven't bound a bank card account yet, click to bind")
    .fontColor("#FF4242")
    .fontSize(16)
}
.backgroundColor(Color.White)
.padding(10)
.margin({bottom:50})
.onClick(e=&amp;gt;{
  this.callback()
})
.height(48)
.width('100%')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt; bindAlipay(){&lt;br&gt;
    Row(){&lt;br&gt;
      Column(){&lt;br&gt;
        Row(){&lt;br&gt;
          Image($r('app.media.tv_card'))&lt;br&gt;
            .height(17)&lt;br&gt;
            .width(17)&lt;br&gt;
            .margin({left:14})&lt;br&gt;
          Text("12212")&lt;br&gt;
            .fontColor("#333333")&lt;br&gt;
            .fontSize(16)&lt;br&gt;
        }&lt;br&gt;
        Text("Expected to arrive within 2 hours (subject to actual arrival time)")&lt;br&gt;
          .fontColor("#999999")&lt;br&gt;
          .fontSize(15)&lt;br&gt;
      }&lt;br&gt;
      Image($r('app.media.back_right_recycle'))&lt;br&gt;
        .height(30)&lt;br&gt;
        .width(30)&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
  build() {&lt;br&gt;
    Column() {&lt;br&gt;
      if (this.bankList.length&amp;gt;0){&lt;br&gt;
        this.bindAlipay()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  }else {
    this.notAlipay()
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Implement the withdrawal amount input module:&lt;/p&gt;

&lt;p&gt;@Component&lt;br&gt;
export struct InputItem {&lt;br&gt;
  @Consume&lt;br&gt;
  moneyNum:number&lt;br&gt;
  @State text: string = ''&lt;br&gt;
  controller: TextInputController = new TextInputController()&lt;br&gt;
  @Consume&lt;br&gt;
  isPost:boolean&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      Row() {&lt;br&gt;
        Text("Withdrawal Amount")&lt;br&gt;
          .fontSize(16)&lt;br&gt;
          .fontColor("#333333")&lt;br&gt;
        Text("Minimum withdrawal per transaction is 1 yuan")&lt;br&gt;
          .fontSize(14)&lt;br&gt;
          .fontColor("#FF4242")&lt;br&gt;
      }&lt;br&gt;
      .width('100%')&lt;br&gt;
      .justifyContent(FlexAlign.SpaceBetween)&lt;br&gt;
      Row() {&lt;br&gt;
        Text("¥")&lt;br&gt;
          .fontSize(28)&lt;br&gt;
          .fontColor("#333333")&lt;br&gt;
        TextInput({ text: this.text, placeholder: 'Enter withdrawal amount', controller: this.controller })&lt;br&gt;
          .placeholderColor("#999999")&lt;br&gt;
          .placeholderFont({ size: 28, weight: 400 })&lt;br&gt;
          .caretColor("#FCDB29")&lt;br&gt;
          .width(400)&lt;br&gt;
          .height(50)&lt;br&gt;
          .backgroundColor(null)&lt;br&gt;
          .type(InputType.Number)&lt;br&gt;
          .margin(20)&lt;br&gt;
          .fontSize(14)&lt;br&gt;
          .fontColor(Color.Black)&lt;br&gt;
          .onChange((value: string) =&amp;gt; {&lt;br&gt;
            this.moneyNum=Number(value)&lt;br&gt;
            this.text = value&lt;br&gt;
            if (this.moneyNum&amp;gt;0&amp;amp;&amp;amp;this.moneyNum&amp;lt;=300) {&lt;br&gt;
              this.isPost=true&lt;br&gt;
            }else {&lt;br&gt;
              this.isPost=false&lt;br&gt;
            }&lt;br&gt;
          })&lt;br&gt;
      }&lt;br&gt;
      Divider().width('100%').height(1)&lt;br&gt;
      Text("Withdrawable amount ¥1500.00 (Daily maximum withdrawal limit: 300)")&lt;br&gt;
        .fontSize(15)&lt;br&gt;
        .fontColor("#333333")&lt;br&gt;
    }&lt;br&gt;
    .padding(10)&lt;br&gt;
    .backgroundColor(Color.White)&lt;br&gt;
    .alignItems(HorizontalAlign.Start)&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Use @Provide and @Consume to facilitate cross-component value acquisition for better logical judgment:&lt;/p&gt;

&lt;p&gt;Column({space:15}){&lt;br&gt;
              Text("Confirm Withdrawal")&lt;br&gt;
                .width('100%')&lt;br&gt;
                .fontColor(Color.White)&lt;br&gt;
                .borderRadius(15)&lt;br&gt;
                .padding(10)&lt;br&gt;
                .textAlign(TextAlign.Center)&lt;br&gt;
                .fontColor(this.isPost?Color.Black:Color.White)&lt;br&gt;
                .backgroundColor(this.isPost?"#ffff6363":$r('app.color.color_999'))&lt;br&gt;
                .onClick(()=&amp;gt;{&lt;br&gt;
                  if (this.isPost) {&lt;br&gt;
                    // Launch pop-up window&lt;br&gt;
                  }else {&lt;br&gt;
                    if (this.moneyNum==0){&lt;br&gt;
                      showToast("Minimum withdrawal amount is 1 yuan per transaction")&lt;br&gt;
                    }&lt;br&gt;
                    if (this.moneyNum&amp;gt;300) {&lt;br&gt;
                      showToast('Daily limit is 300 yuan, please re-enter')&lt;br&gt;
                    }&lt;br&gt;
                  }&lt;br&gt;
                })&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          Text("View Withdrawal Records")
            .width('100%')
            .fontColor(Color.Black)
            .textAlign(TextAlign.Center)
            .backgroundColor("#ffffff")
            .padding(10)
            .borderRadius(15)
        }
        .margin({top:50})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Call the component on the main page:&lt;/p&gt;

&lt;p&gt;import { BindBank } from "../../entity/BindBank"&lt;br&gt;
import showToast from "../../utils/ToastUtils"&lt;br&gt;
import { CommonTopBar } from "../../widget/CommonTopBar"&lt;br&gt;
import { BindAlipay } from "./BindAlipay"&lt;br&gt;
import { InputItem } from "./InputItem"&lt;/p&gt;

&lt;p&gt;@Entry&lt;br&gt;
@Component&lt;br&gt;
export default struct WithdrawMoneyPage {&lt;br&gt;
  @State fontColor: string = '#182431'&lt;br&gt;
  @State selectedFontColor: string = '#007DFF'&lt;br&gt;
  @State currentIndex: number = 0&lt;br&gt;
  @State alipayAcc:string=''&lt;br&gt;
  @State bindAlipayName:string=''&lt;br&gt;
  @State phoneCode:string=''&lt;/p&gt;

&lt;p&gt;@Provide&lt;br&gt;
  isPost:boolean=false&lt;/p&gt;

&lt;p&gt;@Provide&lt;br&gt;
  moneyNum:number=0&lt;/p&gt;

&lt;p&gt;@State bankList:BindBank[]=[]&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/builder"&gt;@builder&lt;/a&gt; TabBuilder(index: number, name: string) {&lt;br&gt;
    Row() {&lt;br&gt;
      Image($r('app.media.tv_card'))&lt;br&gt;
        .height(17)&lt;br&gt;
        .width(17)&lt;br&gt;
        .margin({left:15})&lt;br&gt;
      Text(name)&lt;br&gt;
        .fontColor(this.currentIndex === index ? this.selectedFontColor : this.fontColor)&lt;br&gt;
        .fontSize(16)&lt;br&gt;
        .fontWeight(this.currentIndex === index ? 500 : 400)&lt;br&gt;
        .lineHeight(22)&lt;br&gt;
    }&lt;br&gt;
    .height(55)&lt;br&gt;
    .width('100%')&lt;br&gt;
    .alignItems(VerticalAlign.Center)&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;build() {&lt;br&gt;
    Column() {&lt;br&gt;
      CommonTopBar({ title: "Withdraw", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})&lt;br&gt;
          Column(){&lt;br&gt;
            BindAlipay({bankList:this.bankList,&lt;br&gt;
              callback:()=&amp;gt;{},&lt;br&gt;
              postCallback:()=&amp;gt;{}})&lt;br&gt;
            InputItem()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Column({space:15}){
          Text("Confirm Withdrawal")
            .width('100%')
            .fontColor(Color.White)
            .borderRadius(15)
            .padding(10)
            .textAlign(TextAlign.Center)
            .fontColor(this.isPost?Color.Black:Color.White)
            .backgroundColor(this.isPost?"#ffff6363":$r('app.color.color_999'))
            .onClick(()=&amp;gt;{
              if (this.isPost) {
                // Launch pop-up window
              }else {
                if (this.moneyNum==0){
                  showToast("Minimum withdrawal amount is 1 yuan per transaction")
                }
                if (this.moneyNum&amp;gt;300) {
                  showToast('Daily limit is 300 yuan, please re-enter')
                }
              }
            })

          Text("View Withdrawal Records")
            .width('100%')
            .fontColor(Color.Black)
            .textAlign(TextAlign.Center)
            .backgroundColor("#ffffff")
            .padding(10)
            .borderRadius(15)
        }
        .margin({top:50})
      }
      .backgroundColor('#F1F3F5')
      .height('100%')
      .justifyContent(FlexAlign.Start)
      .padding(10)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;After completing the implementation, execute the code to view the effect.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
