黑马程序员鸿蒙HarmonyOS端云一体化开发【31-52】

遇到报错,网上基本差不到,自己看开发文档agc开发文档

云数据库

概念

在这里插入图片描述

不是关系型数据库,是基于对象模型的数据库

  • 对象类型:用来定义存储对象的集合,不同的对象类型对应不同的数据结构,类似关系型数据库中的表
  • 对象:基本操作单元,每一个对象是一条完整的数据记录
  • 存储区:类似于数据库,有多张表。多份存储区的意义在于隔离测试、正式数据

字段的数据类型:
两种字符串string,text,四种整数,两种浮点数,字节数组(存储二进制数据),整数自增类型(只有正整数)两种(并不是所有客户端语言都支持,ArkTS可以)

数据类型取值范围说明排序方式
String最大长度200如果字符串长度超过200,建议使用Text类型。采用 UTF-8 编码的字节顺序
Booleantrue/false-false < true
Byte ( − 2 7 ) ∼ ( 2 7 − 1 ) (-2^7)\sim(2^7-1) (27)(271)-数字顺序
Short ( − 2 15 ) ∼ ( 2 15 − 1 ) (-2^{15})\sim(2^{15}-1) (215)(2151)-
Integer ( − 2 31 ) ∼ ( 2 31 − 1 ) (-2^{31})\sim(2^{31}-1) (231)(2311)-
Long ( − 2 63 ) ∼ ( 2 63 − 1 ) (-2^{63})\sim(2^{63}-1) (263)(2631)由于JavaScript不支持数据类型“Long”,Web SDK通过引入第三方开源组件实现支持数据类型“Long”的能力。“Long”类型的使用方法请参考https://github.com/dcodeIO/long.js。
Float-3.40E+38 ~ +3.40E+38-
Double-1.79E+308 ~ +1.79E+308-
ByteArray-一般用于文件类型的数据存储,如图片、文档和视频等。在端侧时,使用Android开发应用时,以byte[]表示为字节数组。采用 UTF-8 编码的字节顺序
Text--
Date--时间顺序
IntAutoIncrement 1 ∼ ( 2 31 − 1 ) 1\sim(2^{31}-1) 1(2311)Android、HarmonyOS(Java)和iOS不支持此数据类型。数字顺序
LongAutoIncrement 1 ∼ ( 2 63 − 1 ) 1\sim(2^{63}-1) 1(2631)Android、HarmonyOS(Java)和iOS不支持此数据类型。数字顺序

假设有自增类型 id,执行 upsert (insert+update)

  • id 值在数据库有,更新 {id:1, name:‘李四’ , age:20}
  • id 值在数据库无,按自增添加 {id:5, name:‘王五’ , age:16} 不会按你给的id增加
  • id 值不给,也按自增添加 {name:‘赵六’ , age:16}
student 表
id     name   age
1    李四    20
2    王五    16
3     赵六    16

权限管理:
【角色】共有四种

  • World 所有人 app管理者,使用者(已登录、未登录)
  • Authenticated 已认证
  • Creator 创建者 (是这个用户创建的)
  • Administrator 管理员

【权限】共有三种:Read 查询、Upsert 新增和修改、Delete 删除
例如:
并没有字段去记录是哪个人创建的,这是隐式的

article 表
id    title                                  
                                            用户 111
1   探索自我成长的道路:我的心路历程
2   如何在忙碌的生活中保持身心健康
3   分享我的旅行经历:探索世界的美
                                            用户 222
4    金融投资的新趋势:数字货币的崛起
5   未来科技发展展望:人工智能对社会的影响

它的权限设置如下:

"permissions": [
  {
    "rights": ["Read"],
    "role": "World"
  },
  {
    "rights": ["Read","Upsert"],
    "role": "Authenticated"
  },
  {
    "rights": ["Read","Upsert","Delete"],
    "role": "Creator"
  },
  {
    "rights": ["Read","Upsert","Delete"],
    "role": "Administrator"
  }
]
  • 用户111 未登录,查询所有文章 1 2 3 4 5 属于world所有人 有查询功能
  • 用户333 未登录,查询所有文章 1 2 3 4 5
  • 用户111 未登录,添加新文章 失败 权限不足
  • 用户111 已登录,添加新文章 成功 已登录就可以upsert
  • 用户111 已登录,删除文章1 成功 是他创建的,可以删
  • 用户111 已登录,删除文章4 失败 不是他创建的,不能删
  • 用户111 已登录,修改文章4 成功 匹配authenticated,可以修改,这不对,得通过业务代码去处理

准备云数据库

开通->新增存储区(数据库)->新建对象类型(表) 直接在云端操作版:
在这里插入图片描述
在这里插入图片描述
在开发工具里操作版:
CloudProgram/clouddb/objectType(表)或dataentry(数据)
自带的两个json文件并没有什么用,可以删掉

  1. 新建表 json文件
    在这里插入图片描述
    在这里插入图片描述
    fields 定义表中的字段
    indexes 定义表中的索引
    objectTypeName
    permission表的权限
    这个json文件他自动生成了一堆东西,我们在上面改就行:
    在这里插入图片描述
    belongPrimaryKey如果为true就是主键
    filedName 字段名字
    filedType 是数据类型 可以提示出来类型
    isNeddEncrypt是否加密
    notNull 非空 如果true必须加default
    在这里插入图片描述
    indexName 索引名字 id_idx
    indexList:对应哪个字段、索引排序
    在这里插入图片描述
    permission就算这个粗糙的权限和角色
  2. 添加对象数据
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    cloudDBZoneName 存储区名字,要写好不然就会新创一个存储区
    objectTypeName:表名
    objects:数据(创建时间是毫秒值
  3. 部署到云端
    db-config.json 修改默认存储区
    点cloud右键有一个部署,提示部署成功
    在这里插入图片描述

调用云数据库

端侧调用

在arkts中进行增删改查

准备

添加依赖,entry/oh-package.json5加依赖,其中的long依赖就是对long类型的支持
在这里插入图片描述
开通新服务要重新下载agc配置文件
初始化agc连接器,自动生成,在entryability.ts的oncreate里
在这里插入图片描述

建立模型

操作数据库之前要建立一个模型类(实体类),用js建,不需要自己写,可以借助agc自动生成。
在这里插入图片描述
导出,选择js格式,js文件类型选js,云端的js选serverSDK,就会生成一个zip文件,下载到本地,解压,得到两个js文件(视频的例子是两个表)
在ets里建立一个文件夹model,放进去
在这里插入图片描述

导出schema

schema指云数据库中表的结构(字段、权限等
和导出模型文件类似,选择json文件,下载到本地,_数字是版本号
把这个json文件放到rawfile里
ctrl+alt+shift+L格式化(不是删掉那个格式化,是变得格式起来)
在这里插入图片描述schemaVersion 版本
permission权限
objectType 有表的结构(索引,表名,字段)
弹幕说,目录下自己就有这个json文件

初始化database

要用database对象去操作,先初始化一下
// @ts-ignore
import schema from ‘./com.example.myapplication_21_cn.json’

@Entry
@Component
struct XXX {
// …
private database: Database

async aboutToAppear() {
try {
// 根据 schema 和 zoneName 创建数据库对象
this.database = cloud.database({ objectTypeInfo: schema, zoneName: “shopping” })
} catch (e) {
hilog.error(0, ‘User Query’, ‘error:’ + JSON.stringify(e))
}
}
导包,新建一个Database的对象
在aboutToAppear里写,调用cloud.database()
内部需要dataconfig类型:表信息,存储区名字,可选的两项
在这里插入图片描述
在这里插入图片描述
忽略错误
在这里插入图片描述
database()只有一个collection方法,选择操作哪张表,把模型类作为参数
在这里插入图片描述

查询

.query()返回DatabaseZoneQuery对象,这里面的结构有一个get方法,返回Promise对象,其中是一个T数组(学生)
在这里插入图片描述
展示查询到的学生数据:
在这里插入图片描述
效果:
在这里插入图片描述

问题1:只展示了姓名
原因:Text组件不能直接写数字,需要先转化toString(),或者拼接方式变成字符串
问题2:顺序和数据库不一样
原因:query().orderByAsc(“字段名”).get()
修改后的效果:在这里插入图片描述
改进:
分页查询功能,上滑屏幕显示后续的记录
搜索(向下滑动屏幕会出现一个搜索框,模拟器没法输入汉字)
主界面里包括三个东西Row,List,Divider
效果:
在这里插入图片描述
整体代码:

import cloud, { Database } from '@hw-agconnect/cloud'

// @ts-ignore
import schema from '../../resources/rawfile/schema.json'
import { t_student } from '../model/t_student'
import hilog from '@ohos.hilog'

@Entry
@Component
struct StudentPage {
  @State studentList: t_student[] = []
  private database: Database = null
  private dataOffset: number = 0
  @State searchAge: string = ''
  @State showSearch: boolean = false
  private startY: number = 0
  private startIndex: number = 0

  aboutToAppear() {
    this.database = cloud.database({
      zoneName: 'test',
      objectTypeInfo: schema
    })
    this.search('', '', '', this.dataOffset) //查询全部
  }

//offset偏移量,limit每页多少条记录,给一个默认值
  async search(id: string, name: string, age: string, offset: number, limit: number = 10) {
    try {
      const query = this.database.collection(t_student).query() //拿到database对象,选择表,query查询
      if (id.length > 0) {
        // where id=?
        query.equalTo("id", Number(id))
      }
      if (name.length > 0) {
        // where name like ?
        query.contains("name", name)
      }
      if (age.length > 0) {
        // where age=?
        query.equalTo("age", Number(age))
      }
      query.limit(limit, offset) //参数是:一页几条,每页偏移位置
      query.orderByAsc("id") //id升序
      const list: t_student[] = await query.get() //真正到云数据库去查询
      this.studentList.push(...list)
      hilog.info(0, 'Query', `${list.map(s => s.id)}`)
    } catch (e) {
      hilog.error(0, 'Query', JSON.stringify(e))
    }
  }

  build() {
    Column({ space: 26 }) {
      Row() {
        Text(`编号`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('33%')
        Text(`姓名`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('34%')
        Text(`年龄`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('33%')
      }
      .width('100%')
      .height(36)
      .backgroundColor('black')

      if (this.showSearch) {
        Search()
          .searchButton('搜索')
          .onChange(value => {
            this.searchAge = value
          })
          .onSubmit(() => {
            this.studentList = []
            this.dataOffset = 0
            this.search('', '', this.searchAge, this.dataOffset)
            this.showSearch = false
          })
      }

      List({ space: 52 }) {
        ForEach(this.studentList, (stu: t_student) => {
          ListItem() {
            Row() {
              Text(`${stu.getId()}`)
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('33%')
              Text(stu.getName())
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('34%')
              Text(`${stu.getAge()}`)
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('33%')
            }
            .width('100%')
          }
        })
      }
      .width('100%')
      .height('82%')
      .onReachEnd(() => { //触底时,查询第二页记录,注意,记录一起的高度要比list高度高,否则无法触底
        this.dataOffset += 10
        this.search('', '', '', this.dataOffset)
      })
      .onScrollIndex((start, end) => { //list可视区的顶部索引值,底部索引值
        hilog.info(0, 'Scroll', `start: ${start} end:${end}`)
        this.startIndex = start
      })
      .onTouch(event => { //下滑显示搜索框
        switch (event.type) {
          case TouchType.Down: //按下屏幕 up是松开 event.touches触点,可以拿到坐标
            this.startY = event.touches[0].y //起始的y坐标需要记录,终止的不需要记录
            break;
          case TouchType.Move: //滑动
            const endY = event.touches[0].y
            if (endY - this.startY >= 35 && this.startIndex === 0) { //必须滑动到顶部才显示搜索框
              this.showSearch = true
            } else if (this.startY - endY >= 25) {
              this.showSearch = false
            }
            break;
        }
      })

      Divider()
    }
    .width('100%')
    .justifyContent(FlexAlign.Start)
  }
}
  • 搜索方法:传入的是string,真的去查再转成number
  • 有搜索组件Search,有方法.onSubmit()
  • onTouch触屏事件
新增

对话框效果:
在这里插入图片描述
需要加@CustomDialog 装饰器 @Preview可以配合预览器使用,export抛出,自定义对话框必须有controller,控制打开关闭。

@CustomDialog
export struct StudentInsertDialog {
  private name: string = ''
  private age: number = 18
  controller: CustomDialogController
  confirm: (name: string, age: number) => void //只声明,由将来对话框的使用者去定义
  private static range = (start, stop, step = 1) => Array.from({
    length: (stop - start - 1) / step + 1
  }, (_, i) => start + (i * step))
  static AgeRange: string[] = StudentInsertDialog.range(16, 60).map(i => String(i))

  build() {
    Column({ space: 15 }) {
      Row() {
        Text('姓名')
          .width('20%')
        TextInput({ text: this.name })
          .width('80%')
          .onChange(value => {
            this.name = value
          })
      }
      .width('80%')
      .justifyContent(FlexAlign.SpaceAround)

      Row() {
        Text('年龄')
          .width('20%')
//范围,选中的索引值
        TextPicker({ range: StudentInsertDialog.AgeRange, selected: 2 })
          .width('80%')
          .onChange(value => {
            this.age = Number(value)
          })
      }
      .width('80%')

      Row() {
        Button('取消')
          .onClick(() => {
            this.controller.close() //关闭对话框
          })
          .backgroundColor(0xcccccc)
        Button('确定')
          .onClick(() => {
//database.collection(t_student).upsert(学生对象),但这样写耦合程度太高,希望分离开
            this.confirm(this.name, this.age) //用回调函数实现
            this.controller.close()
          })
      }
      .width('80%')
      .justifyContent(FlexAlign.SpaceAround)
    }
    .justifyContent(FlexAlign.SpaceAround)
    .width('80%')
    .height('55%')
    .margin({ top: 15 })
  }
}
删除

左滑记录,点击可选修改和删除
@Builder和页面渲染相关

@Builder
  showOperation(stu: t_student) {
    Row({ space: 12 }) {
      Image($r("app.media.ic_public_edit_filled"))
        .width(20)
        .onClick(() => {
          this.openStudentUpdateDialog(stu)
        })
      Image($r("app.media.ic_public_delete_filled"))
        .width(21)
        .onClick(() => {
          this.openStudentDeleteDialog(stu)
        })
    }
    .width(80)
    .justifyContent(FlexAlign.Start)
  }

加到listitem里面

ListItem() {
  Row() {
    Text(`${stu.getId()}`)
      .fontSize(18)
      .textAlign(TextAlign.Center)
      .width('33%')
    Text(stu.getName())
      .fontSize(18)
      .textAlign(TextAlign.Center)
      .width('34%')
    Text(`${stu.getAge()}`)
      .fontSize(18)
      .textAlign(TextAlign.Center)
      .width('33%')
  }
  .width('100%')
}
.swipeAction({ end: this.showOperation.bind(this, stu) })
//函数作为参数传递时,会出现this丢失问题,必须调用bind方法
//有剩余参数问题,必须调用bind方法

this丢失现象说明:a和print的关系断了,bind就是用来绑定他们的
在这里插入图片描述
在这里插入图片描述
剩余参数问题说明:
在这里插入图片描述

openStudentDeleteDialog(stu: t_student) {
   AlertDialog.show({
     title: '请确认',
     message: '真的要删除该用户吗?',
     confirm: {
       value: '确定',
       action: async () => {
         try {
           await this.database.collection(t_student).delete(stu)
           AlertDialog.show({ message: '删除学生成功' })
           hilog.info(0, 'Student Delete', 'Success')
           //更新显示
           this.dataOffset = 0
           this.studentList = []
           this.search('', '', '', this.dataOffset)
         } catch (e) {
           hilog.error(0, 'Student Delete', JSON.stringify(e))
         }
       }
     }
   })
 }

效果:
在这里插入图片描述

修改
import { StudentInsertDialog } from './StudentInsertDialog'
@CustomDialog
export struct StudentUpdateDialog {
  private sid: number//不能叫id,因为自己有一个id会冲突
  private name: string
  private age: number
  controller: CustomDialogController
  confirm: (id: number, name: string, age: number) => void

  build() {
    Column({ space: 15 }) {
      Text(`${this.sid}`)

      Row() {
        Text('姓名')
          .width('20%')
        TextInput({ text: this.name })
          .width('80%')
          .onChange(value => {
            this.name = value
          })
      }
      .width('80%')
      .justifyContent(FlexAlign.SpaceAround)

      Row() {
        Text('年龄')
          .width('20%')
        TextPicker({ range: StudentInsertDialog.AgeRange, selected: 2 }) //value:`${this.age}`
          .width('80%')
          .onChange(value => {
            this.age = Number(value)
          })
      }
      .width('80%')

      Row() {
        Button('取消')
          .onClick(() => {
            this.controller.close()
          })
          .backgroundColor(0xcccccc)
        Button('确定')
          .onClick(() => {
            this.confirm(this.sid, this.name, this.age)
            this.controller.close()
          })
      }
      .width('80%')
      .justifyContent(FlexAlign.SpaceAround)
    }
    .justifyContent(FlexAlign.SpaceAround)
    .width('80%')
    .height('65%')
    .margin({ top: 15 })
  }
}
 openStudentUpdateDialog(stu: t_student) {
    this.studentUpdateDialogController = new CustomDialogController({
      builder: StudentUpdateDialog({
        sid: stu.id, name: stu.name, age: stu.age,
        confirm: async (id, name, age) => { //把初始值给到这三个属性
          try {
            const stu = new t_student()
            stu.setId(id)
            stu.setName(name)
            stu.setAge(age)
            await this.database.collection(t_student).upsert(stu)
            AlertDialog.show({ message: '修改学生成功' })
            hilog.info(0, 'Student Update', 'Success')
            this.dataOffset = 0
            this.studentList = []
            this.search('', '', '', this.dataOffset)
          } catch (e) {
            hilog.error(0, 'Student Update', JSON.stringify(e))
          }
        }
      })
    })
    this.studentUpdateDialogController.open()
  }

效果:
在这里插入图片描述

整体studentPage代码:

import cloud, { Database } from '@hw-agconnect/cloud'

// @ts-ignore
import schema from '../../resources/rawfile/schema.json'
import { t_student } from '../model/t_student'
import hilog from '@ohos.hilog'
import { StudentInsertDialog } from './StudentInsertDialog'
import router from '@ohos.router'
import { StudentUpdateDialog } from './StudentUpdateDialog'

@Entry
@Component
struct StudentPage {
  @State studentList: t_student[] = []
  private database: Database = null
  private dataOffset: number = 0
  @State searchAge: string = ''
  @State showSearch: boolean = false
  private startY: number = 0
  private startIndex: number = 0
//对话框的控制器
  private studentInsertDialogController: CustomDialogController = new CustomDialogController({
    builder: StudentInsertDialog({ //使用这个对话框,需要传入函数
      confirm: async (name, age) => {
        try {
          const stu = new t_student()
          stu.setName(name)
          stu.setAge(age)
          await this.database.collection(t_student).upsert(stu)
          AlertDialog.show({ message: '添加学生成功' }) //给用户一个提示
          hilog.info(0, 'Student Insert', 'Success')
          this.dataOffset = 0 //重新查询
          this.studentList = []
          this.search('', '', '', this.dataOffset)
        } catch (e) {
          hilog.error(0, 'Student Insert', JSON.stringify(e))
        }
      }
    })
  })
  private studentUpdateDialogController: CustomDialogController

  openStudentUpdateDialog(stu: t_student) {
    this.studentUpdateDialogController = new CustomDialogController({
      builder: StudentUpdateDialog({
        sid: stu.id, name: stu.name, age: stu.age,
        confirm: async (id, name, age) => {
          try {
            const stu = new t_student()
            stu.setId(id)
            stu.setName(name)
            stu.setAge(age)
            await this.database.collection(t_student).upsert(stu)
            AlertDialog.show({ message: '修改学生成功' })
            hilog.info(0, 'Student Update', 'Success')
            this.dataOffset = 0
            this.studentList = []
            this.search('', '', '', this.dataOffset)
          } catch (e) {
            hilog.error(0, 'Student Update', JSON.stringify(e))
          }
        }
      })
    })
    this.studentUpdateDialogController.open()
  }

  openStudentDeleteDialog(stu: t_student) {
    AlertDialog.show({
      title: '请确认',
      message: '真的要删除该用户吗?',
      confirm: {
        value: '确定',
        action: async () => {
          try {
            await this.database.collection(t_student).delete(stu)
            AlertDialog.show({ message: '删除学生成功' })
            hilog.info(0, 'Student Delete', 'Success')
            this.dataOffset = 0
            this.studentList = []
            this.search('', '', '', this.dataOffset)
          } catch (e) {
            hilog.error(0, 'Student Delete', JSON.stringify(e))
          }
        }
      }
    })
  }

  @Builder
  showOperation(stu: t_student) {
    Row({ space: 12 }) {
      Image($r("app.media.ic_public_edit_filled"))
        .width(20)
        .onClick(() => {
          this.openStudentUpdateDialog(stu)
        })
      Image($r("app.media.ic_public_delete_filled"))
        .width(21)
        .onClick(() => {
          this.openStudentDeleteDialog(stu)
        })
    }
    .width(80)
    .justifyContent(FlexAlign.Start)
  }

  aboutToAppear() {
    this.database = cloud.database({
      zoneName: 'test',
      objectTypeInfo: schema
    })
    this.search('', '', '', this.dataOffset)
  }

  async search(id: string, name: string, age: string, offset: number, limit: number = 10) {
    try {
      const query = this.database.collection(t_student).query()
      if (id.length > 0) {
        // where id=?
        query.equalTo("id", Number(id))
      }
      if (name.length > 0) {
        // where name like ?
        query.contains("name", name)
      }
      if (age.length > 0) {
        // where age=?
        query.equalTo("age", Number(age))
      }
      query.limit(limit, offset)
      query.orderByAsc("id")
      const list: t_student[] = await query.get()
      this.studentList.push(...list)
      hilog.info(0, 'Student Query', `${list.map(s => s.id)}`)
    } catch (e) {
      hilog.error(0, 'Student Query', JSON.stringify(e))
    }
  }

  build() {
    Column() {
      Row() {
        Text(`编号`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('33%')
        Text(`姓名`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('34%')
        Text(`年龄`)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .fontColor('white')
          .textAlign(TextAlign.Center)
          .width('33%')
      }
      .width('100%')
      .height(36)
      .backgroundColor('black')

      if (this.showSearch) {
        Search()
          .searchButton('搜索')
          .onChange(value => {
            this.searchAge = value
          })
          .onSubmit(() => {
            this.studentList = []
            this.dataOffset = 0
            this.search('', '', this.searchAge, this.dataOffset)
            this.showSearch = false
          })
      }

      List({ space: 48 }) {
        ForEach(this.studentList, (stu: t_student) => {
          ListItem() {
            Row() {
              Text(`${stu.getId()}`)
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('33%')
              Text(stu.getName())
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('34%')
              Text(`${stu.getAge()}`)
                .fontSize(18)
                .textAlign(TextAlign.Center)
                .width('33%')
            }
            .width('100%')
          }
          .swipeAction({ end: this.showOperation.bind(this, stu) })
        })
      }
      .width('100%')
      .height('78%')
      .margin({ top: 24, bottom: 24 })
      .onReachEnd(() => {
        this.dataOffset += 10
        this.search('', '', '', this.dataOffset)
      })
      .onScrollIndex((start, end) => {
        hilog.info(0, 'Scroll', `start: ${start} end:${end}`)
        this.startIndex = start
      })
      .onTouch(event => {
        switch (event.type) {
          case TouchType.Down:
            this.startY = event.touches[0].y
            break;
          case TouchType.Move:
            const endY = event.touches[0].y
            if (endY - this.startY >= 25 && this.startIndex === 0) {
              this.showSearch = true
            } else if (this.startY - endY >= 5 || this.startIndex === 0) {
              this.showSearch = false
            }
            break;
        }
      })

      Button('新增', { type: ButtonType.Normal })
        .width('100%')
        .margin({ bottom: 6 })
        .onClick(async () => {
          this.studentInsertDialogController.open()
        })

      Button('登出', { type: ButtonType.Normal })
        .width('100%')
        .backgroundColor(0xcccccc)
        .margin({ bottom: 6 })
        .onClick(async () => {
          try {
            await cloud.auth().signOut()
            hilog.info(0, 'SignOut', 'Success')
            router.replaceUrl({ url: 'pages/MyLoginCustom' })
          } catch (e) {
            hilog.error(0, 'SignOut', JSON.stringify(e))
          }
        })
      Divider()
    }
    .width('100%')
    .justifyContent(FlexAlign.Start)
  }
}

云侧调用

arkts先调云函数,云函数再调云数据库

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值