当前位置:   article > 正文

微信小程序实现和AI语音对话功能_微信小程序 ai自动化回复

微信小程序 ai自动化回复

1.效果

微信小程序与AI语音对话

2.效果主要实现技术
①AI语音合成(阿里云平台)
②微信小程序同声传译功能
③本功能是用原生微信小程序实现的(可自行转成uniapp代码)

3.同声传译
进入微信服务市场,搜索同声传译就能找到这个插件,然后添加到自己的微信小程序中。
可在微信公众平台,设置==》第三方设置==》插件管理中看到添加的插件
在这里插入图片描述
4.添加同声传译插件后可在自己项目中配置,打开app.json

{
 "plugins": {
    "WechatSI": {
      "version": "0.3.5",
      "provider": "wx069ba97219f66d99"
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5.代码
index.wxml

<view class="container">
<!-- <privacypopup></privacypopup> -->
  <view class="header">
    <view>
      <image class="tit jello-horizontal" src="../../../assets/image/1/4.png" mode="aspectFit"></image>
      <!-- 默认初始化 -->
      <image wx:if="{{msgText==1}}" class="textSty" src="../../../assets/image/5.png" mode="aspectFit"></image>
      <!-- 对话正在进行中 -->
      <image wx:elif="{{msgText==2}}" class="textSty" src="../../../assets/image/said.png" mode="aspectFit"></image>
      <!-- 3对话暂停 -->
      <!-- <image  wx:elif="{{msgText==3}}" class="textSty" src="../../../assets/image/pause.png" mode="aspectFit"></image> -->
      <!-- 4对话出现问题 -->
      <!-- <image  wx:elif="{{msgText==4}}" class="textSty" src="../../../assets/image/anew.png" mode="aspectFit"></image> -->
    </view>
  </view>
  <view bindtap="openAi" class="content">
    <view class="logos">
      <!-- <image class="tit1 pulsate-bck" src="../../../assets/image/cheng.png" mode="aspectFit"></image> -->
      <view class="logos_item roll-in-blurred-left">
        <image class="ce1 {{ annimationFlag? 'rotate-center' : '' }}" src="../../../assets/image/ce1.png" mode="aspectFit"></image>
        <image class="ce2 {{ annimationFlag? 'pulsate-bck' : '' }}" src="../../../assets/image/ce2.png" mode="aspectFit"></image>
      </view>
      <!-- 动画音律 -->
      <view class="dajianshiBox" wx:if="{{touchstart}}">
        <view class="dajianshi ">
          <span></span>
          <span></span>
          <span></span>
          <span></span>
          <span></span>
        </view>
      </view>
    </view>
    <view class="iconSty">
      <view class="iconSty_left">
        <image class="close1" bindtap="backIndex" src="../../../assets/image/close.png" mode="aspectFit"></image>
      </view>
      <view class="iconSty_center">
        <view data-flag='1' bindlongpress="touchStart" bindtouchend="touchEnd">
          <image class="{{touchstart == false?'microphone1':'microphone2'}}" src="../../../assets/image/{{touchstart == false?'microphone':'prohibit'}}.png" mode="aspectFit"></image>
          <!-- <image class="microphone2" src="../../../assets/image/prohibit.png" mode="aspectFit"></image> -->
        </view>
      </view>
      <view class="iconSty_right">
        <!-- <image bindtap="openContent" class="fish1" src="../../../assets/image/fish.png" mode="aspectFit"></image> -->
        <image bindtap="openContent" class="fish1" src="../../../assets/image/sa.png" mode="aspectFit"></image>
      </view>
    </view>
    <!-- <image class="tit2" src="../../../assets/image/1/3.png" mode="aspectFit"></image> -->
  </view>
  <view class="footer">
    <image class="end" src="../../../assets/image/end.png" mode="aspectFit"></image>
  </view>
  <!-- 弹窗 历史记录(不需要可删除)-->
  <view class="modal-mask" wx:if="{{showModal}}">
    <view class="modal-container">
      <image class="modal-bg" src="../../../assets/image/contentbg.png" mode="scaleToFill"></image>
      <!-- 这里放置需要滚动的内容 -->
      <view class="modal-content">
        <!-- 多文本展示区域 padding-bottom: 30rpx;-->
        <view class="text-content">
          <scroll-view id="scroll-view" scroll-into-view="{{toView}}" scroll-y="true" style="height: 655rpx;box-sizing: border-box;">
          <view style="box-sizing: border-box;">
            <view wx:for="{{msglist}}" wx:key="*this" id="item{{index}}">
              <!-- 右侧布局 wx:if="{{item.type === 'right'}}"-->
              <view class="right-layout" >
                <view class='right-msg' bindlongpress="copyText" data-key="{{item.question}}">{{item.question}}</view>
                <view class="right-arrow-layout">
                  <view class="right-arrow-img"></view>
                </view>
                <view class="right_item">
                  <image class="right-arrow-photo" src='../../../assets/image/missing-face.png' mode='aspectFill'></image>
                </view>
              </view>
              <!-- 左侧布局 wx:elif="{{item.type === 'left'}}"-->
              <view class="left-layout" >
                <view class="left_item">
                  <image class="left-arrow-photo" src='../../../assets/image/cheng.png' mode='aspectFill'></image>
                </view>
                <view class="left-arrow-layout">
                  <!-- 小尖角 -->
                  <view class="left-arrow-img"></view>
                </view>
                <!-- index.wxml -->
                <view class='left-msg' bindlongpress="copyText" data-key="{{item.answer}}">{{item.answer}}</view>
              </view>
            </view>
          </view>
          </scroll-view>
        </view>
      </view>
      <view class="modal-btns">
        <!-- <image bindtap="copyText" class="modal_img1" src="../../../assets/image/copyBtn.png" mode="scaleToFill"></image> -->
        <image class="" src="../../../assets/image/restart.png" mode="scaleToFill" bindtap="closeModal"></image>
      </view>
    </view>
  </view>
  <!-- 登录 -->
  <loginwin login_show="{{loginShow}}" bind:customEvent="onChildEvent">
  </loginwin>
</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

index.wxss

@charset "UTF-8";

.container {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* 之前的样式保持不变 */
  background-color: #000;
  min-height: 100vh;
  position: relative;
}

.container .header {
  padding: 20rpx;
  text-align: center;
}

.container .header {
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  /* 头部固定高度或其他样式 */
}

.container .header image {
  display: block;
}

.container .content {
  flex-grow: 1;
  overflow-y: auto;
  padding: 20rpx;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.container .footer {
  /* 底部固定高度或其他样式 */
  padding: 20rpx 0 40rpx 0;
  text-align: center;
}

.tit {
  width: 235rpx;
  height: 70rpx;
}

.textSty {
  width: 217rpx;
  height: 73rpx;
  box-sizing: border-box;
  margin-top: 35rpx;
}

.tit1 {
  width: 369rpx;
  height: 368rpx;
}

.ce1 {
  width: 368rpx;
  height: 368rpx;
}

.ce2 {
  width: 330rpx;
  height: 330rpx;
  position: absolute;
  left: 19.5rpx;
  top: 20.8rpx;
}

.iconSty {
  display: flex;
  justify-content: space-around;
  align-items: flex-end;
  height: 172rpx;
  padding-bottom: 48rpx;
  width: 79%;
  /* height: 327rpx; */
}

.logos {
  text-align: center;
  flex: 1;
  position: relative;
}

.logos_item {
  position: relative;
}

.iconSty_left .close1 {
  width: 65rpx;
  height: 65rpx;
}

.iconSty_center .microphone1 {
  width: 59rpx;
  height: 83rpx;
}

.microphone2 {
  width: 75rpx;
  height: 107rpx;
}

.iconSty_right .fish1 {
  width: 65rpx;
  height: 65rpx;
}

.tit2 {
  width: 190rpx;
  height: 22rpx;
  margin-top: 69rpx;
}

.end {
  width: 214rpx;
  height: 74rpx;
}

/* 弹窗 */
.modal-mask {
  touch-action: none; /* 禁止触摸滚动 */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999999999999999;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal-container {
  width: 603rpx;
  height: 878rpx;
  background-color: transparent;
  border-radius: 10rpx;
  /* overflow: hidden; */
  position: relative;
}

.modal-bg {
  width: 603rpx;
  height: 878rpx;
  position: absolute;
  top: 0;
  left: 0;
}

.modal-content {
  position: relative;
  box-sizing: border-box;
  padding: 90rpx 32rpx 20rpx 32rpx;
  color: #000;
  height: 88%;
  /* overflow: hidden; */
  /* 根据实际情况调整文本样式 */
}

.text-content {
  /* 适当调整多文本展示区域的样式 */
  width: 100%;

  height: 100%;
  /* overflow-y: auto; */
  /* border: 1px solid red; */
}

.modal-btns {
  display: flex;
  justify-content: center;
  padding: 47rpx 0rpx;
  position: absolute;
  bottom: 0;
  width: 100%;
}

.modal-btns image {
  width: 148rpx;
  height: 56rpx;
}

.modal_img1 {
  margin-right: 34rpx;
}

.btn {
  width: 48%;
  height: 80rpx;
  line-height: 80rpx;
  border-radius: 10rpx;
  text-align: center;
  color: #fff;
  background-color: #007aff;
}

/* 滚动条 */
.text-content::-webkit-scrollbar {
  /*滚动条整体样式*/
  /*高宽分别对应横竖滚动条的尺寸*/
  /* width: 3px;
  height: 1px; */
}

.text-content::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  /* border-radius: 10px;
  height: 10px;
  -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  background: #4D4D4D; */
}
.text-content::-webkit-scrollbar-track {
  /*滚动条里面轨道*/
  /* -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
  background: #ffffff; */
}
/* 聊天页面 */
/* 左侧布局 */
.left-layout {
  position: relative;
  display: flex;
  justify-content: flex-start;
  padding: 20rpx 60rpx 2vw 2vw;
}

.left-arrow-photo {
  width: 60rpx;
  height: 60rpx;
  min-width: 60rpx;
  min-height: 60rpx;
  border-radius: 50%;
  margin-top: 5rpx;
}

.left-msg {
  flex: 1;
  font-size: 25rpx;
  color: #444;
  line-height: 45rpx;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 10rpx;
  background-color: #ccc;
  margin-left: -12rpx;
  border-radius: 10rpx;
  z-index: 10;
}

.left-arrow-layout {
  position: relative;
  width: 35rpx;
  height: 65rpx;
  display: flex;
  align-items: center;
  z-index: 9;
}

.left-arrow-img {
  width: 0;
  height: 0;
  border-top: 9px solid transparent;
  border-right: 9px solid #ccc;
  border-bottom: 9px solid transparent;
  position: absolute;
  top: 5rpx;
  left: 5px;
}

/* 右侧布局 */
.right-layout {
  box-sizing: border-box;
  display: flex;
  justify-content: flex-end;
  padding: 20rpx 2vw 2vw 15vw;
  /* border: 1px solid green; */
}

.right-arrow-photo {
  width: 60rpx;
  height: 60rpx;
  min-width: 60rpx;
  min-height: 60rpx;
  border-radius: 50%;
  margin-top: 5rpx;
}

.right-msg {
  flex: 1;
  box-sizing: border-box;
  font-size: 25rpx;
  color: #444;
  line-height: 45rpx;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 10rpx;
  background-color: #96EB6A;
  margin-right: -1rpx;
  border-radius: 10rpx;
  z-index: 10;
}

.right-arrow-layout {
  position: relative;
  width: 35rpx;
  height: 65rpx;
  margin-right: 5rpx;
  display: flex;
  align-items: center;
  z-index: 9;
}

.right-arrow-img {
  width: 0;
  height: 0;
  border-top: 18rpx solid transparent;
  border-right: 18rpx solid transparent;
  border-left: 18rpx solid #96EB6A;
  border-bottom: 18rpx solid transparent;
  position: absolute;
  top: 13rpx;
  left: -2rpx;
}

.right_item {
  width: 70rpx;
  height: 70rpx;
  text-align: center;
}

.left_item {
  width: 70rpx;
  height: 70rpx;
  text-align: center;
}

/* 动画 */
.pulsate-bck {
  -webkit-animation: pulsate-bck 2s ease-in-out infinite both;
  animation: pulsate-bck 2s ease-in-out infinite both;
}

@-webkit-keyframes pulsate-bck {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  50% {
    -webkit-transform: scale(0.9);
    transform: scale(0.9);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

@keyframes pulsate-bck {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  50% {
    -webkit-transform: scale(0.9);
    transform: scale(0.9);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

/* 旋转 */
.rotate-center {
  -webkit-animation: rotate-center 1.9s linear infinite;
  animation: rotate-center 1.9s linear infinite;
}

@-webkit-keyframes rotate-center {
  0% {
    -webkit-transform: rotate(0);
    transform: rotate(0);
  }

  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

@keyframes rotate-center {
  0% {
    -webkit-transform: rotate(0);
    transform: rotate(0);
  }

  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}

/* 音律动画 */
.dajianshi {
  /* margin:100px auto 0; */
  width: 100rpx;
  height: 55rpx;
  display: flex;
  margin: 0 auto;
}

.dajianshi span {
  width: 12rpx;
  border-radius: 18px;
  margin-right: 9rpx;
}

.dajianshi span:nth-child(1) {
  animation: bar1 2s 0.2s infinite linear;
}

.dajianshi span:nth-child(2) {
  animation: bar2 2s 0.4s infinite linear;
}

.dajianshi span:nth-child(3) {
  animation: bar3 2s 0.6s infinite linear;
}

.dajianshi span:nth-child(4) {
  animation: bar4 2s 0.8s infinite linear;
}

.dajianshi span:nth-child(5) {
  animation: bar5 2s 1.0s infinite linear;
}

.dajianshi span:nth-child(6) {
  animation: bar6 2s 1.2s infinite linear;
}

.dajianshi span:nth-child(7) {
  animation: bar7 2s 1.4s infinite linear;
}

.dajianshi span:nth-child(8) {
  animation: bar8 2s 1.6s infinite linear;
}

.dajianshi span:nth-child(9) {
  animation: bar9 2s 1.8s infinite linear;
}

@keyframes bar1 {
  0% {
    background: #FF6600;
    margin-top: 20%;
    height: 10%;
  }

  50% {
    background: #FF6600;
    height: 100%;
    margin-top: 0%;
  }

  100% {
    background: #FF6600;
    height: 10%;
    margin-top: 20%;
  }
}

@keyframes bar2 {
  0% {
    background: #FF6600;
    margin-top: 20%;
    height: 10%;
  }

  50% {
    background: #FF6600;
    height: 100%;
    margin-top: 0%;
  }

  100% {
    background: #FF6600;
    height: 10%;
    margin-top: 20%;
  }
}

@keyframes bar3 {
  0% {
    background: #FF6600;
    margin-top: 20%;
    height: 10%;
  }

  50% {
    background: #FF6600;
    height: 100%;
    margin-top: 0%;
  }

  100% {
    background: #FF6600;
    height: 10%;
    margin-top: 20%;
  }
}

@keyframes bar4 {
  0% {
    background: #FF6600;
    margin-top: 20%;
    height: 10%;
  }

  50% {
    background: #FF6600;
    height: 100%;
    margin-top: 0%;
  }

  100% {
    background: #FF6600;
    height: 10%;
    margin-top: 20%;
  }
}

@keyframes bar5 {
  0% {
    background: #FF6600;
    margin-top: 20%;
    height: 10%;
  }

  50% {
    background: #FF6600;
    height: 100%;
    margin-top: 0%;
  }

  100% {
    background: #FF6600;
    height: 10%;
    margin-top: 20%;
  }
}

.dajianshiBox {
  width: 100%;
  position: absolute;
  bottom: 0;
}
/* 滚动条样式设置 */
/* 设置 scroll-view 的滚动条样式 */
.scroll-view::-webkit-scrollbar {
  width: 8px;  /* 滚动条宽度 */
  height: 8px; /* 滚动条高度,如果是横向滚动,这里设置高度 */
}

/* 滚动条轨道 */
.scroll-view::-webkit-scrollbar-track {
  background-color: #4D4D4D; /* 滚动条轨道背景色 */
}

/* 滚动条滑块 */
.scroll-view::-webkit-scrollbar-thumb {
  background-color: #999999; /* 滚动条滑块颜色 */
  border-radius: 10rpx; /* 滑块边框圆角 */
}

/* 滚动条滑块悬停状态 */
.scroll-view::-webkit-scrollbar-thumb:hover {
  background-color: #555; /* 滚动条滑块悬停时的颜色 */
}
/* 滑入式动画 */
.slide-in-elliptic-top-fwd {
  -webkit-animation: slide-in-elliptic-top-fwd 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s both;
  /* Standard animation property */
  animation: slide-in-elliptic-top-fwd 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) 1s both;
}
@-webkit-keyframes slide-in-elliptic-top-fwd {
  0% {
    -webkit-transform: translateY(-600px) rotateX(-30deg) scale(0);
            transform: translateY(-600px) rotateX(-30deg) scale(0);
    -webkit-transform-origin: 50% 100%;
            transform-origin: 50% 100%;
    opacity: 0;
  }
  100% {
    -webkit-transform: translateY(0) rotateX(0) scale(1);
            transform: translateY(0) rotateX(0) scale(1);
    -webkit-transform-origin: 50% 1400px;
            transform-origin: 50% 1400px;
    opacity: 1;
  }
}
@keyframes slide-in-elliptic-top-fwd {
  0% {
    -webkit-transform: translateY(-600px) rotateX(-30deg) scale(0);
            transform: translateY(-600px) rotateX(-30deg) scale(0);
    -webkit-transform-origin: 50% 100%;
            transform-origin: 50% 100%;
    opacity: 0;
  }
  100% {
    -webkit-transform: translateY(0) rotateX(0) scale(1);
            transform: translateY(0) rotateX(0) scale(1);
    -webkit-transform-origin: 50% 1400px;
            transform-origin: 50% 1400px;
    opacity: 1;
  }
}
/* 果冻 */
.jello-horizontal {
	-webkit-animation: jello-horizontal 0.9s 0.5s both;
	        animation: jello-horizontal 0.9s 0.5s both;
}
@-webkit-keyframes jello-horizontal {
  0% {
    -webkit-transform: scale3d(1, 1, 1);
            transform: scale3d(1, 1, 1);
  }
  30% {
    -webkit-transform: scale3d(1.25, 0.75, 1);
            transform: scale3d(1.25, 0.75, 1);
  }
  40% {
    -webkit-transform: scale3d(0.75, 1.25, 1);
            transform: scale3d(0.75, 1.25, 1);
  }
  50% {
    -webkit-transform: scale3d(1.15, 0.85, 1);
            transform: scale3d(1.15, 0.85, 1);
  }
  65% {
    -webkit-transform: scale3d(0.95, 1.05, 1);
            transform: scale3d(0.95, 1.05, 1);
  }
  75% {
    -webkit-transform: scale3d(1.05, 0.95, 1);
            transform: scale3d(1.05, 0.95, 1);
  }
  100% {
    -webkit-transform: scale3d(1, 1, 1);
            transform: scale3d(1, 1, 1);
  }
}
@keyframes jello-horizontal {
  0% {
    -webkit-transform: scale3d(1, 1, 1);
            transform: scale3d(1, 1, 1);
  }
  30% {
    -webkit-transform: scale3d(1.25, 0.75, 1);
            transform: scale3d(1.25, 0.75, 1);
  }
  40% {
    -webkit-transform: scale3d(0.75, 1.25, 1);
            transform: scale3d(0.75, 1.25, 1);
  }
  50% {
    -webkit-transform: scale3d(1.15, 0.85, 1);
            transform: scale3d(1.15, 0.85, 1);
  }
  65% {
    -webkit-transform: scale3d(0.95, 1.05, 1);
            transform: scale3d(0.95, 1.05, 1);
  }
  75% {
    -webkit-transform: scale3d(1.05, 0.95, 1);
            transform: scale3d(1.05, 0.95, 1);
  }
  100% {
    -webkit-transform: scale3d(1, 1, 1);
            transform: scale3d(1, 1, 1);
  }
}
/* 滚入 */
.roll-in-blurred-left {
	-webkit-animation: roll-in-blurred-left 0.65s cubic-bezier(0.230, 1.000, 0.320, 1.000) both;
	        animation: roll-in-blurred-left 0.65s cubic-bezier(0.230, 1.000, 0.320, 1.000) both;
}
 @-webkit-keyframes roll-in-blurred-left {
  0% {
    -webkit-transform: translateX(-1000px) rotate(-720deg);
            transform: translateX(-1000px) rotate(-720deg);
    -webkit-filter: blur(50px);
            filter: blur(50px);
    opacity: 0;
  }
  100% {
    -webkit-transform: translateX(0) rotate(0deg);
            transform: translateX(0) rotate(0deg);
    -webkit-filter: blur(0);
            filter: blur(0);
    opacity: 1;
  }
}
@keyframes roll-in-blurred-left {
  0% {
    -webkit-transform: translateX(-1000px) rotate(-720deg);
            transform: translateX(-1000px) rotate(-720deg);
    -webkit-filter: blur(50px);
            filter: blur(50px);
    opacity: 0;
  }
  100% {
    -webkit-transform: translateX(0) rotate(0deg);
            transform: translateX(0) rotate(0deg);
    -webkit-filter: blur(0);
            filter: blur(0);
    opacity: 1;
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736

index.js

// pages/ai/aiVoice/index.ts
//const { TextEncoder, TextDecoder } = require('../../../miniprogram_npm/text-encoding-shim/index.js')
//let Wxml2canvas  = require('wxml2canvas/index.js');
const app = getApp();
//引入插件:微信同声传译
const plugin = requirePlugin('WechatSI');
//获取全局唯一的语音识别管理器recordRecoManager
const manager = plugin.getRecordRecognitionManager();
Page({
  /**
   * 页面的初始数据
   */
  data: {
    isplay: true,
    onstops: true, //默认执行onStop
    isFlag: false, //是否点击录音到获取结果之间状态
    longPressTimer: null, // 用于存储长按定时器的变量
    touchStartTime: 0, //长按开始
    touchEndTime: 0, //松开结束 
    authsetting: false, //是否获取授权
    url: "地址",
    openid: null,
    islongPress: false, //是否长按
    ParentValue: 'Parent',
    loginShow: false, //登录弹窗默认关闭
    annimationFlag: false, //logo动画默认关闭
    touchstart: false, //默认没有按下
    toView: null,
    scrollTop: 0,
    src: '', //语音地址
    resultobj: {
      result: "",
      tempFilePath: ""
    },
    msgText: 1, //1默认初始化  2对话进行中   3结束对话  4对话出现问题
    flag: 1,
    haveflag: false, //防止重复点击
    recordState: false, //麦克风默认关闭状态
    msglist: [], //聊天记录
    showModal: false, //历时消息记录
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad() {
    const str = new TextDecoder('utf-8').decode(
          new Uint8Array("jsfjsdfslkdf看见撒巅峰时刻京东方·1")
      )
    console.log("str",str)
    // 关闭主页按钮
    wx.hideHomeButton();
    wx.setNavigationBarTitle({
      title: "AI对话"
    })
    //  判断用户是否登录
    this.isLogin();
    // 获取语音授权
    this.getSeeting(1);
    //识别语音
    this.initRecord();
    const authset = wx.getStorageSync('AUTHSETTING');
    if (!authset) { //没有获取录音权限
      // 重新获取录音权限
      this.getSeeting(1);
    }
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    //创建内部 audio 上下文 InnerAudioContext 对象。
    this.innerAudioContext = wx.createInnerAudioContext();
    this.innerAudioContext.src = '';
    // this.innerAudioContext.onError(function (res) {
    //   console.log(res);
    //   wx.showToast({
    //     title: '语音播放失败',
    //     icon: 'none',
    //   })
    // })
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {},
  // 获取聊天记录
  getChartQuery() {
    wx.showLoading({
      title: '读取中...',
      icon: 'none',
      mask: true
    })
    console.log('openid', wx.getStorageSync('OPENID'));
    let openId = wx.getStorageSync('OPENID');
    // 获取语音接口
    wx.request({
      url: this.data.url + '/cyjgVoice/record',
      method: 'POST',
      data: {
        openId: openId
      },
      success: res1 => {
        wx.hideLoading();
        this.setData({
          showModal: true
        });
        let data1 = res1.data.data;
        if (res1.data.code == 200) {
          //设置语音
          this.setData({
            msglist: data1
          })
          // 模拟异步数据加载
          setTimeout(() => {
            //  页面进入时滚动到底部,给在data中定义的变量赋值
            this.setData({
              toView: `item${this.data.msglist.length - 1}`,
            });
          }); // 假设数据加载需要一定时间,这里设置一个延时
        } else {
          wx.showToast({
            title: res1.data.msg,
            icon: 'none',
            duration: 2000
          })
        }
      }
    })
  },
  // 判断用户是否登录
  isLogin() {
    // 获取本地存储中的 OPENID
    const openid = wx.getStorageSync('OPENID');
    if (openid) {
      // 如果本地存储中存在 OPENID,则说明用户已经登录过,可以直接使用 OPENID 进行后续操作
      this.setData({
        loginShow: false
      })
      // 这里可以进行其他操作,比如直接跳转到主页面
    } else {
      // 如果本地存储中没有 OPENID,则需要调用登录接口获取 OPENID
      this.setData({
        loginShow: true,
        openid: openid
      })
    }
  },
  onChildEvent: function (event) {
    this.setData({
      loginShow: event.detail.login_show
    })
  },
  // 复制粘贴
  copyText(e) {
    let key = e.currentTarget.dataset.key;
    wx.setClipboardData({ //设置系统剪贴板的内容
      data: key,
      success(res) {
        wx.getClipboardData({ // 获取系统剪贴板的内容
          success(res) {
            wx.showToast({
              title: '复制成功',
              icon: "none"
            })
          }
        })
      }
    })
  },
  //暂停语音
  backIndex() {
    this.setData({
      msgText: 1, //初始化
      touchstart: false, //按钮恢复初始状态
      annimationFlag: false,
      haveflag: false,
      'resultobj.tempFilePath': "",
      isplay: false,
      resultText: "",
      src: ""
    })
    this.innerAudioContext.src = " "
    wx.stopBackgroundAudio();
    this.innerAudioContext.stop(); //暂停音频
    // 如何判断当前是语音录制识别状态
    if (this.data.isFlag) {
      this.setData({
        onstops: false, //是否执行onStop
      })
      wx.showLoading({
        title: '关闭中...',
        icon: 'none',
        // mask: true
      })
      // 停止识别
      manager.stop();
    }
  },
  // 播放语音
  yuyinPlay: function (e) {
    console.log("播放1", e);
    if (this.data.src == '' && this.data.isplay) {
      console.log("播放2",this.data.src,'222',this.data.isplay);
      return;
    }
    this.setData({
      msgText: 2, //正在对话
      annimationFlag: true,
      haveflag: true
    })
    this.innerAudioContext.src = this.data.src; // 设置音频地址
    this.innerAudioContext.onError(function (res) {
      this.setData({
        msgText: 1, //初始化
        annimationFlag: false,
        haveflag: false
      })
      wx.showToast({
        title: '语音播放失败',
        icon: 'none',
      })
    })
    this.innerAudioContext.onTimeUpdate(() => {
      // console.log('音频播放进度更新', this.data.src);
    });
    this.innerAudioContext.onEnded(() => { // 添加播放结束的回调
      this.setData({
        msgText: 1, //初始化
        annimationFlag: false,
        haveflag: false
      })
      // 在这里执行播放完毕后的操作,比如关闭语音
      this.innerAudioContext.stop(); // 使用 stop 方法停止音频并重置播放状态
    });
    this.innerAudioContext.play(); // 播放音频
  },
  // 结束语音
  end: function (e) {
    that.setData({
      msgText: 1, //初始化
      annimationFlag: false
    })
    this.innerAudioContext.stop(); //暂停音频
  },
  //识别语音 -- 初始化
  initRecord() {
    const that = this;
    // 有新的识别内容返回,则会调用此事件
    manager.onRecognize = function (res) {
      console.log("有新的识别内容返回,则会调用此事件")
    }
    // 正常开始录音识别时会调用此事件
    manager.onStart = function (res) {
      console.log("成功开始录音识别", res)
      that.setData({
        // annimationFlag:true
      })
    }
    //识别结束事件
    manager.onStop = function (res) {
      if (!that.data.isplay) {
        wx.showToast({
          title: "请说话",
          icon: 'success',
          image: '/assets/image/no_voice.png',
          duration: 1000,
          success: function (res) {
            this.setData({
              haveflag: false,
            })
          },
          fail: function (res) {
            console.log(res);
          }
        });
        return false
      }
      if (res.result == '') {
        wx.hideLoading();
        // wx.showToast({
        //   title: '听不清楚,请重新说一遍!',
        //   icon: 'none',
        //   duration: 2000
        // })
        // that.setData({
        //   msgText: 1, //初始化
        //   haveflag: false,
        //   isFlag: false,
        // })
        that.showRecordEmptyTip()
        return;
      } else {
        // wx.showLoading({
        //   title: '正在思考...',
        //   icon: 'none',
        // })
        that.setData({
          resultobj: {
            result: res.result,
            tempFilePath: res.tempFilePath,
            msgText: 2, //正在对话
            annimationFlag: true
          }
        })
        //  调用接口
        // that.resultAPi();
        that.resultTextApi();
        // that.resultAPi3();
      }
    }
    // 识别错误事件
    manager.onError = function (res) {
      console.log("error msg", res);
      wx.hideLoading();
      wx.showToast({
        icon: "none",
        title: '请重新开始~'
      })
      that.setData({
        haveflag: false,
        msgText: 1,
        annimationFlag: false,
        isFlag: false, //当前录制语音识别状态
      })
    }
  },
  // 根据wx.getSetting判断用户是否打开了录音权限,如果没有打开,则通过wx.authorize,向用户打开授权请求,如果用户拒绝了,就给用户打开授权设置页面。
  getSeeting(type) {
    // wx.showLoading({
    //   title: '获取录音权限',
    //   icon: 'none',
    //   mask: true
    // })
    const _this = this
    wx.getSetting({ //获取用户当前设置
      success: res => {
        // wx.hideLoading();
        // console.log('获取权限', res);

        if (res.authSetting['scope.record']) { //查看是否授权了录音设置
          // console.log('获取权限1111');
          const authset = wx.setStorageSync('AUTHSETTING', true);
          _this.setData({
            authsetting: true
          })
          if (type == 2) {
            wx.showToast({
              title: '获取录音权限成功,点击重新开始!',
              icon: 'none',
              duration: 2000
            })
          }
        } else {
          // 用户还没有授权,向 用户发起授权请求
          wx.authorize({ //提前向用户发起授权请求,调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口
            scope: 'scope.record',
            success() { //用户同意授权摄像头
              // console.log("同意授权");
              // wx.showToast({
              //   title: '获取录音权限成功',
              //   icon: 'none',
              //   duration: 2000
              // })

            },
            fail() { //用户不同意授权摄像头
              _this.openSetting()
            }
          })
        }
      },
      fail() {
        // console.log('获取用户授权信息失败');
        wx.showToast({
          title: '获取权限失败',
          icon: 'none',
          duration: 2000
        })
      }
    })
  },
  openSetting() {
    wx.openSetting({
      success(res) {
        console.log(res);
        if (res.authSetting['scope.record']) {
          console.log('用户已经同意录音权限');
          // 在这里可以再次执行录音操作或者其他逻辑
        } else {
          console.log('用户依然拒绝录音权限');
          // 可以提示用户继续操作的限制或者做其他处理
        }
      },
      fail() {
        console.log('打开设置页面失败');
      },
    });
  },
  //请求语音结果
  resultAPi() {
    //调用接口
    wx.request({
      url: this.data.url + '/cyjgVoice/question',
      method: 'POST',
      data: {
        question: this.data.resultobj.result,
        openId: wx.getStorageSync('OPENID')
      },
      success: res => {
        let data = res.data.data;
        if (res.data.code == 200 && this.data.isplay) {
          // 获取语音接口
          wx.request({
            url: this.data.url + '/cyjgVoice/voice',
            method: 'POST',
            data: {
              id: data.id,
              code: data.code,
              openId: data.openId
            },
            success: res1 => {
              wx.hideLoading();
              let data1 = res1.data.data;
              if (res1.data.code == 200 && this.data.isplay) {
                console.log("语音结果成功");
                // //设置语音
                this.setData({
                  src: data1.voiceUrl,
                  isFlag: false,
                  resultText: data1.answer
                })
                if (this.data.src) {
                  // 文字转语音
                  // this.wordYun();
                  this.yuyinPlay();
                } else {
                  console.log("没拿到");
                }
              } else if (res1.data.code != 200) {
                wx.showToast({
                  title: res1.data.msg,
                  icon: 'none',
                  duration: 2000
                })
              }
            }
          })
        } else if (res.data.code != 200) {
          wx.hideLoading();
          wx.showToast({
            title: res.data.msg,
            icon: 'none',
            duration: 2000
          })
          this.setData({
            msgText: 1
          })
        }
      }
    })
  },
  //获取文字接口
  resultTextApi() {
    //调用接口
    const formdata = {
      question: this.data.resultobj.result,
      openId: wx.getStorageSync('OPENID'),
    };
    const requestTask = wx.request({
      url: this.data.url + '/cyjgVoice/ans',
      method: 'POST',
      header: {
        'content-type': 'application/x-www-form-urlencoded' // 或者 'application/json' 如果你的后端能接受JSON格式
      },
      data: formdata, // 直接使用formdata对象
      success: res => {
        console.log("语音1111", res);
        wx.hideLoading();
        if (res.data.code == 200 && this.data.isplay) {
          let data = res.data.data;
          console.log("语音结果成功");
           //设置语音
          this.setData({
            isFlag: false,
            resultText:data.answer,
            src:data.voiceUrl
          })
          if (data.voiceUrl) {
            // 文字转语音
            this.yuyinPlay();
          } else {
            console.log("没拿到");
          }
        } else if (res.data.code != 200) {
          wx.hideLoading();
          wx.showToast({
            title: res.data.msg,
            icon: 'none',
            duration: 2000
          })
          this.setData({
            msgText: 1
          })
        }
      }
    })
    });
  },
  //语音  --按住说话
  touchStart(e) {
    // 判断是否获取录音权限
    if (this.data.haveflag) { //true 请先结束语音
      wx.showToast({
        title: '请先关闭语音!',
        icon: 'none',
        duration: 2000
      })
      return false
    }
    // 当前正在识别语音,还没结束上一次识别,请先关闭再进行录音
    if (this.data.isFlag) { //true 请先结束语音
      wx.showToast({
        title: '请先关闭语音!',
        icon: 'none',
        duration: 2000
      })
      return false
    }
    this.setData({
      islongPress: true,
      isplay: true
    })
    var flag = Number(e.currentTarget.dataset.flag)
    this.setData({
      recordState: true, //录音状态
      flag: flag,
      touchstart: true, //按下
      msgText: 2, //初始化状态
    })
    // 语音开始识别
    manager.start({
      lang: 'zh_CN', // 识别的语言
    })
  },
  // 
  resultAPi3() {
    //调用接口  获取后端请求返回的base64答案,前端转成文字,利用同声传译生成语音功能
    wx.request({
      url: this.data.url + '/cyjgVoice/question',
      method: 'POST',
      data: {
        question: this.data.resultobj.result,
        openId: wx.getStorageSync('OPENID')
      },
      success: res => {
        console.log("语音1111", res.data);
        let data = res.data.data;
        if (res.data.code == 200 && this.data.isplay) {
          // 获取语音接口
          wx.hideLoading();
          // //设置语音
          this.setData({
            // src: data.voiceUrl,
            isFlag: false,
            resultText: data.answer
          })
          this.base64ChangeVideo(data.voiceUrl);
        } else if (res.data.code != 200) {
          wx.hideLoading();
          wx.showToast({
            title: res.data.msg,
            icon: 'none',
            duration: 2000
          })
          this.setData({
            msgText: 1
          })
        }
      }
    })
  },
  // base64转mp3音频
  base64ChangeVideo(base64Data) {
    // const backgroundAudioManager = wx.getBackgroundAudioManager()
    const audioPath = wx.env.USER_DATA_PATH + '/ordernew.mp3'
    const fs = wx.getFileSystemManager();
    let that = this;
    fs.writeFile({
      filePath: audioPath,
      data: base64Data,
      encoding: 'base64',
      success(res) {
        that.setData({
          src: audioPath
        })
        that.yuyinPlay();
      },
    })
  },
  //语音  --松开结束
  touchEnd(e) {
    if (!(this.data.islongPress)) { //如果是长按执行下面内容
      return false
    }
    wx.showLoading({
      title: '正在思考...',
      icon: 'none',
    })
    if (this.data.haveflag) { //true 请先结束语音
      wx.hideLoading();
      // wx.showToast({
      //   title: '请先关闭语音111!',
      //   icon: 'none',
      //   duration: 2000
      // })
      return false
    }
    this.setData({
      touchstart: false,
      recordState: false,
      islongPress: false, //长按初始状态
      isFlag: true, //判断从松手到识别录音期间状态
      haveflag: true
    })
    // 语音结束识别
    manager.stop();
  },
  // 打开弹窗
  openContent() {
    if ((this.data.msgText == 1 && !(this.data.annimationFlag)) || (this.data.msgText == 2 && this.data.annimationFlag)) { //true 请先结束语音
      // wx.showToast({
      //   title: '请先关闭对话!',
      //   icon: 'none',
      //   duration: 2000
      // })
      this.getChartQuery();
    } else {
      return false
    }
  },
  // 关闭弹窗
  closeModal() {
    this.setData({
      showModal: false
    })
  },
  showRecordEmptyTip: function () {
    this.setData({
      msgText: 1, //初始化
      haveflag: false,
      isFlag: false,
    })
    wx.showToast({
      title: "请说话",
      icon: 'success',
      image: '/assets/image/no_voice.png',
      duration: 1000,
      success: function (res) {},
      fail: function (res) {
        console.log(res);
      }
    });
  },
  // 文字转语音
  wordYun: function (e) {
    var that = this;
    var content = this.data.resultText;
    plugin.textToSpeech({
      lang: "zh_CN",
      tts: true,
      content: content,
      success: function (res) {
        console.log("succ tts", res.filename);
        that.setData({
          src: res.filename
        })
        that.yuyinPlay();

      },
      fail: function (res) {
        console.log("fail tts", res)
      }
    })
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
    this.innerAudioContext.stop();
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    this.innerAudioContext.stop();
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {},
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {},
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {}
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709

index.json

{
  "usingComponents": {
    "loginwin": "../../../components/loginwin/index"
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5

6.注意:
2.微信同声传译点录音start后,不说话然后调用stop,需要10S以上才能返回结果,目前没有找到解决方案(有解决的小伙伴,给我说一下,谢谢~)
3.如果同声传译真机调试使用不了,报错“start:fail api scope is not declared in the privacy agreement”,需要去微信公众平台更新一下隐私协议,吧麦克风添加进去
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
7.微信登录组件
效果
在这里插入图片描述
7.1 创建loginwin组件
在这里插入图片描述
7.2 index.wxml代码

<view>
	<view  class="modal-mask1"  wx:if="{{login_show}}">
		<view class="modal-container1">
			<!-- 微信授权流程 -->
			<view class="popupBox1">
				<view class="ruleContent">
					<view class="loginIcon1">
						<image src="../../assets/image/weixin.png" class="wx-icon" mode="aspectFit"></image>
					</view>
					<view class="ruleTitle">微信授权登录</view>
				</view>
				<view class="popupClose">
					<image src="../../assets/image/loginBtn.png" class="login-btn" bindtap="login1" mode="widthFix"></image>
				</view>
				<view>
					<view class="flex_start flex_items endSty">
            <checkbox-group bindchange="checkboxChange" class="checkbox-group" style="transform: scale(0.8);">
	<checkbox value="all" checked="{{allchecked}}" color="#00C800" class="checkbox"></checkbox>
</checkbox-group>
						<view class="txt">
							阅读用户协议
							<text bindtap="read" class="policy-text">《用户协议及隐私政策》</text>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
	<!-- 获取微信头像部分 不需要可删除-->
<!-- 引入必要样式 -->
<view class="modal-mask" wx:if="{{getHeadShow}}" >
<view class="modal-container" wx:if="{{getHeadShow}}" style="padding:0;">
	<view class="popupBox">
		<view class="ruleContent">
			<view class="loginIcon">
				<button class="avatar-wrapper" open-type="chooseAvatar"  bindchooseavatar="onChooseAvatar">
					<image wx:if="userInfo.headImg" class="avatar" src="{{userInfo.headImg}}"></image>
					<image v-else class="avatar" src="../../assets/image/cheng.png"></image>
					<view class="up_img">上传头像</view>
				</button>
			</view>
			<view class="ruleTitle">
        <!-- <input type="text" class="weui-input" placeholder="请输入昵称" bindinput="getNickname" /> -->
        <input value="{{userInfo.nickName||''}}" bindchange="onInput" type="nickname" class="weui-input" placeholder="请输入昵称" />
			</view>
		</view>
		<view class="popupClose">
      <!-- <button class="avatar-wrapper1" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">
	<image src="../../static/loginBtn.png" mode="widthFix"></image>
</button> -->
<button >
保存
</button>
		</view>
	</view>
</view>
</view>
</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

7.3 index.js代码

// pages/ai/loginpage/index.ts
Component({
  // "component": true,
  properties: {
    login_show: {
      type: Boolean,
      value: false, // 设置默认值
      observer: function (oldVal, newVal) { //每次父组件向子组件传值的时候都会调用这个函数
        console.log("间停止", oldVal, newVal) // 旧数据和新数据
        // this.Fn()
      }
    },
  },
  /**
   * 页面的初始数据
   */
  data: {
    allchecked: false,//是否选中
    login_show: false,//默认不显示
    getHeadShow: false,//是否获取昵称及用户头像
    url: "地址",
    userInfo: {
      nickName: '',
      openId: '',
      headImg: '',
    }
  },
  onLoad() {
  },
  // 可以在这里监听属性变化
  observerLoginShow: function (newVal, oldVal) {
    console.log('监听', newVal);
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {},
  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {},
  methods: {
    //隐私协议
    read(){
      wx.navigateTo({
        url: '/pages/ai/userAgreement/index',
      })
    },
    // 登录
    login1() {
      if (!this.data.allchecked) {
        wx.showToast({
          title: '请阅读并勾选用户协议',
          icon: 'none'
        })
        return
      }
      this.getUserInfo();
    },
    //复选框
    checkboxChange(n) {
      console.log('复选框', n)
      if (n.detail.value[0]) {
        this.setData({
          allchecked: true
        })
      } else {
        this.setData({
          allchecked: false
        })
      }
    },
    getUserInfo() {
      var that = this;
      wx.showLoading({ // 展示加载框
        title: '加载中',
      });
      let code = '';
      wx.login({
        success: (loginRes) => {
          console.log("登录code",loginRes)
          code = loginRes.code;
        },
        fail: () => {
          wx.showToast({
            title: "微信登录授权失败",
            icon: "none"
          });
        }
      });
      wx.getUserProfile({
        desc: '登录',
        success: (info) => {
          console.log('登录的openid', info)
          let obj = {
            code: code,
            rawData: info.rawData,
            signature: info.signature,
            encryptedData: info.encryptedData,
            iv: info.iv
          };
          // 登录成功
          wx.showLoading({
            mask: true,
            title: '登录中...'
          });
          //  登录接口
          wx.request({
            url:this.data.url+'/cyjgVoice/login',
            method: 'POST',
            data:obj,
            success: res => {
              wx.hideLoading();
              console.log("登录",res.data);
              let info = res.data;
              if (info.code == 200) {
                wx.setStorageSync('OPENID', info.data.openId);
                wx.setStorageSync('TOKEN', info.data.token);
                // 给父组件传值  关闭组件
                that.triggerEvent('customEvent', {
                  login_show: false
                });
              } else {//登录出错
                wx.showToast({
                  title: res.data.msg,
                  icon: "none"
                });
              }
            }
          })
        },
        fail: (error) => {
          // 处理getUserProfile失败的情况
        }
      });
    },
    // 图片上传 
    onChooseAvatar: function (e) {
      console.log('图片', e)
      let that = this;
      // 获取七牛云token
      getQiniuyunToken().then(res => {
        if (res.code === 20000) {
          // 构建key值
          const imgurl = e.detail.avatarUrl.replace('http://tmp/', '');
          const key = 'ar/files/' + new Date().getTime() + '_' + imgurl;
          wx.showLoading({
            mask: true,
            title: '上传中...',
          });

          // 准备上传文件
          wx.uploadFile({
            url: 'https://upload-z2.qiniup.com', // 华东地区上传
            filePath: e.detail.avatarUrl,
            name: 'file',
            method: 'POST',
            formData: {
              key: key, // key值
              token: res.token, // 七牛云token值
            },
            success: (uploadFileRes) => {
              // 解析返回的JSON字符串
              const strToObj = JSON.parse(uploadFileRes.data);
              // 拼接域名和key值得到完整URL
              const backUrl = VUE_APP_IMG_URL + strToObj.key;
              // 更新用户信息的头像地址
              that.userInfo.headImg = backUrl;
              wx.hideLoading();
            },
            fail: (fail) => {
              wx.showToast({
                title: '网络错误',
                icon: 'none',
              });
              // 注意:原代码中的data.fail(fail)调用在小程序中可能无对应逻辑,需根据实际情况调整
              wx.hideLoading();
            },
            complete: () => {
              // 完成回调,可根据需要处理
            }
          });
        } else {
          // 如果获取token失败,根据业务需求处理
        }
      }).catch(error => {
        wx.showToast({
          title: error.message || '请求失败',
          icon: 'none',
        });
      });
    },
  },



  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231

7.4 index.wxss代码

/* 添加或调整样式以匹配原生小程序组件 */
.modal-mask1 {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgba(0, 0, 0, 0.5);
	display: flex;
	justify-content: center;
	align-items: center;
	z-index: 999;
}

.modal-container1 {
	width: 500rpx;
	border-radius: 8rpx;
	background-color: #fff;
	padding: 40rpx;
}

.wx-icon {
	width: 120rpx;
	height: 120rpx;
}

.login-btn {
	width: 260rpx;
	height: 58rpx;
}

/* 其他样式保持与uni-app中的样式一致,但需根据微信原生组件调整类名和属性 */
.flex_start {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.txt {
  color: #161828;
  font-size: 24rpx;
  margin-left: 7rpx;
}

.txt text {
  color: #000;
  font-weight: 600;
  text-decoration: underline;
}

.endSty {
  width: 100%;
  justify-content: center;
}

.avatar-wrapper {
  padding: 0;
  width: 180px !important;
  border-radius: 8px;
  margin: auto;
  /* margin-top: 40px; */
  margin-bottom: 50rpx;
  position: relative;
  padding-bottom: 20rpx;
  background-color: transparent;
  /* text-align: center; */

}
.avatar-wrapper1{
  padding: 0;
  width: 180px !important;
  border-radius: 8px;
  margin: auto;
  position: relative;
  padding-bottom: 20rpx;
  background-color: transparent;
}
.avatar-wrapper1::after {
  border: none;
}
.weui-input {
  font-size: 28rpx;
  border-bottom: 1px solid #000;
  width: 207rpx;
  margin: auto;
}

.up_img {
  width: 120rpx;
  height: 34rpx;
  color: #fff;
  background-color: #000;
  line-height: 34rpx;
  text-align: center;
  font-size: 22rpx;
  border-radius: 17rpx;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  z-index: 999;
  bottom: 0;
}

.avatar-wrapper::after {
  border: none;
}

.avatar {
  display: block;
  width: 150rpx;
  height: 150rpx;
  border-radius: 50%;
  margin: auto;
}
.popupBox1 {
  width: 100%;
  border-radius: 8rpx 8rpx;
}
.loginIcon1 {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 30rpx 0 30rpx 0;
}

.popupClose {
  box-sizing: border-box;
  padding: 70rpx 0 30rpx 0;
  text-align: center;
 
}
.popupClose image {
  /* width: 250rpx;
  height: 58rpx; */
  vertical-align: middle;
}
.btnSty{
width: 260rpx !important;
height: 58rpx;
}
.ruleTitle {
  text-align: center;
  font-weight: bold;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

7.5 index.json代码

{
  "usingComponents": {}
}```



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/904725
推荐阅读
相关标签
  

闽ICP备14008679号