概述

上节讲解开发嘟宝,Android studio如何配置github copilot,使用ai agent开发。

目前为止,嘟宝完成的基本功能设计包括

  • MQTT 基础通信
  • 后台驻留
  • SQLite数据存储
  • 二维码显示身份识别码
  • 开启自启动前台服务
  • 任务栏消息发送与点击
  • 高德定位实时更新
  • webrtc点对点通信
  • mAgentWeb控件封装解决全屏与获取视频权限问题
    嘟妈采用vue3编写它的核心需求已完成包含以下部分:
  • 完成登录注册页面
  • 完成二维码扫描完成与嘟宝绑定
  • 与嘟妈建立音视频通信
  • 查看嘟宝桌面共享视频
    项目地址在github上。
    嘟宝地址
    嘟妈地址

绑定流程

  • 嘟妈通过相机扫描二维码,获取到嘟宝的uuid,
  • 检验uuid是否合法
  • 校验uuid是否已经绑定
  • 若合法未绑定,通过mqtt发送绑定信令
  • 嘟宝收到绑定信令,检测是否已经和嘟妈绑定,
  • 若已绑定过,通过mqtt发送已经绑定的信令
  • 若未绑定,弹出消息,引导用户确定绑定,建立绑定关系,发送信令给嘟宝
  • 嘟妈收到嘟宝的同意绑定信令,建立绑定关系

扫描二维码

二维码工具库qr-scanner,

<template>
  <div class="scanbox">
    <video
      ref="videoRef"
      class="scanner-video"
      muted
      playsinline
    ></video>
 <van-icon
      name="arrow-left"
      class="back-btn"
      size="24"
      @click="goBack"
    />
    <div class="result">
      {{ qrResult || '请将二维码放入镜头中' }}
    </div>

  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import QrScanner from 'qr-scanner'
import { validate as uuidValidate } from 'uuid'

// 定义 emits
const emit = defineEmits<{
  (e: 'scan-success', data: string): void
  (e: 'scan-error', error: string): void
  (e: 'close'): void
}>()

// 校验是否为有效的UUID
const isValidUUID = (str: string): boolean => {
  return uuidValidate(str)
}

const videoRef = ref(null)
const qrResult = ref('')
let scanner:any = null

const startScan = async () => {
  if (!scanner && videoRef.value) {
    scanner = new QrScanner(
      videoRef.value,
      result => {
        qrResult.value = result.data
        if (isValidUUID(result.data)) {
          emit('scan-success', result.data)
        }

      },
      {
        returnDetailedScanResult: true,
        highlightScanRegion: true,
        highlightCodeOutline: true,
      }
    )
  }

  await scanner?.start()
}

const stopScan = () => {
  scanner?.stop()
}

onMounted(() => {
  startScan()
})

onUnmounted(() => {
  scanner?.destroy()
})
const goBack = () => {
   stopScan()
  // 向父组件传递关闭事件
  emit('close')
}
</script>

解析uuid

校验uuid,用的是uuid库

import { validate as uuidValidate } from 'uuid'
 if (!uuidValidate(dubaoId.value)) {
    showToast('请扫描或者输入正确的嘟宝ID')
    return
  }

使用pinna存储uuid

import { defineStore } from 'pinia'
import {   reactive } from 'vue';
import { getdubaoID,setdubaoID } from '@/api/storge'
interface dubaointerface {
  dubaoId: string;
  dubaoName: string;
  cover: string;
}
export const useDubaoStore = defineStore('dubao', () => {

  let dubaoId: dubaointerface[] = reactive(JSON.parse(getdubaoID() as string)||[]);
  function add(d: dubaointerface) {
    for (let i = 0; i < dubaoId.length; i++) {
      if (dubaoId[i]?.dubaoId === d.dubaoId) {
        return false;
      }
    }
    dubaoId.push(d)
    console.log(d);
    setdubaoID(JSON.stringify(dubaoId));
    return true;
  }
  function getDuBao(id: string) {
    return dubaoId.find((item) => item.dubaoId === id);
  }
  function remove(id: string) {
    const index = dubaoId.findIndex((item) => item.dubaoId === id);
    if (index !== -1) {
      dubaoId.splice(index, 1);
      setdubaoID(JSON.stringify(dubaoId));
      return true;
    }
    return false;
  }
  function unbind(id: string) {
    return remove(id);
  }
  function checkaddrepeat(d: dubaointerface) {
    for (let i = 0; i < dubaoId.length; i++) {
      if (dubaoId[i]?.dubaoId === d.dubaoId) {
        return true;
      }
    }
    return false;
  }
  return { dubaoId,add,getDuBao,remove,unbind,checkaddrepeat };

})

绑定页面

<template>
  <div class="container">
    <!-- 扫一扫头部 - 调整布局使图标和标题水平对齐 -->
    <div class="scan-header">
      <div class="scan-icon-wrapper">
        <div @click="scan" class="icon-wrapper">
          <van-icon name="scan" size="80px" color="#fff" />
        </div>
      </div>
      <span class="scan-title">扫一扫</span>
    </div>
    <!-- 输入区域 - 完全按照图片设计 -->
    <div class="input-wrapper">
      <van-field v-model="dubaoId" placeholder="请输入或者点击上面按钮扫描" clearable class="input-field" />
      <br />
      <van-field v-model="dubaoName" placeholder="昵称" clearable class="input-field" />
      <van-button type="primary" size="large" class="add-btn" @click="handleAdd"> 添加 </van-button>
      <!-- 底部装饰 - 与图片风格保持一致 -->
      <div class="footer-decoration">
        <span class="footer-text">扫一扫,请输入嘟宝ID</span>
      </div>
    </div>
    <scanner @scan-success="handleScanSuccess" @close="showscanner = !showscanner" class="scanner" v-if="showscanner" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { showToast } from 'vant'
import Scanner from '@/components/scanner .vue'
import { validate as uuidValidate } from 'uuid'
import { useDubaoStore } from '@/store/dubao'
import { useMQTTStore } from '@/store/mqtt'
const mqtt = useMQTTStore()
mqtt.$subscribe(async (mutate: any, state) => {
  if (typeof mutate.events.newValue === 'boolean') {
    console.log('是布尔类型')
    return
  }
  let data = JSON.parse(state.datamsg)
  let msg = JSON.parse(data.msg)
  switch (msg.code) {
    case 'binded':
      showToast('已经绑定过了')
      let d = {
        dubaoId: dubaoId.value,
        dubaoName: dubaoName.value,
        cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
      }
      store.add(d)
      dubaoId.value = ''
      dubaoName.value = ''
      break
    case 'bindok':
      let d1 = {
        dubaoId: dubaoId.value,
        dubaoName: dubaoName.value,
        cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
      }
      store.add(d1)
      dubaoId.value = ''
      dubaoName.value = ''
      showToast('绑定成功')
      break
    default:
      break
  }
})
let store = useDubaoStore()

// 输入框绑定值
const dubaoName = ref('')
const dubaoId = ref('')
let showscanner = ref(false)

// 添加按钮点击处理
const handleAdd = () => {
  console.log(1212)
  if (!uuidValidate(dubaoId.value)) {
    showToast('请扫描或者输入正确的嘟宝ID')
    return
  }
  let d = {
    dubaoId: dubaoId.value,
    dubaoName: dubaoName.value,
    cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
  }
  if (!store.checkaddrepeat(d)) {
    showToast('该嘟宝ID已存在')
    return
  }
  mqtt.pushmsg(dubaoId.value, 'bind', '')
  // store.add(d)

  // showToast('添加完成')
}
function scan() {
  showscanner.value = true
}
function handleScanSuccess(uuid: string) {
  dubaoId.value = uuid
  showscanner.value = false
}
</script>

<style scoped>
.container {
  padding-top: 100px;
}

.scan-header {
  height: 30%;
  text-align: center;
}

.scan-title {
  font-size: 20px;
}

.input-wrapper {
  font-size: 15px;
  text-align: center;
  padding: 50px;
}

.input-field {
  border: 2px solid #1989fa;
  border-radius: 4px;
}

.add-btn {
  margin-top: 30px;
  width: 100%;
}

.footer-decoration {
  margin: 10px;
  font-size: 15x;
  text-align: right;
}

.icon-wrapper {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  background: #1989fa;
  border-radius: 50%;
  padding: 10px;
}

.scanner {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
}
</style>

演示实例
在这里插入图片描述
由于之前已经绑定过,提示设备已经绑定,删除还是完成。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐