微信小程序 讯飞录音 点击按钮录音内容转文字

news2024/12/28 18:20:11

<page-meta page-style="{{ showPolish ? 'overflow: hidden;' : '' }}" />
<view class="wrap">  
  <view class="header-tab" style="justify-content: {{typeList.length > 2 ? 'start' : 'center'}}">
    <view class="tab-list {{idx == item.id ? 'active' : ''}}" wx:for="{{typeList}}" wx:key="id" data-scene="{{item.scene}}" data-idx="{{item.id}}" data-ext="{{item.ext}}" bindtap="tabHandle">
      <image src="{{item.thumb}}" class="icon-daily" mode="aspectFill" />
      <view class="v1">{{item.name}}</view>
    </view>
    <!-- <view class="tab-list v2 {{idx == '2' ? 'active' : ''}}" data-idx="2" bindtap="tabHandle">
      <image src="/image/outdoors.png" class="icon-daily" mode="widthFix"/>
    </view>
    <view class="tab-list {{idx == '3' ? 'active' : ''}}" data-idx="3" bindtap="tabHandle">      
      <image src="/image/mixedcollar.png" class="icon-daily" mode="widthFix"/>
    </view> -->
  </view>

  <!--如果是管理员-->
  <block wx:if="{{isAdmin || isSeniorTeacher || isTeacherDirector}}">
    <scroll-view class="scroll-class-box" scroll-x="true">
      <view class="scroll-class-list {{classCheckedId == item.classId ? 'active': ''}}" wx:for="{{classData}}" wx:key="id" data-index="{{index}}" data-id="{{item.classId}}" bindtap="checkClassHandle">
        {{item.className}}
      </view>
    </scroll-view>
  </block>

  <!--指向主题活动-->
  <view class="white-box record-white-box" wx:if="{{themeExt}}">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">指向主题活动</view>
      </view>
      <view class="close-box" bindtap="openThemeHandle">
        <image src="{{openTheme ? '/image/icon_arrow_up2.png' : '/image/icon_arrow_down2.png'}}" data-idx="{{index}}" class="icon-close-black"></image>
      </view>
    </view>
    <block wx:if="{{openTheme}}">
      <view class="theme-item" wx:if="{{activityList.length > 0}}">
        <view class="theme-list" wx:for="{{activityList}}" wx:key="id" data-idx="{{index}}" bindtap="checkActivityHandle">
          <image src="{{item.checked?'/image/icon_checkbox_checked.png':'/image/icon_checkbox.png'}}" class="icon-checkbox"></image>
          <view class="v1">{{item.name}}</view>
          <view class="v2">{{item.status == '1' ? '整理' : '计划'}}{{item.monthWeek ? item.monthWeek : '-暂无'}}</view>
        </view>
        <view class="package-footer" bindtap="loadMoreActivity">{{moreTxt}}</view>
        <view class="up-box mt20" bindtap="openThemeHandle">
          <image src="/image/icon_arrow_up2.png" class="icon-close-black"></image>
        </view>
      </view>
      <block wx:else>
        <view class="close-box-str" bindtap="openThemeHandle">暂未安排活动 | 计划-无</view>
      </block>
    </block>
    <view class="close-box-str" wx:if="{{!openTheme}}" bindtap="openThemeHandle">{{themeStr ? themeStr : '未选择相关主题活动'}}</view>
  </view>

  <!--选择幼儿-->
  <view class="white-box record-white-box">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">
          选择幼儿
          <text class="t1">*</text>          
        </view>
        <view class="student-number">已选择{{checkedStudentsTreated.length}}个幼儿</view>
      </view>
      <view class="close-box" bindtap="openStudentHandle">
        <image src="{{openStudents ? '/image/icon_arrow_up2.png' : '/image/icon_arrow_down2.png'}}" data-idx="{{index}}" class="icon-close-black"></image>
      </view>
    </view>    
    <!--名字保留四个字-->
    <block wx:if="{{openStudents}}">      
      <view class="student-box" wx:if="{{students.length > 0}}">
        <view class="student-list" wx:for="{{students}}" wx:key="id" data-idx="{{index}}" bindtap="checkHandle">
          <image src="/image/icon_check.png" class="icon-check" wx:if="{{item.checked}}" />
          <image src="{{item.studentImage ? item.studentImage : '/image/default.png'}}" mode="aspectFill" class="student-photo" />
          <view class="v1">{{item.studentNumber}}号-{{item.studentName}}</view>
        </view>
      </view>
      <view class="up-box" bindtap="openStudentHandle" wx:if="{{students.length > 0}}">
        <image src="/image/icon_arrow_up2.png" class="icon-close-black"></image>
      </view>
      <block wx:if="{{students.length == 0}}">
        <view class="close-box-str">还未录入本班幼儿信息,请去后台录入</view>
      </block>
    </block>
    
    <view class="student-box" wx:if="{{!openStudents && checkedStudents.length > 0}}" bindtap="openStudentHandle">
      <view class="student-list2" wx:for="{{checkedStudentsTreated}}" wx:key="id">
        <image src="{{item.studentImage ? item.studentImage : '/image/default.png'}}" mode="aspectFill" class="student-photo2" />
        <view class="v1">{{item.studentNumber}}号-{{item.studentName}}</view>
      </view>
      <view class="student-list2" wx:if="{{checkedStudents.length > 10}}">
        <view class="more-box">...</view>
      </view>
    </view>       
    <view class="no-graphs" wx:if="{{!openStudents && students.length > 0 && checkedStudents.length == 0}}" bindtap="openStudentHandle">未选择幼儿</view>    
  </view>

  <!--记录日期-->
  <view class="white-box record-white-box only-box">

    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">记录日期<text class="t1">*</text></view>
      </view>      
    </view>

    <view class="check-list-rig">
      <picker mode="date" bindchange="bindDateChange" value="{{selectedDate}}">
        <view class="picker">
          {{selectedDate ? selectedDate : '日期未选'}}
        </view>
      </picker>
    </view>
  
  </view>

  <!--观察场景-->
  <view class="white-box record-white-box only-box">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">观察场景<text class="t1">*</text></view>
      </view>      
    </view>
    
    <view class="check-list-rig">
      <picker mode="selector" range="{{observeSceneList}}" bindchange="bindParentChange" value="{{observeParentIndex}}" range-key="expenseItem">
        <view class="picker">
          {{observeSceneList[observeParentIndex].expenseItem}}
        </view>
      </picker>
      <view class="ones-aline">-</view>
      <picker mode="selector" range="{{childArray}}" bindchange="bindChildChange" value="{{observeChildIndex}}" range-key="expenseItem">
        <view class="picker">
          {{childArray[observeChildIndex].expenseItem}}
        </view>
      </picker>
    </view>
         
  </view>

  <!--观察目的-->
  <view class="white-box record-white-box">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">观察目的</view>
      </view>
      <!-- <view class="close-box" bindtap="openObserveHandle">
        <image src="{{openObserve ? '/image/icon_arrow_up2.png' : '/image/icon_arrow_down2.png'}}" data-idx="{{index}}" class="icon-close-black"></image>
      </view> -->
    </view>
    <view class="observe-cont mt-20">
      <view class="textarea-wrap">
        <textarea class="textarea-box2" value="{{observe}}" placeholder="" maxlength="500" bindinput="monitorObserveInput" style="border-radius: 10rpx 10rpx 0 0;"></textarea>
        <!-- <view class="ai-wrap">
          <view class="v1" data-aistyle="1" bindtap="aimAiHandle">
            <image src="/image/ai.png" class="icon-ai" />
            <view class="v1">AI续写</view>
          </view>
        </view> -->
        <view class="textarea-foot">
          <view class="textarea-foot-lef">已输入{{observeNumber}}个字</view>
          <view class="textarea-foot-rig">{{observeNumber}}/500</view>
        </view>        
      </view>
    </view>
    <!--如果时间 主题 textarea都是空的 则显示 暂无观察情境-->
    <!-- <view class="close-box-str" wx:if="{{!openObserve}}" bindtap="openObserveHandle">{{observeStr ? observeStr : '未设相关信息'}}</view> -->
  </view>

  <!--观察记录-->
  <view class="white-box record-white-box" wx:for="{{activityMaterials}}" wx:key="index">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">观察记录<text class="t1">*</text></view>
      </view>
      <image src="/image/close.png" data-idx="{{index}}" class="icon-close-black2" bindtap="deleteHandle" style="margin-right:9rpx"></image>
    </view>

    <view class="textarea-box-wrap">

      <view class="voice-box" wx:if="{{item.recordArr.length > 0}}">

        <view class="record-item" wx:for="{{item.recordArr}}" wx:key="txt" wx:for-item="oItem" wx:for-index="oIndex">
          <!--down:-160rpx  up:90rpx-->
          <view class="pos-box" style="margin-top:{{oItem.directionUp?'-160':'90'}}rpx;" wx:if="{{oItem.showTip}}">
            <view class="pos-box-lef" data-pidx="{{index}}" data-idx="{{oIndex}}" bindtap="txtRecordHandle">
              <image src="/image/icon_txt.png" class="icon-txt" />
              <text class="t1">转文字</text>
            </view>
            <view class="pos-box-rig" data-pidx="{{index}}" data-idx="{{oIndex}}" bindtap="delRecordHandle">
              <image src="/image/icon_del.png" class="icon-del" />
              <text class="t1">删除</text>
            </view>
            <image src="/image/icon_arrow_down.png" wx:if="{{oItem.directionUp}}" class="icon-arrow-down" />
            <image src="/image/icon_arrow_up.png" wx:if="{{!oItem.directionUp}}" class="icon-arrow-up" />
          </view>
          <view class="record-list" data-pidx="{{index}}" data-idx="{{oIndex}}" bindtap="playHandle" bindlongpress="onLongPress">
            <image src="{{oItem.played == true ? '/image/icon_pause.png' : '/image/icon_video.png'}}" class="icon-video" />
            <text class="t1">语音</text>
            <text class="t2">00:{{oItem.time}}</text>
          </view>
          <view class="record-txt" wx:if="{{oItem.showTxt}}">{{oItem.txt}}</view>
        </view>

      </view>

      <textarea class="textarea-box" value="{{item.content}}" data-idx="{{index}}" bindinput="textareaBlurHandle" placeholder="请输入内容" maxlength="19999"></textarea>
      <view class="textarea-box-footer">
        <!-- <view class="ai-box" data-idx="{{index}}" data-aistyle="2" bindtap="recordAiHandle">
          <image src="/image/ai.png" class="icon-ai" />
          <view class="v1">AI续写</view>
        </view> -->
        <button class="record-btn" data-idx="{{index}}" bindtap="recordHandle">
          <image src="/image/icon_record_gray.png" wx:if="{{!item.recordState}}" class="icon-record" />
          <image src="/image/icon_record_red.png" wx:else="{{item.recordState}}" class="icon-record" />
        </button>
      </view>
    </view>

    <view class="material-box">      
      <block wx:for="{{activityMaterials[index].material}}" wx:for-item="mItem" wx:for-index="mIndex" wx:key="url">
        <view class="material-list" wx:if="{{mItem.type == 'img'}}">
          <image src="/image/icon_close.png" class="icon-close" data-pidx="{{index}}" data-idx="{{mIndex}}" bindtap="closeHadle" />
          <image src="{{mItem.url}}" data-src="{{mItem.url}}" data-pidx="{{index}}" data-idx="{{mIndex}}" bindtap="preview" class="material-list-m2" mode="aspectFill"></image>
        </view>
        <view class="material-list" wx:if="{{mItem.type == 'mp4'}}">
          <image src="/image/icon_close.png" class="icon-close" data-pidx="{{index}}" data-idx="{{mIndex}}" bindtap="closeHadle" />
          <video src="{{mItem.url}}" data-src="{{mItem.url}}" class="material-list-m2" mode="aspectFill"></video>
        </view>
      </block>
      <button class="upload-box" data-idx="{{index}}" bindtap="uploadFile">
        <image src="/image/icon_photo.png" class="icon-photo" />
        上传图片、视频
      </button>
    </view>

  </view>
  <view class="add-box" bindtap="addListHandle">
    <image src="/image/add.png" mode="widthFix" class="icon-add2" />添加新的图文描述
  </view>

  <!--幼儿发展水平评估-->
  <view class="white-box record-white-box">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">幼儿发展水平评估</view>
      </view>
      <view class="close-box" bindtap="openAreaHandle" wx:if="{{selectArea.length > 0}}">
        <image src="{{openArea ? '/image/icon_arrow_up2.png' : '/image/icon_arrow_down2.png'}}" data-idx="{{index}}" class="icon-close-black"></image>
      </view>
    </view>
    
    <block wx:if="{{openArea && selectArea.length > 0}}">
      <!--第一级-->
      <scroll-view class="scroll-box" scroll-x="true">
        <view class="domain-first {{areaFirstIndex == index ? 'active': ''}}" wx:for="{{selectArea}}" wx:key="id" data-index="{{index}}" data-id="{{item.id}}" bindtap="getSelectAreaId">
          {{item.name}}
          <block wx:if="{{item.checked}}">
            <image src="/image/corner_mark.png" class="corner-mark"></image>
          </block>
        </view>
      </scroll-view>      
      <!--有可能消失的第二级 如果第一级的id用于查询指标列表 指标列表type是3 则第二级显示 如果type是4则该第二级隐藏 ***如果没有children 直接使用选项卡*** 第二级是单选-->
      <view class="domain-second" wx:if="{{showAreaSecond}}">
        <view class="domain-second-list {{areaSecondIndex == index ? 'active': ''}}" wx:for="{{listSelect}}" wx:key="id" data-index="{{index}}" bindtap="getAreaSecondIndex">{{item.label}}</view>
      </view>
      <!--必然存在的第三级 第三级的组成是title + list 第三级是子级单选 理论上有多个数组 多个数组有对应的子级-->
      <view class="domain-three" wx:if="{{showAreaSecond}}">
        <view class="domain-three-item" wx:for="{{threeData.children}}" wx:key="id">
          <view class="domain-three-title">
            <view class="v1">{{item.label}}</view>
            <view class="v2">(请在下方选择一个水平)</view>
          </view>
          <view class="domain-three-list" wx:for="{{item.children}}" wx:for-item="mItem" wx:for-index="mIndex" wx:key="id" data-parentindex="{{index}}" data-childindex="{{mIndex}}" data-item="{{mItem}}" bindtap="checkedAreaHandle">
            <image src="{{mItem.checked ? '/image/icon_checkbox_checked.png' : '/image/icon_checkbox.png'}}" class="icon-checkbox"></image>
            <view class="v2 {{mItem.checked ? 'active' : ''}}">{{mItem.label}}</view>
          </view>
        </view>
      </view>
      <!--type为4的时候-->
      <view class="domain-three" wx:else>
        <view class="domain-three-item" wx:for="{{threeData}}" wx:key="id">
          <view class="domain-three-title">
            <view class="v1">{{item.label}}</view>
            <view class="v2">(请在下方选择一个水平)</view>
          </view>
          <view class="domain-three-list" wx:for="{{item.children}}" wx:for-item="mItem" wx:for-index="mIndex" wx:key="id" wx:for-item="mItem" wx:for-index="mIndex" wx:key="id" data-parentindex="{{index}}" data-childindex="{{mIndex}}" data-item="{{mItem}}" bindtap="checkedAreaHandle">
            <image src="{{mItem.checked ? '/image/icon_checkbox_checked.png' : '/image/icon_checkbox.png'}}" class="icon-checkbox"></image>
            <view class="v2 {{mItem.checked ? 'active' : ''}}">{{mItem.label}}</view>
          </view>
        </view>
      </view>
    </block>
    <view wx:if="{{selectArea.length == 0}}">
      <view class="no-graphs">未做幼儿发展水平评估</view> 
    </view>
    <view class="close-box-str" wx:if="{{!openArea && selectArea.length > 0}}" bindtap="openAreaHandle">{{areaStr ? areaStr : '暂无幼儿发展水平评估'}}</view>

  </view>

  <view class="white-box record-white-box">
    <view class="title-box">
      <view class="yellow-fence"></view>
      <view class="title-txt-part">
        <view class="v1">改进措施</view>
      </view>
      <!-- <view class="close-box">
        <image src="/image/icon_arrow_down2.png" data-idx="{{index}}" class="icon-close-black"></image>
      </view> -->
    </view>
    <view class="textarea-wrap" style="margin-top: 20rpx;">
      <textarea class="textarea-box2" value="{{measure}}" placeholder="" maxlength="500" bindinput="monitorMeasureInput"></textarea>
      <view class="textarea-foot">
        <view class="textarea-foot-lef">已输入{{measureNumber}}个字</view>
        <view class="textarea-foot-rig">{{measureNumber}}/500</view>
      </view>
    </view>
  </view>

  <!-- <view class="save-btn" bindtap="save">提交</view> -->
  <view class="white-box record-footer">
    <view class="footer">
      <view wx:if="{{!oid}}" class="v3" bindtap="cacelObserve">取消</view>
      <view wx:if="{{oid}}" class="v3" bindtap="deleteObserve">删除</view>
      <view class="v1" data-status="0" bindtap="save">暂存</view>
      <view class="v2" data-status="1" bindtap="save">提交</view>
    </view>
  </view>

  <view class="mask" wx:if="{{maskShow}}" bindtap="closeTipHandle"></view>

  <!--Ai弹窗-->
  <view class="ai-mask" wx:if="{{showPolish}}">
    <view class="ai-pop">
      <scroll-view class="ai-pop-cont" scroll-y="true">
        <textarea class="textarea-box2" value="{{aiPolish}}" placeholder="" maxlength="500" style="border-radius: 10rpx 10rpx 0 0;" bindinput="monitorPopInput"></textarea>
      </scroll-view>      
      <view class="ai-pop-footer">
        <view class="v1" bindtap="aiCancel">取消</view>
        <view class="v2" bindtap="aiAgain">重写</view>
        <view class="v3" bindtap="aiConfirm">确定</view>
      </view>
    </view>
  </view>
</view>
const app = getApp()
const util = require('../../utils/util.js');
const api = require('../../config/api.js');
const BASE_URL = app.globalData.BASE_URL
let lock = false

//获取当天的年月日用‘-’分隔
function getDayDate() {
  const currentDate = new Date();
  const year = currentDate.getFullYear();
  const month = String(currentDate.getMonth() + 1).padStart(2, '0');
  const day = String(currentDate.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

const innerAudioContext = wx.createInnerAudioContext({
  useWebAudioImplement: false // 是否使用 WebAudio 作为底层音频驱动,默认关闭。对于短音频、播放频繁的音频建议开启此选项,开启后将获得更优的性能表现。由于开启此选项后也会带来一定的内存增长,因此对于长音频建议关闭此选项
})

const recorderManager = wx.getRecorderManager();
var wxst; //语音websocket
var status = 0; // 音频的状态
var iatResult = [] // 识别结果
const searchoptions = {
  duration: 1000 * 60,
  sampleRate: 16000,
  numberOfChannels: 1,
  encodeBitRate: 48000,
  format: 'mp3',
  frameSize: 6
}

Page({
  data: {
    idx: '1',
    students: [],
    activityMaterials: [],
    userInfo: {},
    oid: null, //跳转过来编辑的id

    //recordArr: [], recordArr率属于activityMaterials的子集 //音频数组 包含三个字段 url->mp3格式文件 txt:MP3的文字版的文本 time: 录音的时间 played:是否正在播放     
    //录音部分-start
    parentIndex: null,
    maskShow: false, //透明的遮罩层
    srcMic: '',
    edit_text_max: 200,
    remain_length: 200,
    edit_text: "",
    is_focus: false,
    tips: "",
    index: -1,
    voicePath: "",
    //语音
    //recordState: false, //录音状态 该字段纳入作为activityMaterials的子级 由activityMaterials统一调配
    contentTxt: '', //内容
    firstSend: true,
    clientY: 0, //点击的地方到顶部的距离
    //录音部分-end

    activityId: null, //指向主题活动回显
    themeList: [], //指向主题活动
    themeChecked: {}, //主题选中
    themeStr: '', //指向主题活动关闭时候显示的文本
    openTheme: false, //指向主题活动开关
    checkedStudents: [], //选中的幼儿列表
    checkedStudentsTreated: [], //选中的幼儿处理过的列表 超过10个得截取成9个
    openStudents: false, //选择幼儿开关
    openObserve: false, //观察背景开关
    observeStr: '', //观察关闭时候显示的文本
    openArea: false, //幼儿发展水平评估开关
    areaStr: '', //幼儿发展水平评估关闭时候显示的文本
    observe: '', //观察目的
    observeNumber: 0,
    areaFirstIndex: 0, //一级选中的index 默认第一个选中
    areaSecondIndex: 0, //二级选中的index 默认第一个选中 如果type为3
    //selectArea: [], //评估对象列表    
    showAreaSecond: false, //是否展示二级
    observationViewId: '', //编辑观察记录的id
    listSelect: [], //指标列表
    threeData: [], //三级列表数据
    evaluationItems: [], //幼儿发展水平评估最终存储的数组 也就是选中的数组
    activityList: [], //指向主题活动列表
    pageNum: 1,
    pageSize: 6,
    moreTxt: '点击加载更多',
    flag: false,
    selectedDate: getDayDate(),

    /*观察场景-start*/
    observeSceneList: [],
    childArray: [], // 子集数组
    observeParentIndex: 0, // 当前选中的父级索引
    observeChildIndex: 0, // 当前选中的子集索引
    /*观察场景-end*/

    measure: '', //改进措施
    measureNumber: 0,
    isAdmin: false, //判断是不是管理员
    isSeniorTeacher: false,//判断是不是超级教师
    isTeacherDirector: false,//判断是不是混龄教师
    classData: [],
    classCheckedId: '', //选中的classId 如果是管理员的时候 默认选中第一个 非管理员不调用

    typeList: [], //观察记录顶部tab
    sceneChecked: '', //观察场景选中对象
    themeExt: false, //指向主题活动是否显示

    //观察目的Ai续写
    aiPolish: '', //Ai续写的内容
    showPolish: false, //Ai续写弹窗
    aistyle: null, //1是观察目的 2是观察记录
    aiParentIndex: null, //观察记录 第几个在Ai续写
    aimAiPolish: '', //观察目的Ai续写的内容
    aimAiKeyword: '', //关键词
  },

  onLoad() {},

  onShow: function () {
    wx.setStorageSync('activtyTab', {}); //重置备课助手tab的条件
    wx.setStorageSync('activityAdminTab', {}); //ly-add 2023-10-09 重置主题活动列表管理员状态下的班级选中状态
    if (app.globalData.isActivityMaterials) return
    app.globalData.isActivityMaterials = false //重置记观察记录的上传状态
    lock = false;
    const userInfo = wx.getStorageSync('userInfo');
    //判断roles是不是'sch'判断当前用户是不是'园长' 如果roles是senior_teacher那么该角色和园长拥有相同'观察评价'权限 统计里也要和园长一样 也就是'观察记录'、'观察统计'  混龄账号目前不可能是超级老师 2024-04-16
    let isAdmin = false
    let isSeniorTeacher = false
    let isTeacherDirector = false
    if(userInfo.roleKeysString){
      let oarr = userInfo.roleKeysString.split(',')
      isAdmin = util.arrayContainsSch(oarr)
      isSeniorTeacher = util.arrayContainsSeniorteacher(oarr)
      isTeacherDirector = util.arrayContainsTeacherdirector(oarr)
    }
    this.setData({
      userInfo,
      isAdmin: isAdmin,//判断是不是管理员
      isSeniorTeacher: isSeniorTeacher,//判断是不是 超级教师
      isTeacherDirector: isTeacherDirector,//判断是不是混龄教师
    })
    this.loadRecord();

    this.selectClass(); //加载的时候 幼儿发展水平评估 走的这个方法        

    //重置录音模块
    this.initRecord();
    this.resetObserve()
  },
    
  loadRecord() {
    var that = this;
    recorderManager.onStart(() => { //开始录音时触发
      status = 0;
      iatResult = []
      //console.log('recorder start');
      that.data.firstSend = false;
    });
    recorderManager.onError((res) => { //错误回调
      //console.log(res);
    });
    recorderManager.onStop((res) => { //结束录音时触发
      //console.log('recorder stop')
      //console.log(res)
      let otime = (res.duration / 1000).toFixed(0)
      status = 2;
      var sendsty = '{"data":{"status":2,"audio":"","format":"audio/L16;rate=8000","encoding":"raw"}}'
      wxst.send({
        data: sendsty
      })
      wx.uploadFile({
        // 模拟https
        url: BASE_URL + 'common/uploadMediaToTencent', //需要用HTTPS,同时在微信公众平台后台添加服务器地址
        filePath: res.tempFilePath, //上传的文件本地地址
        name: 'file',
        formData: {
          'userId': wx.getStorageSync('userInfo').userId,
          'scene': 'observation'
        },
        //附近数据,这里为路径
        success: function (result) {
          // console.log("--结束录音--")
          // console.log(that.data.contentTxt)
          // console.log(JSON.parse(result.data).url)
          // console.log(otime)
          if (that.data.contentTxt) {
            //recordArr: []//音频数组 包含三个字段 url->mp3格式文件 txt:MP3的文字版的文本 time: 录音的时间 played:是否正在播放
            let ourl = JSON.parse(result.data).url
            let pidx = that.data.parentIndex
            let params = {
              url: ourl,
              txt: that.data.contentTxt,
              time: that.timeHandle(otime), //这个时间是用来显示的
              played: false,
              showTxt: false, //语音的文字部分是否展示
              showTip: false, //Tooltip 文字提示是否展示
              directionUp: false, //Tooltip的方向是向上还是向下
            }
            let oarr = that.data.activityMaterials

            oarr.forEach((item) => {
              item.recordArr = item.recordArr && item.recordArr.length > 0 ? item.recordArr : []
            })

            oarr[pidx].recordArr.push(params)
            that.setData({
              activityMaterials: oarr
            })
            //console.log(that.data.activityMaterials)
          } else {
            //console.log("木有内容啊")
          }
        },
        fail: function (err) {
          //console.log(err)
        }
      })
    });
    recorderManager.onFrameRecorded((res) => { //每帧触发
      const that = this
      const {
        frameBuffer,
        isLastFrame
      } = res
      let params = {
        'common': {
          'app_id': '57198f05'
        },
        'business': {
          'language': 'zh_cn', //⼩语种可在控制台--语⾳听写(流式)--⽅⾔/语种处添加试⽤
          'domain': 'iat',
          'accent': 'mandarin', //中⽂⽅⾔可在控制台--语⾳听写(流式)--⽅⾔/语种处添加试⽤
          'vad_eos': 1000,
          'dwa': 'wpgs' //为使该功能⽣效,需到控制台开通动态修正功能(该功能免费)
        },
        'data': {
          'status': 0,
          'format': 'audio/L16;rate=16000',
          'encoding': 'lame',
          'audio': wx.arrayBufferToBase64(frameBuffer)
        }
      }
      // 拼接数据
      let status = 0
      if (this.data.firstSend) {
        this.data.firstSend = false
      } else {
        if (isLastFrame) {
          status = 2
        } else {
          status = 1
        }
      }
      params.data.status = status
      wx.sendSocketMessage({
        data: JSON.stringify(params),
        success: (data) => {
          //console.log('send success:' + JSON.stringify(data))
          //that.resetRecordState()
        },
        fail: (err) => {
          //console.log('send error:' + JSON.stringify(err))
          //中断录音的时候
          //that.resetRecordState()
        },
        completed: () => {
          if (isLastFrame) {
            // wx closeSocket
          }
        }
      })
    })
  },
  resetObserve() {
    //选择领域模块
    this.setData({
      areaFirstIndex: 0,
      selectArea: [], //评估对象列表 
      showAreaSecond: false, //是否展示二级
      observationViewId: '', //编辑观察记录的id
      listSelect: [], //指标列表      
      idx: '1',

      openTheme: false, //指向主题活动开关
      themeStr: '', //指向主题活动关闭时候显示的文本

      openStudents: false,
      openObserve: false,
      openArea: false,
      observeStr: '',
      areaStr: '',
      evaluationItems: [],

      measureNumber: 0,
      observeParentIndex: 0,
      oid: app.globalData.isRecordEdit ? app.globalData.recordId : '', //判断是不是从报告页面跳转过来 如果是则赋值id

      measure: '',

      classData: [],
      classCheckedId: '', //选中的classId 如果是管理员的时候 默认选中第一个 非管理员不调用

      activityId: null,
      //选择幼儿-start        
      checkedStudents: [],
      checkedStudentsTreated: [],
      students: [],
      studentArr: [],
      themeChecked: {},
      //选择幼儿-end

      //观察背景-start
      selectedDate: getDayDate(), //记录日期
      observeParentIndex: 0,
      observeChildIndex: 0,
      observe: '',
      observeNumber: 0,
      //观察背景-end              

      activityMaterials: [{
        content: '',
        material: []
      }],

      typeList: [], //观察记录顶部tab
      sceneChecked: '', //观察场景选中对象
      themeExt: false, //指向主题活动是否显示

      //观察目的Ai续写
      aiPolish: '', //Ai续写的内容
      showPolish: false, //Ai续写弹窗
      aistyle: null, //1是观察目的 2是观察记录
      aiParentIndex: null, //观察记录 第几个在Ai续写
      aimAiPolish: '', //观察目的Ai续写的内容
      aimAiKeyword: '', //关键词
    })

    if (this.data.oid) {
      this.loadData()
    }
  },

  //回显数据
  loadData() {
    const that = this;

    util.request(api.observeDetail + this.data.oid, '', 'get').then(res => {
      if (res.code == 200) {
        let odata = res.data

        //选择幼儿回显
        let studentArr = this.data.students
        let checkedStudents = []
        if (odata.participants.length > 0) {
          checkedStudents = odata.participants
          //判断两个数组是否有相同的id 如果有相同的id 给当前的student添加选中状态
          studentArr.forEach(item => {
            const isChecked = checkedStudents.some(citem => citem.studentId === item.studentId);
            item.checked = isChecked;
          });
        }
        let oarr2 = JSON.parse(JSON.stringify(checkedStudents))
        this.checkedStudentsHandle(oarr2)

        //观察背景回显
        let observeIndex = odata.scene.split(',')
        let observeSceneList = this.data.observeSceneList
        let observeParentIndex = 0
        let observeChildIndex = 0
        if (observeSceneList.length > 0) {
          for (let i in observeSceneList) {
            if (observeSceneList[i].expenseId == observeIndex[0]) {
              observeParentIndex = i
              break
            }
          }
          for (let i in observeSceneList[observeParentIndex].children) {
            if (observeSceneList[observeParentIndex].children[i].expenseId == observeIndex[1]) {
              observeChildIndex = i
              break
            }
          }
        }
        let scene = odata.recordDate + ',' + observeSceneList[observeParentIndex].expenseItem + observeSceneList[observeParentIndex].children[observeChildIndex].expenseItem + ',' + (odata.purpose ? odata.purpose : '')
        //观察背景回显-end
        //重组数据
        //type 1图片 3视频 
        let oarr = odata.observationRecords.map(function (item) {
          //console.log(item)
          //由于后端返回的数据原因 导致得先把返回的数据剥离成两个数组 一个是语音部分的数组 一个是图片、视频的数组
          let paragraphsRecord = [] //存储语音
          let paragraphsIV = [] //存储图片视频   
          let paragraphsIVLastArr = [] //存储图片视频过滤后的最终形态          
          if (item.paragraphs && item.paragraphs.length > 0) {
            for (let i in item.paragraphs) {
              if (item.paragraphs[i].type == '2') {
                paragraphsRecord.push(item.paragraphs[i])
                paragraphsRecord.push(item.paragraphs[(i - 0) + 1])
              }
            }
            paragraphsIV = item.paragraphs.slice(paragraphsRecord.length) //通过语音部分数组的长度切割数组 后面的数组就都是图片或者视频的数组了
            for (let i in paragraphsIV) {
              paragraphsIVLastArr.push({
                url: paragraphsIV[i].content,
                type: paragraphsIV[i].type == '3' ? 'mp4' : paragraphsIV[i].type == '1' ? 'img' : '', //3是视频、1是图片
              })
            }
          }
          let oparagraphsRecord = []
          for (let i in paragraphsRecord) {
            if (paragraphsRecord[i].type == '2') {
              oparagraphsRecord.push({
                url: paragraphsRecord[i].content,
                txt: paragraphsRecord[(i - 0) + 1].content,
                time: that.timeHandle(paragraphsRecord[i].fileSize - 0),
                played: false,
                showTxt: false, //语音的文字部分是否展示
                showTip: false, //Tooltip 文字提示是否展示
                directionUp: false, //Tooltip的方向是向上还是向下
              })
            }
          }
          return {
            content: item.content,
            recordArr: oparagraphsRecord, //语音部分
            material: paragraphsIVLastArr, //图片、视频部分            
          }
        })

        let str = ''
        let evaluationItems = odata.evaluationItems
        for (let i in evaluationItems) {
          str += (evaluationItems[i].sort + ':' + evaluationItems[i].syndrome)
        }
        str = str.substring(0, str.length - 1)

        this.setData({
          idx: odata.type,
          activityId: odata.activityId,
          activityMaterials: oarr,
          students: studentArr, //处理过的学生列表
          checkedStudents: checkedStudents, //选中的学生
          checkedStudentsTreated: checkedStudents, //选中的学生
          selectedDate: odata.recordDate, //记录日期
          observeParentIndex: observeParentIndex,
          childArray: this.data.observeSceneList[observeParentIndex].children, //ly-add 2023-09-15观察场景回显的问题
          observeChildIndex: observeChildIndex,
          observe: odata.purpose,
          observeStr: scene,
          observeNumber: odata.purpose ? odata.purpose.length : 0,
          areaStr: str,
          evaluationItems: odata.evaluationItems,
          measure: odata.measure,
          measureNumber: odata.measure ? odata.measure.length : 0,
          classCheckedId: odata.classId,
          pageNum: 1,
          activityList: [], //指向主题活动列表                
        })
        if (odata.type == '2') {
          this.data.themeChecked.id = odata.activityId
        } else {
          this.data.themeChecked.id = ''
          this.setData({
            activityId: null
          })
        }
        //选择幼儿列表
        this.getStudent()
        this.getListSelectArea();
        this.getListSelectActivity();
      } else {
        wx.showToast({
          title: res.msg,
          icon: 'error',
          duration: 2000
        })
      }
    });
  },

  getObservationTypeListFun() {
    util.request(api.getObservationTypeList + this.data.userInfo.schoolId, '', 'get').then(res => {
      if (res.code == 200) {
        //获得列表数据 获取第一个idx的值
        this.setData({
          typeList: res.rows,
          idx: res.rows[0].id,
          sceneChecked: res.rows[0].scene
        })
        //观察场景请求数据
        this.getObserveScene();
        //选择幼儿列表
        this.getStudent()
        this.getListSelectArea();
        //指向主题活动
        this.setData({
          pageNum: 1,
          activityList: [], //指向主题活动列表 
          flag: false,
        })
        this.getListSelectActivity(); //指向主题活动   
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  selectClass() {
    util.request(api.selectClass + '?userId=' + this.data.userInfo.userId, '', 'get').then(res => {
      if (res.code == 200) {
        this.setData({
          classData: res.data,
          classCheckedId: res.data[0].classId
        })
        var oid = app.globalData.isRecordEdit ? app.globalData.recordId : '';
        if (!oid) {
          this.getObservationTypeListFun()
        }
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  openThemeHandle() {
    this.setData({
      openTheme: this.data.openTheme ? false : true
    })
  },

  cacelObserve() {
    const that = this
    wx.showModal({
      title: '',
      content: '是否清空当前页面数据',
      success(res) {
        if (res.confirm) {
          that.resetObserve()
        } else if (res.cancel) {
          //console.log('用户点击取消')
        }
      }
    })
  },

  //删除观察
  deleteObserve() {
    const that = this
    wx.showModal({
      title: '',
      content: '是否删除该观察记录',
      success(res) {
        if (res.confirm) {
          util.request(api.deleteObservation + that.data.oid, '', 'delete').then(res => {
            if (res.code == 200) {
              wx.showToast({
                title: '删除成功!',
                icon: 'success',
                duration: 2000
              })
              wx.switchTab({
                url: '/pages/report/report',
              });
            } else {
              wx.showModal({
                title: res.msg,
                icon: 'error',
                showCancel: false,
                duration: 3000
              });
            }
          });
        } else if (res.cancel) {
          //console.log('用户点击取消')
        }
      }
    })
  },

  save(e) {
    let ostatus = e.currentTarget.dataset.status
    if (this.data.checkedStudents.length == 0) {
      util.alert('请选择观察对象!')
      return
    }
    if (!this.data.selectedDate) {
      util.alert('请选择记录日期!')
      return
    }
    let allHasContent = true //后端要求内容必填 否则以下的内容都不会保存
    allHasContent = this.data.activityMaterials.every(function (item) {
      return item.content != '' && item.content != null && item.content != undefined
    })
    if (!allHasContent) {
      util.alert('请先输入内容!')
      return
    }
    //this.saveDocconfirm() //保存Ai续写的内容
    if (lock) return
    lock = true
    //处理过滤activityMaterials数据
    let actArr = this.data.activityMaterials.map(function (item) {
      let oarr = []
      //转换数据格式
      oarr[0] = {
        content: item.content
      }
      //录音部分转化成特定格式给后端
      for (let i in item.recordArr) {
        oarr.push({
          content: item.recordArr[i].url,
          fileSize: item.recordArr[i].time - 0, //后端要用这个字段名称存储时间
        })
        oarr.push({
          content: item.recordArr[i].txt
        })
      }
      //把图片、视频以content的子级的方式添加到paragraphs里面
      for (let i in item.material) {
        oarr.push({
          content: item.material[i].url
        })
      }
      return {
        paragraphs: oarr
      }
    })
    //console.log(actArr)

    for (let i in actArr) {
      //title等于编辑标题就代表没编辑过 paragraphs[0].content的值为空就代表textare没编辑过 paragraphs[1]不存在或者content为空就代表没编辑过
      if (!actArr[i].paragraphs[0].content && (!actArr[i].paragraphs[1] || !actArr[i].paragraphs[1].content)) {
        actArr.splice(i, 1)
      }
    }

    let observeSceneList = this.data.observeSceneList
    let observeParentIndex = this.data.observeParentIndex
    let observeChildIndex = this.data.observeChildIndex
    let scene = observeSceneList[observeParentIndex].expenseId + ',' + observeSceneList[observeParentIndex].children[observeChildIndex].expenseId

    //过滤数据成后台需要的结构
    let oevaluationItems = this.data.evaluationItems
    //console.log(oevaluationItems)
    oevaluationItems = oevaluationItems.map(function (item) {
      if (item.parentId) {
        return {
          evaluationIndicatorId: item.parentId,
          id: item.id
        }
      } else {
        return {
          evaluationIndicatorId: item.evaluationIndicatorId,
          id: item.id
        }
      }
    })

    let params = {
      userId: this.data.userInfo.userId,
      classId: this.data.classCheckedId,
      type: this.data.idx,
      activityId: this.data.themeChecked.id,
      recordDate: this.data.selectedDate,
      scene: scene,
      purpose: this.data.observe,
      measure: this.data.measure,
      observationParticipants: this.data.checkedStudents,
      observationRecords: actArr,
      evaluationItems: oevaluationItems,
      status: ostatus,
    }
    let requestStyle = ''
    let requestUrl = ''
    if (this.data.oid) {
      params.id = this.data.oid
      requestStyle = 'PUT'
      requestUrl = api.observationViewEdit
    } else {
      requestStyle = 'POST'
      requestUrl = api.observeSceneSave
    }
    wx.showLoading({
      title: '提交中'
    })
    util.request(requestUrl, params, requestStyle, 'application/json').then(res => {
      if (res.code == 200) {
        wx.showToast({
          title: '提交成功!',
          icon: 'success',
          duration: 2000
        })
        this.bookHandle('suc', '')
      } else {
        this.bookHandle('err', res)
      }
    });
  },

  bookHandle(result, ores) {
    const that = this
    let isSuccess = false
    wx.requestSubscribeMessage({
      tmplIds: ['hGQUXKwyQtenWhFPnKvGcZk1mq-hdjxOPSvh_5FT46w'],
      success(res) {
        if (result == 'suc') {
          isSuccess = true
          that.setData({
            oid: '',
            studentArr: [],
            activityId: null,
            checkedStudentsTreated: []
          })
          app.globalData.isActivityMaterials = false //阻止调用onshow
          wx.switchTab({
            url: '/pages/report/report',
          });
          lock = false
          wx.hideLoading();
        } else {
          wx.showToast({
            title: ores.msg,
            icon: 'error',
            duration: 2000
          })
          app.globalData.isActivityMaterials = false
          lock = false
          wx.hideLoading();
        }
      },
      complete() {
        //如果调用成功 则不用调用第二遍 complete是必调用的 所以拦住省得第二次触发
        if (isSuccess) return
        app.globalData.isActivityMaterials = false //阻止调用onshow
        wx.switchTab({
          url: '/pages/report/report',
        });
        lock = false
        wx.hideLoading();
      },
    })
  },

  saveHandle() {
    if (editType == 0) { //添加
      wx.switchTab({
        url: '/pages/activityn/activityn',
      })
    } else { //修改
      wx.navigateBack({
        delta: 1
      });
    }
    lock = false
    wx.hideLoading();
  },

  tabHandle(e) {
    //清掉幼儿发展水平评估的选中状态
    let oindex = e.currentTarget.dataset.idx
    this.setData({
      openArea: false,
      idx: oindex,
      areaStr: '', //重置幼儿发展水平评估选中的值
      areaSecondIndex: 0,
      areaFirstIndex: 0,
      // threeData: [],
      // selectArea: [],
      evaluationItems: [],
      sceneChecked: e.currentTarget.dataset.scene,
      themeExt: e.currentTarget.dataset.ext == 1 ? true : false,
      //classCheckedId: this.data.classData[0].classId,//ly-add 2023-10-09
    })
    // if(oindex == '2'){
    //   this.setData({
    //     pageNum: 1,
    //     activityList: [],//指向主题活动列表
    //   })      
    // }   
    this.getIndex();
    this.getListSelectArea();
  },

  monitorMeasureInput(e) {
    let value = e.detail.value.replace(/\n\s*/g, '\n'); // 获取输入的文本内容
    if (value.length > 500) {
      value = value.slice(0, 500);
    }
    this.setData({
      measure: value,
      measureNumber: value.length || 0,
    })
  },

  bindParentChange: function (e) {
    const observeParentIndex = e.detail.value;
    const childArray = this.data.observeSceneList[observeParentIndex].children; // 根据选中的父级索引获取对应的子集数组
    this.setData({
      observeParentIndex: observeParentIndex,
      childArray: childArray,
      observeChildIndex: 0,
    });
  },
  bindChildChange: function (e) {
    const observeChildIndex = e.detail.value;
    // 获取选中的父级和子集数据
    // const parentData = this.data.observeSceneList[this.data.parentIndex];
    // const childData = this.data.childArray[childIndex];
    this.setData({
      observeChildIndex: observeChildIndex
    });
  },

  //观察场景请求数据
  getObserveScene() {
    var that = this;
    util.request(api.listObserveScene, '', 'get').then(res => {
      if (res.code == 200) {
        that.setData({
          observeSceneList: res.data
        })
        this.getIndex()
      } else {
        wx.showToast({
          title: res.msg,
          icon: 'error',
          duration: 2000
        })
      }
    });
  },

  //获取观察场景的父级index、子集index
  getIndex() {
    const that = this
    let observeSceneList = this.data.observeSceneList
    observeSceneList.forEach(function (item, index) {
      //ly-edit 2023-09-15 非编辑状态添加默认的子级 如果是编辑状态就重新赋值
      let sceneChecked = that.data.sceneChecked
      if (item.expenseId == sceneChecked.split(",")[0]) {
        let cIndex = item.children.findIndex(citem => citem.expenseId == sceneChecked.split(",")[1]);
        that.setData({
          observeParentIndex: index,
          childArray: item.children, //先给一个默认值
          observeChildIndex: cIndex
        })
      }
    });
  },

  //选择记录日期
  bindDateChange(e) {
    let oval = e.detail.value
    this.setData({
      selectedDate: oval
    });
  },

  //指向主题活动加载更多
  loadMoreActivity() {
    if (this.data.flag) return
    this.getListSelectActivity();
  },

  //指向主题活动选中某一个元素
  checkActivityHandle(e) {
    let otheme = this.data.activityList
    let oidx = e.currentTarget.dataset.idx
    let obj = otheme[oidx]
    //重置选中状态
    otheme = otheme.map(item => {
      item.checked = false;
      return item;
    });
    otheme[oidx].checked = true
    let themeStr = otheme[oidx].name + (otheme[oidx].status == '1' ? '整理' : '计划') + (otheme[oidx].monthWeek ? otheme[oidx].monthWeek : '')
    this.setData({
      activityList: otheme,
      themeChecked: obj,
      openTheme: false,
      themeStr: themeStr,
    })
  },

  //加载指向主题活动数据
  getListSelectActivity() {
    let oclassId = this.data.classCheckedId == this.data.userInfo.schoolId ? '' : this.data.classCheckedId;
    var param = '&classId=' + oclassId + '&schoolId=' + this.data.userInfo.schoolId
    util.request(api.listSelectActivity + this.data.pageNum + '&pageSize=' + this.data.pageSize + param + '&id=' + (this.data.activityId ? this.data.activityId : '') + '&includeActiveAuthPlan=' + true, '', 'get').then(res => {
      if (res.code == 200) {
        let odata = res.rows
        let newDataList = this.data.activityList.concat(odata);
        //回显
        if (this.data.activityId) {
          for (let i in newDataList) {
            if (newDataList[i].id == this.data.activityId) {
              newDataList[i].checked = true
              let themeStr = newDataList[i].name + (newDataList[i].status == '1' ? '整理' : '计划') + newDataList[i].monthWeek
              this.setData({
                themeStr: themeStr
              })
              break
            }
          }
        }
        this.setData({
          activityList: newDataList,
          pageNum: this.data.pageNum + 1,
        })
        if (newDataList.length >= res.total) {
          this.setData({
            flag: true,
            moreTxt: '-无更多数据-'
          })
        } else {
          this.setData({
            flag: false,
            moreTxt: '-点击加载更多-'
          })
        }
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  //开关闭合 幼儿发展水平评估
  openAreaHandle() {
    //获取areaStr的值
    let str = ''
    let evaluationItems = this.data.evaluationItems
    for (let i in evaluationItems) {
      if (evaluationItems[i].label) {
        str += evaluationItems[i].label
      } else {
        str += (evaluationItems[i].sort + ':' + evaluationItems[i].syndrome)
      }
    }
    str = str.substring(0, str.length - 1)
    this.setData({
      openArea: this.data.openArea ? false : true,
      areaStr: str
    })
  },

  checkedAreaHandle(e) {
    let parentIndex = e.currentTarget.dataset.parentindex
    let childindex = e.currentTarget.dataset.childindex
    let oitem = e.currentTarget.dataset.item
    let evaluationItems = this.data.evaluationItems
    let threeData = this.data.threeData
    //思路:点击的时候 判断当前checked是否为true 如果是true则改为false 如果是false通过父级index 把父级下标下所有的checked改为false 在子级下标对应的那个值改为true
    //1、判断点击的元素 checked是否为true
    let activeList = ''
    if (this.data.showAreaSecond) {
      activeList = threeData.children[parentIndex].children[childindex] //选中的元素      
    } else {
      activeList = threeData[parentIndex].children[childindex] //选中的元素      
    }
    if (activeList.checked) { //重置 如果是true改为false
      for (let i in evaluationItems) { //删除相同id的item
        if (evaluationItems[i].id == oitem.id) {
          evaluationItems.splice(i, 1)
          break
        }
      }
      activeList.checked = false
    } else {
      if (this.data.showAreaSecond) {
        threeData.children[parentIndex].children.forEach(function (item) {
          //遍历清除该点击元素同级的所有元素
          for (let i in evaluationItems) {
            if (item.id == evaluationItems[i].id) {
              evaluationItems.splice(i, 1)
            }
          }
          item.checked = false
        })
      } else {
        threeData[parentIndex].children.forEach(function (item) {
          //遍历清除该点击元素同级的所有元素
          for (let i in evaluationItems) {
            if (item.id == evaluationItems[i].id) {
              evaluationItems.splice(i, 1)
            }
          }
          item.checked = false
        })
      }

      evaluationItems.push(oitem)
      activeList.checked = true
    }

    //如果threeData里有checked是true 那就出现角标
    //获取第一级的index
    //console.log(this.data.areaFirstIndex)
    //console.log(threeData)
    let hasCornerMark = false
    if (this.data.showAreaSecond) {
      hasCornerMark = this.findCheckedItem(threeData.children)
    } else {
      hasCornerMark = this.findCheckedItem(threeData)
    }

    let selectArea = this.data.selectArea
    selectArea[this.data.areaFirstIndex].checked = hasCornerMark
    //console.log(evaluationItems)
    this.setData({
      threeData,
      selectArea
    })

  },

  //查找多层级数组中是否带有checked为true的属性并返回
  findCheckedItem(arr) {
    const that = this
    for (let item of arr) {
      if (item.checked === true) {
        return true;
      }
      if (item.children && item.children.length > 0) {
        const found = that.findCheckedItem(item.children);
        if (found) {
          return true;
        }
      }
    }
    return false;
  },

  updateCheckedStatus(arr1, arr2) {
    for (let i = 0; i < arr1.length; i++) {
      // 检查当前元素的id是否在arr2中存在
      if (arr2.some(item => item.id === arr1[i].id)) {
        arr1[i].checked = true;
      }
      // 递归遍历children数组
      if (arr1[i].children) {
        this.updateCheckedStatus(arr1[i].children, arr2);
      }
    }
  },

  //第三级页面显示
  getThreeData() {
    let listSelect = this.data.listSelect
    if (this.data.showAreaSecond) {
      //需要加children
      let areaSecondIndex = this.data.areaSecondIndex      
      //回显    
      if(listSelect.length > 0 && this.data.evaluationItems.length > 0){  
        this.updateCheckedStatus(listSelect[areaSecondIndex].children, this.data.evaluationItems)      
      }
      this.setData({
        threeData: listSelect[areaSecondIndex]
      })
    } else {
      //不需要加children
      //回显      
      if(listSelect.length > 0 && this.data.evaluationItems.length > 0){  
        this.updateCheckedStatus(listSelect, this.data.evaluationItems)
      }
      this.setData({
        threeData: listSelect
      })
    }
  },

  getAreaSecondIndex(e) {
    let index = e.currentTarget.dataset.index
    this.setData({
      areaSecondIndex: index
    })
    this.getThreeData()
  },

  //指标列表
  getlistSelect(id) {
    util.request(api.listSelect + id + '&observationViewId=' + this.data.observationViewId, '', 'get').then(res => {
      if (res.code == 200) {
        //有可能消失的第二级 如果第一级的id用于查询指标列表 指标列表type是3 则第二级显示 如果type是4则该第二级隐藏 ***如果没有children 直接使用选项卡*** 第二级是单选
        let odata = res.data
        let showAreaSecond = this.data.showAreaSecond //是否展示二级 
        // 使用find方法找到第一个包含非null children数组的元素
        const elementWithChildren = odata.find(element => element.children !== null);
        let firstType = ''
        // 如果找到了包含非null children数组的元素
        if (elementWithChildren) {
          // 使用some方法遍历children数组,找到第一个type字段的值
          firstType = elementWithChildren.children.find(child => child.type).type;                          
        } else {
          //都没有children的情况
          //console.log('No element with non-null children found.');
        }
        if (odata.length > 0 && (firstType == '3')) {
          showAreaSecond = true
        } else {
          showAreaSecond = false
        }
        this.setData({
          listSelect: res.data,
          showAreaSecond: showAreaSecond
        })
        //获取并展示第三级页面的值
        this.getThreeData()
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  //一级的tab操作
  getSelectAreaId(e) {
    let id = e.currentTarget.dataset.id
    let index = e.currentTarget.dataset.index
    this.setData({
      areaFirstIndex: index,
    })
    this.getlistSelect(id)
  },

  //选择评估对象
  getListSelectArea() {
    util.request(api.listSelectArea2 + (this.data.userInfo.schoolId ? this.data.userInfo.schoolId : '') + '/' + this.data.idx, '', 'get').then(res => {
      if (res.code == 200) {
        let odata = res.data
        let arryNew = []
        odata.map((item) => {
          arryNew.push(Object.assign({}, item, {
            checked: false
          }))
        })
        this.setData({
          selectArea: arryNew
        })
        if (odata.length == 0) return
        //默认查询第一条id对应的指标列表
        this.getlistSelect(odata[0].id)
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  monitorObserveInput(e) {
    this.setData({
      observe: e.detail.value,
      observeNumber: e.detail.cursor
    })
  },

  openObserveHandle() {
    let selectedDate = this.data.selectedDate
    let observeSceneList = this.data.observeSceneList
    let observeParentIndex = this.data.observeParentIndex
    let observeChildIndex = this.data.observeChildIndex
    let scene = selectedDate + ',' + observeSceneList[observeParentIndex].expenseItem + observeSceneList[observeParentIndex].children[observeChildIndex].expenseItem + ',' + (this.data.observe ? this.data.observe : '')
    this.setData({
      openObserve: this.data.openObserve ? false : true,
      observeStr: scene
    })
  },

  //处理选中学生如果超过十个用...显示
  checkedStudentsHandle(oarr) {
    if (this.data.openStudents && oarr.length > 10) {
      //如果关闭的时候 选中的列表超过10个则截取列表剩下9个显示
      oarr = oarr.slice(0, 9)
      this.setData({
        checkedStudentsTreated: oarr
      })
    } else {
      this.setData({
        checkedStudentsTreated: this.data.checkedStudents
      })
    }
  },

  openStudentHandle() {
    let oarr = JSON.parse(JSON.stringify(this.data.checkedStudents))
    this.checkedStudentsHandle(oarr)

    this.setData({
      openStudents: this.data.openStudents ? false : true
    })
  },

  checkHandle(e) {
    let idx = e.currentTarget.dataset.idx
    let arr = this.data.students
    arr[idx].checked = arr[idx].checked == true ? false : true

    let checkedarr = arr.filter(function (item) {
      return item.checked == true
    })

    this.setData({
      students: arr,
      checkedStudents: checkedarr
    })
  },

  checkClassHandle(e) {
    //this.data.classCheckedId == e.currentTarget.datasetid ? [] : this.data.checkedStudentsTreated
    this.setData({
      classCheckedId: e.currentTarget.dataset.id,
      flag: false,
      pageNum: 1,
      activityList: [], //指向主题活动列表
      students: [],
      checkedStudents: [],
      checkedStudentsTreated: [],
      themeChecked: {},
      themeStr: '',
      activityId: null
    })

    this.getStudent()
    this.getListSelectActivity();//ly-edit 2023-10-09
    this.getListSelectArea(); //ly-add 2023-10-09
  },

  getStudent() {
    var param = {};
    param.deptId = this.data.classCheckedId;
    param.schoolId = wx.getStorageSync('userInfo').schoolId;
    util.request(api.studentList, param, 'POST').then(res => {
      if (res.code == 200) {
        let oarr = res.rows.map(function (item) {
          return {
            studentId: item.id,
            studentName: item.name,
            studentNumber: item.number,
            studentImage: item.headUrl ? item.headUrl : '',
            sex: item.sex,
            checked: false
          }
        })
        if (this.data.checkedStudents.length > 0) {
          let checkedStudents = this.data.checkedStudents
          //判断两个数组是否有相同的id 如果有相同的id 给当前的student添加选中状态
          oarr.forEach(item => {
            const isChecked = checkedStudents.some(citem => citem.studentId === item.studentId);
            item.checked = isChecked;
          });
        }
        this.setData({
          students: oarr
        })
      } else {
        wx.showModal({
          title: res.msg,
          icon: 'error',
          showCancel: false,
          duration: 3000
        });
      }
    });
  },

  timeHandle(time) {
    if (time < 10) {
      return '0' + time
    } else {
      return time
    }
  },

  //重置录音按钮状态
  resetRecordState() {
    let activityMaterials = this.data.activityMaterials
    activityMaterials[this.data.parentIndex].recordState = false
    this.setData({
      activityMaterials: activityMaterials
    })
  },

  addListHandle() {
    let obj = this.data.activityMaterials
    obj.push({
      content: '',
      material: []
    })
    this.setData({
      activityMaterials: obj
    })
  },

  textareaBlurHandle(e) {
    let oval = e.detail.value
    let obj = this.data.activityMaterials
    let idx = e.currentTarget.dataset.idx
    obj[idx].content = oval
    this.setData({
      activityMaterials: obj
    })
  },

  preview(e) {
    let currentUrl = e.currentTarget.dataset.src
    let pidx = e.currentTarget.dataset.pidx //父级循环的index
    const oarr = []
    for (let i in this.data.activityMaterials[pidx].material) {
      oarr.push(this.data.activityMaterials[pidx].material[i].url)
    }
    wx.previewImage({
      current: currentUrl, // 当前显示图片的http链接
      urls: oarr // 需要预览的图片http链接列表
    })
  },

  closeHadle(e) {
    const that = this
    wx.showModal({
      title: '',
      content: '是否删除素材',
      success(res) {
        if (res.confirm) {
          let obj = that.data.activityMaterials
          let pidx = e.currentTarget.dataset.pidx //父级循环的index
          let idx = e.currentTarget.dataset.idx //子级循环的index
          obj[pidx].material.splice(idx, 1)
          that.setData({
            activityMaterials: obj
          })
        } else if (res.cancel) {
          //console.log('用户点击取消')
        }
      }
    })
  },

  //上传图片、视频
  uploadFile: function (e) {
    //如果不添加这个判断 则在这里会默认调用onshow
    app.globalData.isActivityMaterials = true //阻止调用onshow
    const that = this
    let obj = this.data.activityMaterials
    let pidx = e.currentTarget.dataset.idx
    wx.chooseMedia({
      count: 9, // 设置为需要上传的文件数量
      mediaType: ['image', 'video'],
      sizeType: ['compressed'], //压缩图片
      success: function (res) {
        const files = res.tempFiles;
        // 遍历选择的文件数组,依次上传每个文件
        wx.showLoading({
          title: '上传中'
        })
        files.forEach(function (file) {
          const tempFilePath = file.tempFilePath;
          wx.uploadFile({
            url: BASE_URL + 'common/uploadMediaToTencent',
            formData: {
              'userId': wx.getStorageSync('userInfo').userId,
              'scene': 'observation'
            },
            filePath: tempFilePath,
            name: 'file',
            success: function (res) {
              let ores = JSON.parse(res.data)
              //每个数组里添加一个type值是mp4或者img,在for循环里通过type赋值到mp4或者img里面
              let otype = that.getFileExtension(ores.url)
              if (otype) {
                let params = {
                  url: ores.url,
                  type: otype
                }
                obj[pidx].material.push(params)
              }
              that.setData({
                activityMaterials: obj,
              })
              wx.hideLoading();
            },
            fail: function (res) {
              // 处理上传失败后的逻辑
              wx.hideLoading();
            }
          })
        });
      }
    })
  },
  //用一个方法来判断 返回的文件是mp4 还是图片
  getFileExtension(url) {
    const dotIndex = url.lastIndexOf('.');
    const extension = url.substring(dotIndex + 1);
    if (/(jpg|jpeg|png)$/.test(extension.toLowerCase())) {
      return 'img'
    } else if (/(mp4|avi|mov)$/.test(extension.toLowerCase())) {
      return 'mp4'
    }
    return false
  },

  deleteHandle(e) {
    const that = this
    wx.showModal({
      title: '',
      content: '是否删除',
      success(res) {
        if (res.confirm) {
          let obj = that.data.activityMaterials
          let idx = e.currentTarget.dataset.idx //子级循环的index
          obj.splice(idx, 1)
          that.setData({
            activityMaterials: obj
          })
        } else if (res.cancel) {
          //console.log('用户点击取消')
        }
      }
    })
  },

  //识别语音 -- 初始化
  initRecord: function () {
    var that = this;
    wx.onSocketOpen((res) => { // websocket打开
      //console.log('监听到 WebSocket 连接已打开' + res);
    })
    wx.onSocketError((err) => { //连接失败
      //console.log('websocket连接失败', err);
      wx.showToast({
        title: 'websocket连接失败',
        icon: 'none',
        duration: 2000,
        mask: false
      })
    })
    wx.onSocketMessage((res) => { //接收返回值
      var data = JSON.parse(res.data)
      //console.log(data)
      if (data.code != 0) {
        //console.log("error code " + data.code + ", reason " + data.message)
        return
      }
      let str = ""
      if (data.data.status == 2) { //最终识别结果
        // data.data.status ==2 说明数据全部返回完毕,可以关闭连接,释放资源
        wxst.close();
      } else { //中间识别结果
      }
      iatResult[data.data.result.sn] = data.data.result
      if (data.data.result.pgs == 'rpl') {
        data.data.result.rg.forEach(i => {
          iatResult[i] = null
        })
      }
      iatResult.forEach(i => {
        if (i != null) {
          i.ws.forEach(j => {
            j.cw.forEach(k => {
              str += k.w
            })
          })
        }
      });
      // console.log('这个是中间的语音识别结果')
      // console.log(str)
      that.setData({
        contentTxt: str //这个是中间的语音识别结果
      })
      if (!this.data.contentTxt) {
        wx.showToast({
          title: '识别失败,请重新录入',
          icon: 'none',
          duration: 2000,
          mask: false
        })
        return
      }
    })
    wx.onSocketClose((res) => { //WebSocket连接已关闭!
      //var that = this;
      recorderManager.stop();
      // var str = that.data.contentTxt;
      // console.log(str);
      // str = str.replace(/\s*/g, "");//去除空格
      // if (str.substr(str.length - 1, 1) == "。") {//去除句号
      //   str = str.substr(0, str.length - 1);
      // }
      // console.log('这个是最后确定的语音识别结果', str)
      // that.setData({
      //   contentTxt: str//这个是最后确定的语音识别结果
      // })
      //console.log('WebSocket连接已关闭!')
    })
  },

  //录音和停止录音操作
  recordHandle(e) {
    let oactivityMaterials = this.data.activityMaterials
    let parentIndex = e.currentTarget.dataset.idx

    this.setData({ //获取父级的下标 后面录音结束后给对应的模块赋值
      parentIndex: parentIndex
    })
    //改成点击事件
    if (!oactivityMaterials[parentIndex].recordState) {
      wx.showToast({
        title: '开始录音',
        icon: 'none',
        duration: 1000
      })
      //兄弟节点的录音按钮改成灰色
      if (oactivityMaterials.length > 1) {
        for (let i in oactivityMaterials) {
          oactivityMaterials[i].recordState = false
        }
        this.setData({
          activityMaterials: oactivityMaterials
        })
      }
      oactivityMaterials[parentIndex].recordState = true
      this.setData({
        activityMaterials: oactivityMaterials //录音状态
      })
      wx.getSetting({ //查看用户有没有开启语音权限
        success(res) {
          if (res.authSetting['scope.record']) {
            wx.authorize({
              scope: 'scope.record',
              success() {
                var xfurl = "";
                wx.request({ //请求接口 获取讯飞语音鉴权
                  url: BASE_URL + 'assistant/url',
                  method: "get",
                  header: {
                    'content-type': 'application/json' // 默认值
                  },
                  success: function (res) {
                    //console.log('鉴权结果start:');
                    //console.log(res);
                    if (res.statusCode == "200" && res.data) {
                      xfurl = res.data;
                      wxst = wx.connectSocket({ // 开启websocket连接
                        url: xfurl,
                        method: 'GET',
                        success: function (res) {
                          recorderManager.start(searchoptions); //开始录音
                        }
                      });
                    } else {
                      wx.showToast({
                        title: '获取语音鉴权失败',
                        icon: 'none',
                        mask: true,
                        duration: 3000
                      })
                    }
                  },
                  fail: function () {
                    wx.showToast({
                      title: '获取语音鉴权失败',
                      icon: 'none',
                      mask: true,
                      duration: 3000
                    })
                  }
                })
              },
              fail() {
                wx.showModal({
                  title: '微信授权',
                  content: '您当前未开启语音权限,请在右上角设置(···)中开启“录音功能”',
                  showCancel: false,
                  success(res) {
                    if (res.confirm) {
                      //console.log('用户点击确定')
                    }
                  }
                })
              }
            })
          } else {
            wx.showModal({
              title: '微信授权',
              content: '您当前未开启语音权限,请在右上角设置(···)中开启“录音功能”',
              showCancel: false,
              success(res) {
                if (res.confirm) {
                  //console.log('用户点击确定')
                }
              }
            })
          }
        }
      })
    } else {
      oactivityMaterials[parentIndex].recordState = false
      this.setData({
        activityMaterials: oactivityMaterials
      })
      recorderManager.stop();
    }
  },

  //播放操作
  playHandle(e) {
    const that = this
    let idx = e.currentTarget.dataset.idx
    let pidx = e.currentTarget.dataset.pidx
    //recordArr的字段有url/txt/time/played/showTxt: false,//语音的文字部分是否展示showTip: false,//Tooltip 文字提示是否展示directionUp: false,//Tooltip的方向是向上还是向下    
    let activityMaterials = this.data.activityMaterials
    let orecordArr = activityMaterials[pidx].recordArr[idx]

    innerAudioContext.src = orecordArr.url
    if (!orecordArr.played) {
      //查找兄弟节点 把所有的played状态改成false
      for (let i in activityMaterials) {
        for (let j in activityMaterials[i].recordArr) {
          activityMaterials[i].recordArr[j].played = false
        }
      }
      // if(activityMaterials && activityMaterials.length > 1){
      //   that.setData({
      //     activityMaterials: activityMaterials
      //   })
      // }
      //播放
      orecordArr.played = true
      innerAudioContext.play() // 播放      
      innerAudioContext.onEnded(() => {
        //console.log('语音播放结束');     
        orecordArr.played = false
        that.setData({
          activityMaterials: activityMaterials
        })
      });
    } else {
      //关闭
      orecordArr.played = false
      innerAudioContext.stop() // 停止
    }
    this.setData({
      activityMaterials: activityMaterials
    })

  },

  onLongPress(e) {
    //console.log(e)
    //const listItem = e.currentTarget;
    let activityMaterials = this.data.activityMaterials
    let pidx = e.currentTarget.dataset.pidx //父级下标
    let idx = e.currentTarget.dataset.idx //子级下标
    //console.log(e.touches[0].clientY)
    let oClientY = e.touches[0].clientY * 2 //点击的位置和Y轴顶部的距离

    //隐藏所有语音列表的tip
    //console.log(activityMaterials)
    for (let i in activityMaterials) {
      for (let j in activityMaterials[i].recordArr) {
        activityMaterials[i].recordArr[j].showTip = false
      }
    }
    this.setData({
      activityMaterials: activityMaterials
    })

    //判断只要距离Y轴顶部的距离 大于220rpx 一律往上面冒泡    
    if (oClientY > 220) {
      activityMaterials[pidx].recordArr[idx].directionUp = true
    } else {
      activityMaterials[pidx].recordArr[idx].directionUp = false
    }
    activityMaterials[pidx].recordArr[idx].showTip = true
    this.setData({
      activityMaterials: activityMaterials,
      maskShow: true
    })
  },

  txtRecordHandle(e) {
    let activityMaterials = this.data.activityMaterials
    let pidx = e.currentTarget.dataset.pidx //父级下标
    let idx = e.currentTarget.dataset.idx //子级下标
    activityMaterials[pidx].recordArr[idx].showTxt = true
    activityMaterials[pidx].recordArr[idx].showTip = false
    this.setData({
      activityMaterials: activityMaterials
    })
  },

  delRecordHandle(e) {
    let activityMaterials = this.data.activityMaterials
    let pidx = e.currentTarget.dataset.pidx //父级下标
    let idx = e.currentTarget.dataset.idx //子级下标
    activityMaterials[pidx].recordArr.splice(idx, 1)
    this.setData({
      activityMaterials: activityMaterials,
      maskShow: false
    })
  },

  closeTipHandle() {
    let activityMaterials = this.data.activityMaterials
    //隐藏所有语音列表的tip
    //console.log(activityMaterials)
    for (let i in activityMaterials) {
      for (let j in activityMaterials[i].recordArr) {
        activityMaterials[i].recordArr[j].showTip = false
      }
    }
    this.setData({
      activityMaterials: activityMaterials,
      maskShow: false
    })
  },

  onUnload: function () {
    innerAudioContext.stop() // 停止        
  },

  onShareAppMessage() {},

  recordAiHandle(e) {
    let oactivityMaterials = this.data.activityMaterials
    let parentIndex = e ? e.currentTarget.dataset.idx : this.data.aiParentIndex
    let params = {
      docstyle: 3, //如果观察记录有值输入3 没值输入1
      content: {
        'level1': this.data.observeSceneList[this.data.observeParentIndex].expenseItem,
        'level2': this.data.childArray[this.data.observeChildIndex].expenseItem,
      },
      text: oactivityMaterials[parentIndex].content
    }
    wx.showLoading({
      title: '加载中...'
    });
    util.request('https://ai.keeko.ai/docgeneration', params, 'POST', 'application/json').then(res => {
      wx.hideLoading();
      if (res.result == 1) {
        this.setData({
          aiPolish: res.data.text,
          aistyle: e ? e.currentTarget.dataset.aistyle : this.data.aistyle,
          aiParentIndex: parentIndex
        })
        if (!this.data.showPolish) {
          this.setData({
            showPolish: true
          })
        }
      } else {
        wx.showToast({
          title: '尚在学习中',
          icon: 'none',
          mask: true,
          duration: 3000
        })
      }
    });
  },

  //Ai续写 观察目的
  aimAiHandle(e) {
    let observe = this.data.observe
    let params = {
      docstyle: !observe ? 1 : 2, //如果目的有值输入2 没值输入1
      content: {
        'level1': this.data.observeSceneList[this.data.observeParentIndex].expenseItem,
        'level2': this.data.childArray[this.data.observeChildIndex].expenseItem,
      },
      text: observe
    }
    wx.showLoading({
      title: '加载中...'
    });
    util.request('https://ai.keeko.ai/docgeneration', params, 'POST', 'application/json').then(res => {
      wx.hideLoading();
      if (res.result == 1) {
        this.setData({
          aiPolish: res.data.text,
          aistyle: e ? e.currentTarget.dataset.aistyle : this.data.aistyle
        })
        //aiAgain 重写的时候不刷新弹窗状态
        if (!this.data.showPolish) {
          this.setData({
            showPolish: true
          })
        }
      } else {
        wx.showToast({
          title: '尚在学习中',
          icon: 'none',
          mask: true,
          duration: 3000
        })
      }
    });
  },

  //判断是不是空对象
  isEmptyObject(obj) {
    return Object.keys(obj).length === 0;
  },

  saveDocconfirm() {
    let observe = this.data.observe
    let level1 = this.data.observeSceneList[this.data.observeParentIndex].expenseItem
    let level2 = this.data.childArray[this.data.observeChildIndex].expenseItem
    let observeParams = {}
    if (observe) {
      observeParams = {
        docstyle: 2, //2代表观察目的
        content: {
          'level1': level1,
          'level2': level2,
        },
        title: '观察目的',
        text: this.data.aimAiKeyword,
        doctext: this.data.aimAiPolish
      }
      //console.log(observeParams)
    }
    //先过滤无值的项
    let activityArr = []
    if (this.data.activityMaterials.length > 0 && this.data.activityMaterials[0].content) {
      activityArr = this.data.activityMaterials.map(function (item) {
        if (item.recordAiPolish) {
          return {
            docstyle: 3, //2代表观察目的
            content: {
              'level1': level1,
              'level2': level2,
            },
            title: '观察记录',
            text: item.aiKeyword,
            doctext: item.recordAiPolish
          }
        }
      })
    }
    if (!this.isEmptyObject(observeParams)) {
      activityArr.unshift(observeParams)
    }
    let params = {
      doc: activityArr
    }
    if (activityArr.length == 0) return
    util.request('https://ai.keeko.ai/docconfirm', params, 'POST', 'application/json').then(res => {
      //console.log(res)
    });
  },

  aiCancel() {
    this.setData({
      showPolish: false,
    })
  },

  aiAgain() {
    if (this.data.aistyle == '1') {
      this.aimAiHandle()
    } else {
      this.recordAiHandle()
    }
  },

  aiConfirm() {
    if (this.data.aistyle == '1') {
      let otxt = this.data.aiPolish
      let value = (this.data.observe + otxt).replace(/\n\s*/g, '\n'); // 获取输入的文本内容
      if (value.length > 500) {
        value = value.slice(0, 500);
      }
      this.setData({
        aimAiPolish: otxt,
        aimAiKeyword: this.data.observe, //关键词
        observe: value,
        observeNumber: value.length,
        showPolish: false,
      })
    } else {
      let oactivityMaterials = this.data.activityMaterials
      let parentIndex = this.data.aiParentIndex
      let otxt = this.data.aiPolish
      let value = (oactivityMaterials[parentIndex].content + otxt).replace(/\n\s*/g, '\n'); // 获取输入的文本内容
      if (value.length > 500) {
        value = value.slice(0, 500);
      }
      oactivityMaterials[parentIndex].aiKeyword = oactivityMaterials[parentIndex].content
      oactivityMaterials[parentIndex].content = value
      oactivityMaterials[parentIndex].recordAiPolish = otxt
      this.setData({
        activityMaterials: oactivityMaterials,
        showPolish: false,
      })
    }
  },

  monitorPopInput(e) {
    this.setData({
      aiPolish: e.detail.value
    })
  },
})
.wrap{ padding: 30rpx 30rpx 100rpx 30rpx;}
.header-tab{ display: flex; overflow-x: scroll;}
.tab-list{ position: relative; margin-right: 20rpx; padding: 0; background: #fff; text-align: center;border-radius: 16rpx; opacity: 0.3;}
.tab-list:last-child{ margin-right: 0;}
.icon-daily{ margin: 0 auto; display: block; width: 225rpx; height: 178rpx; border-radius: 10rpx;}
.tab-list .v1{ position: absolute; bottom: 0; left: 0; width: 100%; height: 50rpx; line-height: 50rpx; background: #33a9ff; color: #fff; font-size: 28rpx; border-radius: 0 0 10rpx 10rpx; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
.tab-list.active{ opacity: 1;}
.title-box{ display: flex; align-items: center; font-size: 26rpx; font-weight: bold;}
.warn{ margin-top: 100rpx; text-align: center;}
.icon-add{ margin-left: 15rpx; display: block; width: 124rpx; height: 124rpx;}
.student-item{ display: flex; flex-wrap: wrap;}
.student-list{ position: relative;}
.student-list .v1{ margin-top: 10rpx; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 22rpx; color: #777;}
.student-photo{ margin: 0 auto; display: block; width: 124rpx; height: 124rpx; border-radius: 50%;}
.student-box{ padding: 30rpx 0 45rpx 0; display: grid; grid-template-columns: repeat(4, 1fr); grid-gap: 20rpx 0;}
.record-white-box{ margin-top: 30rpx; padding: 22rpx}

.title-box,.title-txt-part{ display: flex; align-items: center;}
.icon-close-black{ display: block; width: 28rpx; height: 16rpx;}
.icon-close-black2{ display: block; width: 28rpx; height: 28rpx;}
.icon-edit{ margin-left: 10rpx; width: 31rpx; height: 30rpx;}
.yellow-fence{ margin-right: 10rpx; width: 6rpx; height: 30rpx; background: #33a9ff; border-radius: 3rpx;}
.title-txt-part{ flex: 1; font-size: 28rpx; font-weight: bold;}
.title-input{ padding-left: 16rpx; width: 360rpx; height: 60rpx; border:1rpx solid #ddd; border-radius: 10rpx; font-size: 26rpx;}
.material-box{ margin-top: 22rpx; display: flex; justify-content: flex-start; flex-wrap: wrap;}
.upload-box{ margin: 0 25rpx 25rpx 0; padding: 0; display: flex; justify-content: center; align-items: center; width: 310rpx; height: 186rpx; background: #f0f0f0; font-size: 25rpx; color: #111; border: 0; border-radius: 22rpx;}
button::after {border: none;}
.icon-photo{ margin-right: 10rpx; display: block; width: 93rpx; height: 85rpx;}
.material-list{ position: relative; margin: 0 25rpx 25rpx 0; width: 295rpx; height: 186rpx;}
.material-list-m2{ width: 100%; height: 100%; border-radius: 22rpx;}
.icon-close{ position: absolute; top: 10rpx; right: 10rpx; z-index: 999; display: block; width: 50rpx; height: 50rpx;}
.add-box{ margin-top: 30rpx; display: flex; justify-content: center; align-items: center; display: flex; font-size: 28rpx; color: #33a9ff;}
.save-btn{ margin: 100rpx auto 0 auto; width: 330rpx; height: 84rpx; text-align: center; line-height: 84rpx; background: #33a9ff; font-size: 30rpx; color: #111; font-weight: bold; border-radius: 42rpx;}

.textarea-box-wrap{ position: relative; margin-top: 22rpx; padding: 22rpx 22rpx 100rpx 22rpx; background: #f0f0f0; border-radius: 10rpx;}
.textarea-box{ width: 100%; height: 300rpx; box-sizing: border-box; font-size: 25rpx; color: #111;}
.voice-box{ margin-bottom: 20rpx; box-sizing: border-box; background: #f0f0f0; font-size: 25rpx; color: #111;}
.videoBtn {width: 50%;}
.videoBtn text{color:#fff;}
.videoBtnBg {background: #bdb4b4;}
.icon-record{ display: block; width: 70rpx; height: 70rpx;}
.textarea-box-footer{ position: absolute; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; width: 100%; height: 100rpx;}
.record-btn{ margin: 0; padding: 0; width: 70rpx; height: 70rpx; background: transparent; border-radius: 50%;}
button::after{border: none;}
.record-list{ padding-left: 18rpx; display: flex; align-items: center; box-sizing: border-box; width: 640rpx; height: 74rpx; background: #fff; color: #19b2ff; border-radius: 18rpx;}
.icon-video{ display: block; width: 56rpx; height: 55rpx;}
.record-list .t1{ margin: 0 22rpx;}
.record-txt{ padding:10rpx 10rpx 0 10rpx; font-size: 24rpx; color: #19b2ff;}
.record-item{ margin-bottom: 22rpx;}
.record-item:last-child{ margin-bottom: 0;}
.icon-txt{ display: block; width: 60rpx; height: 61rpx;}
.icon-del{ margin-top: 10rpx; display: block; width: 41rpx; height: 53rpx;}
.pos-box{ position: absolute; left: 50%; z-index: 999; transform: translateX(-50%); display: flex; align-items: center; width: 300rpx; height: 140rpx; background: #19b2ff; border-radius: 14rpx;}
.pos-box-lef,.pos-box-rig{ flex: 1; height: 140rpx; display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: 24rpx; color: #fff;}
.pos-box-lef .t1,.pos-box-rig .t1{ margin-top: 6rpx;}
.icon-arrow-up,.icon-arrow-down{ display: block; width: 28rpx; height: 19rpx;}
.icon-arrow-down{ position: absolute; bottom: -19rpx; left: 50%; transform: translateX(-50%);}
.icon-arrow-up{ position: absolute; top: -19rpx; left: 50%; transform: translateX(-50%);}
.mask{ position: fixed; z-index: 99; top: 0; right: 0; bottom: 0; left: 0; background: transparent}

.icon-check{display: block; width: 42rpx; height: 42rpx;}
.icon-check{ position: absolute; top: 0; right: 0;}
.icon-arrow-down{ display: block; width: 24rpx; height: 24rpx;}
.close-box{ width: 40rpx; height: 40rpx; display: flex; justify-content: center; align-items: center;}
.no-graphs{ padding: 30rpx 20rpx; font-size: 24rpx; color: #666;}
.observe-txt{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 26rpx; color: #666;}
.textarea-box2{ padding: 20rpx; width: 100%; height: 300rpx; box-sizing: border-box; background: #f0f0f0; font-size: 26rpx; border-radius: 10rpx;}
.textarea-foot{ padding: 10rpx 10rpx 0 10rpx; display: flex; justify-content: space-between; font-size: 22rpx; color: #777;}
.check-list{ margin: 25rpx 0 10rpx 0; display: flex; justify-content: space-between;}
.check-list-lef{ font-size: 26rpx; color: #333;}
.check-list-rig{ display: flex; font-size: 28rpx; color: #777;}

.theme-list{ display: flex; align-items: center; height: 80rpx; border-bottom: 1rpx dashed #ddd;}
.icon-checkbox{ display: block; width: 40rpx; height: 40rpx;}
.theme-list .v1{ margin: 0 20rpx; width: 300rpx; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 28rpx; font-weight: bold; color: #333;}
.theme-list .v2{ font-size: 26rpx; color: #666;}
.theme-list:last-child{ border-bottom: 0;}

.scroll-box{ margin-top: 20rpx; white-space: nowrap;}
.domain-first,.domain-second-list{ margin-right: 10rpx; padding: 0 30rpx; height: 60rpx; line-height: 60rpx; white-space: nowrap; border-radius: 12rpx; background: rgba(51,169,255, 0.3); font-size: 26rpx; color: #333;}
.domain-first.active,.domain-second-list.active{background: rgba(51,169,255, 1); color: #fff;}
.domain-first{ position: relative; overflow: hidden; display: inline-block;}
.corner-mark{ position: absolute; bottom: 0; right: 0; width: 35rpx; height: 33rpx;}
.domain-second-list{ background: rgba(51,169,255, 0.1);}
.domain-second-list.active{background: rgba(51,169,255, 0.7)}
.domain-second{ margin-top: 30rpx; padding: 20rpx 0 0 0; display: flex; flex-wrap: wrap; border-top: 1px solid #eee;}
.domain-second-list{ margin-bottom: 10rpx;}
.domain-three-item{ margin-top: 20rpx;}
.domain-three-title{ margin-bottom: 20rpx; padding: 0 20rpx; display: flex; justify-content: space-between; align-items: center; height: 70rpx; line-height: 70rpx; border: 1px solid #eee; border-radius: 12rpx;}
.domain-three-title .v1{ font-size: 26rpx; color: #333;}
.domain-three-title .v2{ font-size: 24rpx; color: #999;}
.domain-three-list{ margin-bottom: 20rpx; display: flex;}
.domain-three-list .v1{ margin: 0 10rpx; width: 100rpx; line-height: 40rpx; font-size: 24rpx; color: #666;}
.domain-three-list .v2{ margin-left:20rpx; width: 0; flex: 1; line-height: 36rpx; font-size: 24rpx; color: #666;}
.domain-three-list .v2.active{ color: rgb(0, 0, 99); font-weight: bold;}
.close-box-str{ padding: 40rpx 20rpx; font-size: 26rpx; color: #666; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;}
.package-footer{ margin-top: 20rpx; text-align: center; font-size: 24rpx; color: #999;}
.ones-aline{ margin: 0 15rpx;}

.footer{ display: flex; justify-content: space-evenly;}
.footer .v1,.footer .v2,.footer .v3{ margin: 0 25rpx; flex: 1; height: 80rpx; text-align: center; line-height: 80rpx; font-size: 30rpx; border-radius: 50rpx;}
.footer .v1,.footer .v3{ background: #b1b2b9; color: #fff;}
.footer .v2{ background: #33a9ff; color: #fff;}
.record-footer{ margin-top: 30rpx; padding: 20rpx 0;}
.picker{ text-decoration: underline;}
.student-number{ margin-left: 20rpx; font-weight: 400; font-size: 26rpx; color: #777;}
.up-box{ display: flex; justify-content: center; align-items: center; height: 50rpx; background: #fff; border-radius: 10rpx;}
.up-box .icon-close-black{ width: 28rpx; height: 16rpx;}

.student-list2{ position: relative; min-height: 140rpx;}
.student-list2 .v1{ margin-top: 10rpx; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 20rpx; color: #111;}
.student-photo2{ margin: 0 auto; display: block; width: 100rpx; height: 100rpx; border-radius: 50%;}
.more-box{ width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;}

.scroll-class-box{ margin: 20rpx 0; white-space: nowrap;}
.scroll-class-list{ margin-right: 10rpx; padding: 0 30rpx; display: inline-block; height: 60rpx; line-height: 60rpx; white-space: nowrap; border-radius: 12rpx; background: rgba(25, 178, 255, 0.3); font-size: 26rpx; color: #333;}
.scroll-class-list.active{background: rgba(25, 178, 255, 1); color: #fff;}
.icon-add-txt{ margin-right: 14rpx; width: 45rpx; height: 45rpx; background: #33a9ff; text-align: center; line-height: 45rpx; font-size: 28rpx; color: #fff; border-radius: 50%;}

.only-box{display: flex; justify-content: space-between;}
.mt-20{ margin-top: 20rpx;}
.icon-ai{ display: block; width: 60rpx; height: 60rpx;}
.ai-wrap .v1,.ai-box .v1{ font-size: 20rpx; color: #33a9ff;}
.ai-wrap{ padding-bottom: 8rpx; display: flex; flex-direction: column; justify-content: center; align-items: center; background: #f0f0f0; border-radius: 0 0 10rpx 10rpx;}
.ai-box{ margin-right: 60rpx;}
.icon-add2{ margin-right: 14rpx; display: block; width: 44rpx; height: 45rpx;}

.ai-mask{ position: fixed; z-index: 99; left: 0; bottom:0; width: 750rpx; height: 100vh; background: rgba(0, 0, 0, 0.3);}
.ai-pop{ position: fixed; top: 50%; left: 30rpx; z-index: 100; transform: translateY(-50%); width: 690rpx; min-height: 400rpx; background: #fff; border-radius: 10rpx;}
.ai-pop-cont{ margin: 29rpx 0 0 30rpx; width: 630rpx; height: 300rpx; border-radius: 10rpx;}
.ai-pop-footer{ padding: 20rpx 0; display: flex; justify-content: center;}
.ai-pop-footer .v1,.ai-pop-footer .v2,.ai-pop-footer .v3{ margin: 0 25rpx; flex: 1; height: 60rpx; text-align: center; line-height: 60rpx; font-size: 30rpx; border-radius: 30rpx;}
.ai-pop-footer .v1{ background: #b1b2b9; color: #fff;}
.ai-pop-footer .v2,.ai-pop-footer .v3{ background: #33a9ff; color: #fff;}

个人记录项目使用的 想使用的同学自己扣代码吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1617114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

加速大数据分析:Apache Kylin使用心得与最佳实践详解

Apache Kylin 是一个开源的分布式分析引擎&#xff0c;提供了Hadoop之上的SQL接口和多维分析&#xff08;OLAP&#xff09;能力以支持大规模数据。它擅长处理互联网级别的超大规模数据集&#xff0c;并能够进行亚秒级的查询响应时间。Kylin 的主要使用场景包括大数据分析、交互…

【基础算法】双指针

1.移动零 移动零 思路&#xff1a; 利用双指针算法 cur&#xff1a;从左往右扫描数组&#xff0c;遍历数组 dest&#xff1a;处理好的区间包括dest dest初始化为-1&#xff0c;因为刚开始dest前应该没有非零元素。 即将非零元素移到dest之前即可 class Solution { public…

BFS解决FloodFill算法:(Leetcode:733. 图像渲染)

题目链接&#xff1a;733. 图像渲染 - 力扣&#xff08;LeetCode&#xff09; 使用广度优先遍历算法解决该问题&#xff1a; 从初始位置开始搜索&#xff0c;初始位置符合条件就入栈&#xff0c;并修改初始位置值。初始位置出栈。 再从初始位置开始广度优先搜索&#xff08;…

【机器学习300问】78、都有哪些神经网络的初始化参数方法?

在训练神经网络时&#xff0c;权重初始化是确保良好收敛的关键步骤之一。不合适的初始化方法可能会导致梯度消失或爆炸&#xff0c;特别是在深层网络中。那么都有哪些神经网络的初始化参数方法呢&#xff1f;选择它这些方法的原则是什么&#xff1f; 一、常用神经网络初始化参…

Kubernetes(k8s)的概念以及使用

k8s的概念&#xff1a; K8s是指Kubernetes&#xff0c;是一个开源的容器编排和管理平台。它最初由Google开发&#xff0c;并于2014年将其开源。Kubernetes旨在简化容器化应用程序的部署、扩展和管理。 Kubernetes提供了一种可靠且可扩展的平台&#xff0c;用于管理容器化应用…

怎样才能迅速了解一个产品的业务流程?

很多小伙伴经常问我&#xff0c;刚进入一家新的企业&#xff0c;想要快速了解产品的业务流程&#xff0c;不知从何下手。主要是因为&#xff0c;有的企业根本没有文档可看&#xff1b;还有的企业有文档&#xff0c;但是记录的比较凌乱&#xff0c;想要从中找出点头绪来&#xf…

【Python-装饰器】

Python-装饰器 ■ 简介■ 装饰器的一般写法&#xff08;闭包写法&#xff09;■ 装饰器的语法 (outer写法) ■ 简介 装饰器其实是一种闭包&#xff0c; 功能就是在不破坏目标函数原有的代码和功能的前提下为目标函数增加新功能。 ■ 装饰器的一般写法&#xff08;闭包写法&am…

2024年前端技术发展趋势

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

程客有话说05 | 吕时有:在GIS行业深耕13年,做梦做出来了数学竞赛题,这是让我最开心的事

《程客有话说》是我们最新推出的一个访谈栏目&#xff0c;邀请了一些国内外有趣的程序员来分享他们的经验、观点与成长故事&#xff0c;我们尝试建立一个程序员交流与学习的平台&#xff0c;也欢迎大家推荐朋友或自己来参加我们的节目&#xff0c;一起加油。 本期我们邀请的程…

使用Docker搭建本地Nexus私有仓库

0-1开始Java语言编程之路 一、Ubuntu下Java语言环境搭建 二、Ubuntu下Docker环境安装 三、使用Docker搭建本地Nexus Maven私有仓库 四、Ubuntu下使用VisualStudioCode进行Java开发 你需要Nexus Java应用编译构建的一种主流方式就是通过Maven, Maven可以很方便的管理Java应用的…

网盘兼职真的能月入过万吗?你适合做哪种网盘分享牛?

1. 分享大容量文件&#xff1a; 提供常见软件安装包、系统镜像、游戏资源等常用的大容量文件&#xff0c;以满足用户的需求。 创建分类目录&#xff0c;便于用户浏览和查找所需文件。 编写详细的文件描述&#xff0c;包括文件版本、适用系统、安装方法等信息&#xff0c;帮助用…

Promise.all 的方法还没执行完就执行了.then

碰见一个问题&#xff0c;接盘了一个有问题的页面修改。 改变日期后 查询很多数据再去重新加载页面上的数据显示相关的组件。 问题就来了。 加载异常捏…… 最后我一通查&#xff1a; 重点来了 是因为这个Promise.all(数组)&#xff0c;里边这个数组的问题。现在是在数据中…

XYCTF 部分wp及学习记录

1.ezmd5 根据题目提示 我们知道应该是要上传两张md5值相同的图片 根据原文链接&#xff1a;cryptanalysis - Are there two known strings which have the same MD5 hash value? - Cryptography Stack Exchange 把保存下来的图片上传一下 得到flag 2.ezhttp 根据原文链接&…

STM32H7的LCD控制学习和应用

STM32H7的LCD控制 LTDC基础硬件框图LTDC时钟源选择LTDC的时序配置LTDC背景层、图层1、图层2和Alpha混合LTDC的水平消隐和垂直消隐LCD的DE同步模式和HV同步模式的区别区分FPS帧率和刷新率避免LTDC刷新撕裂感的解决方法 驱动示例分配栈的大小MPU和Cache配置初始化SDRAM初始化LCD应…

鸿蒙 harmonyos 线程 并发 总结 async promise Taskpool woker(三)多线程并发 Worker

Worker Worker是与主线程并行的独立线程。创建Worker的线程称之为宿主线程&#xff0c;Worker自身的线程称之为Worker线程。创建Worker传入的url文件在Worker线程中执行&#xff0c;可以处理耗时操作但不可以直接操作UI。 Worker主要作用是为应用程序提供一个多线程的运行环境…

办公设备租赁行业内卷瞎扯

办公设备租赁行业内卷瞎扯 最近听到很多同行抱怨&#xff0c;现在市场太卷了&#xff0c;真的有点到了卷不死就往死里卷的节奏&#xff0c;让大家都开始想换地方&#xff0c;或者转行。但是今天&#xff0c;我想从另外一个角度聊一下这个问题&#xff0c;分析一下&#xff0c;…

苍穹外卖day9 (1)用户端历史订单

文章目录 前言用户端历史订单1. 查询历史订单1.1 业务规则1.2 接口设计1.3 代码实现 2. 查询历史订单详情2.1 接口设计2.2 代码实现 3. 取消订单3.1 业务规则3.2 接口设计3.3 代码设计 4. 再来一单4.1 业务规则4.2 接口设计4.3 代码实现 前言 用户端对历史订单的操作&#xff…

机器人系统开发ros2-基础学习16-使用 rosdep 管理依赖关系

1. what is rosdep? rosdep是一个依赖管理实用程序&#xff0c;可以与包和外部库一起使用。它是一个命令行实用程序&#xff0c;用于识别和安装依赖项以构建或安装包。 其本身rosdep并不是一个包管理器&#xff1b;它是一个元包管理器&#xff0c;它使用自己的系统知识和依赖…

Day10案例分页查询,条件查询

对要求进行逻辑分析,传递固定参数{page,pagesize}任意参数{name,gender,begin,end},返回总记录数以及当前页码的记录 不使用pagehelper插件,首先完成SQL语句 SQL语句 //固定头 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLI…

SQL-DML数据操纵语言(Oracle)

文章目录 DML数据操纵语言常见的字段属性字符型字段属性char(n)varchar2(n)/varchar(n) 数值型字段属性number([p],[s]int 日期型字段属性DATEtimestamp 如何查看字段属性增加数据INSERT快捷插入 删除数据DELETE修改数据UPDATE DML数据操纵语言 定义 是针对数据做处理&#xf…