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

<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:是否正在播放     //录音部分-startparentIndex: 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, //点击的地方到顶部的距离//录音部分-endactivityId: 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: '', //编辑观察记录的idlistSelect: [], //指标列表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: [], //观察记录顶部tabsceneChecked: '', //观察场景选中对象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) returnapp.globalData.isActivityMaterials = false //重置记观察记录的上传状态lock = false;const userInfo = wx.getStorageSync('userInfo');//判断roles是不是'sch'判断当前用户是不是'园长' 如果roles是senior_teacher那么该角色和园长拥有相同'观察评价'权限 统计里也要和园长一样 也就是'观察记录'、'观察统计'  混龄账号目前不可能是超级老师 2024-04-16let isAdmin = falselet isSeniorTeacher = falselet isTeacherDirector = falseif(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({// 模拟httpsurl: 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).urllet pidx = that.data.parentIndexlet 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.activityMaterialsoarr.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 = thisconst {frameBuffer,isLastFrame} = reslet 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 = 0if (this.data.firstSend) {this.data.firstSend = false} else {if (isLastFrame) {status = 2} else {status = 1}}params.data.status = statuswx.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: '', //编辑观察记录的idlistSelect: [], //指标列表      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 : '', //判断是不是从报告页面跳转过来 如果是则赋值idmeasure: '',classData: [],classCheckedId: '', //选中的classId 如果是管理员的时候 默认选中第一个 非管理员不调用activityId: null,//选择幼儿-start        checkedStudents: [],checkedStudentsTreated: [],students: [],studentArr: [],themeChecked: {},//选择幼儿-end//观察背景-startselectedDate: getDayDate(), //记录日期observeParentIndex: 0,observeChildIndex: 0,observe: '',observeNumber: 0,//观察背景-end              activityMaterials: [{content: '',material: []}],typeList: [], //观察记录顶部tabsceneChecked: '', //观察场景选中对象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.studentslet 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.observeSceneListlet observeParentIndex = 0let observeChildIndex = 0if (observeSceneList.length > 0) {for (let i in observeSceneList) {if (observeSceneList[i].expenseId == observeIndex[0]) {observeParentIndex = ibreak}}for (let i in observeSceneList[observeParentIndex].children) {if (observeSceneList[observeParentIndex].children[i].expenseId == observeIndex[1]) {observeChildIndex = ibreak}}}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.evaluationItemsfor (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 = thiswx.showModal({title: '',content: '是否清空当前页面数据',success(res) {if (res.confirm) {that.resetObserve()} else if (res.cancel) {//console.log('用户点击取消')}}})},//删除观察deleteObserve() {const that = thiswx.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.statusif (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) returnlock = 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.observeSceneListlet observeParentIndex = this.data.observeParentIndexlet observeChildIndex = this.data.observeChildIndexlet 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.oidrequestStyle = '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 = thislet isSuccess = falsewx.requestSubscribeMessage({tmplIds: ['hGQUXKwyQtenWhFPnKvGcZk1mq-hdjxOPSvh_5FT46w'],success(res) {if (result == 'suc') {isSuccess = truethat.setData({oid: '',studentArr: [],activityId: null,checkedStudentsTreated: []})app.globalData.isActivityMaterials = false //阻止调用onshowwx.switchTab({url: '/pages/report/report',});lock = falsewx.hideLoading();} else {wx.showToast({title: ores.msg,icon: 'error',duration: 2000})app.globalData.isActivityMaterials = falselock = falsewx.hideLoading();}},complete() {//如果调用成功 则不用调用第二遍 complete是必调用的 所以拦住省得第二次触发if (isSuccess) returnapp.globalData.isActivityMaterials = false //阻止调用onshowwx.switchTab({url: '/pages/report/report',});lock = falsewx.hideLoading();},})},saveHandle() {if (editType == 0) { //添加wx.switchTab({url: '/pages/activityn/activityn',})} else { //修改wx.navigateBack({delta: 1});}lock = falsewx.hideLoading();},tabHandle(e) {//清掉幼儿发展水平评估的选中状态let oindex = e.currentTarget.dataset.idxthis.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、子集indexgetIndex() {const that = thislet observeSceneList = this.data.observeSceneListobserveSceneList.forEach(function (item, index) {//ly-edit 2023-09-15 非编辑状态添加默认的子级 如果是编辑状态就重新赋值let sceneChecked = that.data.sceneCheckedif (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.valuethis.setData({selectedDate: oval});},//指向主题活动加载更多loadMoreActivity() {if (this.data.flag) returnthis.getListSelectActivity();},//指向主题活动选中某一个元素checkActivityHandle(e) {let otheme = this.data.activityListlet oidx = e.currentTarget.dataset.idxlet obj = otheme[oidx]//重置选中状态otheme = otheme.map(item => {item.checked = false;return item;});otheme[oidx].checked = truelet 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.schoolIdutil.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.rowslet 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 = truelet themeStr = newDataList[i].name + (newDataList[i].status == '1' ? '整理' : '计划') + newDataList[i].monthWeekthis.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.evaluationItemsfor (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.parentindexlet childindex = e.currentTarget.dataset.childindexlet oitem = e.currentTarget.dataset.itemlet evaluationItems = this.data.evaluationItemslet threeData = this.data.threeData//思路:点击的时候 判断当前checked是否为true 如果是true则改为false 如果是false通过父级index 把父级下标下所有的checked改为false 在子级下标对应的那个值改为true//1、判断点击的元素 checked是否为truelet activeList = ''if (this.data.showAreaSecond) {activeList = threeData.children[parentIndex].children[childindex] //选中的元素      } else {activeList = threeData[parentIndex].children[childindex] //选中的元素      }if (activeList.checked) { //重置 如果是true改为falsefor (let i in evaluationItems) { //删除相同id的itemif (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 = falseif (this.data.showAreaSecond) {hasCornerMark = this.findCheckedItem(threeData.children)} else {hasCornerMark = this.findCheckedItem(threeData)}let selectArea = this.data.selectAreaselectArea[this.data.areaFirstIndex].checked = hasCornerMark//console.log(evaluationItems)this.setData({threeData,selectArea})},//查找多层级数组中是否带有checked为true的属性并返回findCheckedItem(arr) {const that = thisfor (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.listSelectif (this.data.showAreaSecond) {//需要加childrenlet 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.indexthis.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.datalet 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.idlet index = e.currentTarget.dataset.indexthis.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.datalet 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.selectedDatelet observeSceneList = this.data.observeSceneListlet observeParentIndex = this.data.observeParentIndexlet observeChildIndex = this.data.observeChildIndexlet 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.idxlet arr = this.data.studentsarr[idx].checked = arr[idx].checked == true ? false : truelet 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.checkedStudentsTreatedthis.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-09this.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.activityMaterialsactivityMaterials[this.data.parentIndex].recordState = falsethis.setData({activityMaterials: activityMaterials})},addListHandle() {let obj = this.data.activityMaterialsobj.push({content: '',material: []})this.setData({activityMaterials: obj})},textareaBlurHandle(e) {let oval = e.detail.valuelet obj = this.data.activityMaterialslet idx = e.currentTarget.dataset.idxobj[idx].content = ovalthis.setData({activityMaterials: obj})},preview(e) {let currentUrl = e.currentTarget.dataset.srclet pidx = e.currentTarget.dataset.pidx //父级循环的indexconst 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 = thiswx.showModal({title: '',content: '是否删除素材',success(res) {if (res.confirm) {let obj = that.data.activityMaterialslet pidx = e.currentTarget.dataset.pidx //父级循环的indexlet idx = e.currentTarget.dataset.idx //子级循环的indexobj[pidx].material.splice(idx, 1)that.setData({activityMaterials: obj})} else if (res.cancel) {//console.log('用户点击取消')}}})},//上传图片、视频uploadFile: function (e) {//如果不添加这个判断 则在这里会默认调用onshowapp.globalData.isActivityMaterials = true //阻止调用onshowconst that = thislet obj = this.data.activityMaterialslet pidx = e.currentTarget.dataset.idxwx.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 = thiswx.showModal({title: '',content: '是否删除',success(res) {if (res.confirm) {let obj = that.data.activityMaterialslet idx = e.currentTarget.dataset.idx //子级循环的indexobj.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.resultif (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.activityMaterialslet parentIndex = e.currentTarget.dataset.idxthis.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 = truethis.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 = falsethis.setData({activityMaterials: oactivityMaterials})recorderManager.stop();}},//播放操作playHandle(e) {const that = thislet idx = e.currentTarget.dataset.idxlet pidx = e.currentTarget.dataset.pidx//recordArr的字段有url/txt/time/played/showTxt: false,//语音的文字部分是否展示showTip: false,//Tooltip 文字提示是否展示directionUp: false,//Tooltip的方向是向上还是向下    let activityMaterials = this.data.activityMaterialslet orecordArr = activityMaterials[pidx].recordArr[idx]innerAudioContext.src = orecordArr.urlif (!orecordArr.played) {//查找兄弟节点 把所有的played状态改成falsefor (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 = trueinnerAudioContext.play() // 播放      innerAudioContext.onEnded(() => {//console.log('语音播放结束');     orecordArr.played = falsethat.setData({activityMaterials: activityMaterials})});} else {//关闭orecordArr.played = falseinnerAudioContext.stop() // 停止}this.setData({activityMaterials: activityMaterials})},onLongPress(e) {//console.log(e)//const listItem = e.currentTarget;let activityMaterials = this.data.activityMaterialslet 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 = truethis.setData({activityMaterials: activityMaterials,maskShow: true})},txtRecordHandle(e) {let activityMaterials = this.data.activityMaterialslet pidx = e.currentTarget.dataset.pidx //父级下标let idx = e.currentTarget.dataset.idx //子级下标activityMaterials[pidx].recordArr[idx].showTxt = trueactivityMaterials[pidx].recordArr[idx].showTip = falsethis.setData({activityMaterials: activityMaterials})},delRecordHandle(e) {let activityMaterials = this.data.activityMaterialslet 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.activityMaterialslet parentIndex = e ? e.currentTarget.dataset.idx : this.data.aiParentIndexlet params = {docstyle: 3, //如果观察记录有值输入3 没值输入1content: {'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.observelet params = {docstyle: !observe ? 1 : 2, //如果目的有值输入2 没值输入1content: {'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.observelet level1 = this.data.observeSceneList[this.data.observeParentIndex].expenseItemlet level2 = this.data.childArray[this.data.observeChildIndex].expenseItemlet 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) returnutil.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.aiPolishlet 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.activityMaterialslet parentIndex = this.data.aiParentIndexlet otxt = this.data.aiPolishlet value = (oactivityMaterials[parentIndex].content + otxt).replace(/\n\s*/g, '\n'); // 获取输入的文本内容if (value.length > 500) {value = value.slice(0, 500);}oactivityMaterials[parentIndex].aiKeyword = oactivityMaterials[parentIndex].contentoactivityMaterials[parentIndex].content = valueoactivityMaterials[parentIndex].recordAiPolish = otxtthis.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.mzph.cn/pingmian/2387.shtml

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

相关文章

S-Edge网关:柔性部署,让物联网接入更统一

S-Edge网关是什么&#xff1f; 网关是在实际物理世界与虚拟网络世界相连接的交叉点&#xff0c;为了让这个交叉点尽可能的复用&#xff0c;无需每种设备都配套一种连接方式&#xff0c;边缘网关主要就是用于传感器等物理设备与网络实现数据交互的通用设备&#xff0c;也称为物…

贪心算法-活动安排问题和背包问题

实验6贪心算法-活动安排问题和背包问题 实验目的&#xff1a; 理解贪心算法的基本思想运用贪心算法解决实际问题 实验内容&#xff1a; 采用贪心方法编程实现以下问题的算法 1.如何安排下列活动使得使用的活动场所最少&#xff0c;并给出具体的安排方法。 活动 a b c …

Leetcode算法训练日记 | day34

专题九 贪心算法 一、K次取反后最大化的数组和 1.题目 Leetcode&#xff1a;第 1005 题 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数组&#xff1a; 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。 重复这个过程恰好 k 次。可以多次选择同一个…

【大语言模型LLM】- Meta开源推出的新一代大语言模型 Llama 3

&#x1f525;博客主页&#xff1a;西瓜WiFi &#x1f3a5;系列专栏&#xff1a;《大语言模型》 很多非常有趣的模型&#xff0c;值得收藏&#xff0c;满足大家的收集癖&#xff01; 如果觉得有用&#xff0c;请三连&#x1f44d;⭐❤️&#xff0c;谢谢&#xff01; 长期不…

git常见命令(成长版)

ps&#xff1a;所谓成长版就是后续可能还会添加命令&#xff1a; 1.删除本地分支&#xff1a; git branch -d 分支名 2.拉取代码后默认master分支&#xff0c;切换到线上其他分支&#xff1a; &#xff08;1&#xff09;查看线上所有分支&#xff1a; git branch -a &#…

【STM32+HAL+Proteus】系列学习教程4---GPIO输入模式(独立按键)

实现目标 1、掌握GPIO 输入模式控制 2、学会STM32CubeMX配置GPIO的输入模式 3、具体目标&#xff1a;1、按键K1按下&#xff0c;LED1点亮&#xff1b;2、按键K2按下&#xff0c;LED1熄灭&#xff1b;2、按键K3按下&#xff0c;LED2状态取反&#xff1b; 一、STM32 GPIO 输入…

基于小程序实现的查寝打卡系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

[Algorithm][前缀和][模板 一维前缀和][模板 二维前缀和][寻找数组中心下标][除自身以外数组的乘积] + 前缀和原理 + 前缀和模板

目录 0.原理讲解1.[模板]一维前缀和1.题目链接2.模板代码实现 2.[模板]二维前缀和1.题目链接2.算法原理讲解3.模板代码实现 3.寻找数组的中心下标1.题目链接2.算法原理详解3.代码实现 4.除自身以外数组的乘积1.题目链接2.算法原理详解3.代码实现 0.原理讲解 前缀和&#xff1a;…

Docker学习(二十五)构建 Arthas 基础镜像

目录 一、简介二、构建基础镜像2.1 下载 Arthas2.2 编写 Dockerfile2.3 构建镜像2.4 创建容器2.5 测试 一、简介 Arthas 是一款由 阿里巴巴 开发的 线上监控诊断工具。通过全局视角实时查看应用负载、内存、GC、线程等信息&#xff0c;能在不修改代码的情况下&#xff0c;对业…

Pytorch常用的函数(八)常见优化器SGD,Adagrad,RMSprop,Adam,AdamW总结

Pytorch常用的函数(八)常见优化器SGD,Adagrad,RMSprop,Adam,AdamW总结 在深度学习中&#xff0c;优化器的目标是通过调整模型的参数&#xff0c;最小化&#xff08;或最大化&#xff09;一个损失函数。 优化器使用梯度下降等迭代方法来更新模型的参数&#xff0c;以使损失函数…

【QT进阶】Qt http编程之实现websocket server服务器端

往期回顾 【QT进阶】Qt http编程之json解析的简单介绍-CSDN博客 【QT进阶】Qt http编程之nlohmann json库使用的简单介绍-CSDN博客 【QT进阶】Qt http编程之websocket的简单介绍-CSDN博客 【QT进阶】Qt http编程之实现websocket server服务器端 一、最终效果 通过ip地址和端口…

人工智能时代的关键技术:深入探索向量数据库及其在AI中的应用

文章目录 1. 理解向量数据库&#xff1a;二维模型示例2. 向量数据库中的数据存储与检索3. 向量数据库如何工作&#xff1f;4. 向量数据库如何知道哪些向量相似&#xff1f; 在人工智能技术日益成熟的当下&#xff0c;向量数据库作为处理和检索高维数据的关键工具&#xff0c;对…

Dropout Feature Ranking for Deep Learning Models

摘要 深度神经网络( deep neural networks&#xff0c;DNNs )在多个领域取得了最新的研究成果。不幸的是&#xff0c;DNNs因其不可解释性而臭名昭著&#xff0c;从而限制了其在生物和医疗保健等假说驱动领域的适用性。此外&#xff0c;在资源受限的环境下&#xff0c;设计依赖…

Linux下的UDEV机制/守护进程

一. Udev机制概念引入 ( 需要在 etc/udev/rules.d/ 下创建设备的相关规则&#xff0c;不然有可能udev机制生成的设备文件不具备可读可写的权限&#xff0c;adb无法成功通过该设备文件访问设备 ) a. 创建文件夹 sudo vim Xiaomi-audroid.rules b. 添加规则 …

在vscode上面进行分支merge的记录

前言&#xff1a;在我们的项目中&#xff0c;有两个分支&#xff1a;master和liutielong。现在要将liutielong分支的改动merge到master分支中。 如果master分支已经更改了&#xff0c;所以要先pull&#xff08;这是在git bash里面的命令&#xff09;。 git pull origin master…

5分钟——快速搭建后端springboot项目

5分钟——快速搭建后端springboot项目 1. idea新建工程2. 构建pom.xml文件3. 构建application.yml配置文件4. 构建springboot启动类5. 补充增删改查代码6. 运行代码 1. idea新建工程 点击右上角新建一个代码工程 别的地方不太一样也不用太担心&#xff0c;先创建一个工程就好…

学习配置文件

1.yml的语法格式问题&#xff1a; 2.配置文件获取数据&#xff1a; Value方式&#xff1a; Environment&#xff1a; 获取自定义对象的方式&#xff1a; 设置get和set方法&#xff0c;还有toString方法。 3. 日志配置&#xff1a; logo的配置&#xff1a; 日志插件&#xff…

汽车纵染压制专用液压机比例阀放大器

汽车纵染压制专用液压机比例阀放大器是一种专门用于汽车纵梁拉伸工艺的设备&#xff0c;它也可以用于其他金属薄板的压制成型及校正工艺。该类型的液压机通常具备独立的动力机构和电气系统&#xff0c;采用PLC技术进行控制&#xff0c;以确保操作的准确性和稳定性。除了纵梁拉伸…

【iOS】分类,扩展与关联对象

文章目录 前言一、分类实现原理二、分类加载流程三、扩展四、类别与类扩展的区别五、关联对象动态添加取值移除关联对象应用 总结 前言 上一篇章我们探究了类与对象的底层&#xff0c;这一篇我们探究一下分类&#xff0c;扩展与关联对象 一、分类实现原理 首先我们知道扩展是…

CentOS-7安装grafana

一、通用设置&#xff08;分别在4台虚拟机设置&#xff09; 1、配置主机名 hostnamectl set-hostname --static 主机名2、修改hosts文件 vim /etc/hosts 输入&#xff1a; 192.168.15.129 master 192.168.15.133 node1 192.168.15.134 node2 192.168.15.136 node33、 保持服…