<template>
	<view class="p-home-chat g_w_all g_bg_f_5">
		<view class="chat-content g_clear_scroll">
			<scroll-view :scroll-y="true" :scroll-top="stesttest"  :scroll-with-animation="true"
				:style="{
					height: wh,
				}"
				:upper-threshold="200" @scrolltoupper ='getMore' @scroll="getScrollInfo"
			>
				<view class="g_flex_row_center g_fs_12 g_pt_12 g_pb_12 obj_1" v-show="list && list.length >= 10"
						style="color: #b3b7bc;"	
					>
				{{ isFinish == 1 ? "查看更多" : "已全部加载" }}
				</view>
				<view style="padding-top: 12px" class="chatBox obj_2">
					<view class="g_mb_16 chat-item" 
								v-for="(item, index) in list" :key="index"
								:class="item.robotTag == 1 ? '' : (item.robotTag == 0 ? 'g_flex_row_end' : 'g_flex_row_center')" 
								:id="'id_' + item.id"
					>
						<view class="m-item chat-left g_flex_row_start" v-if="item.robotTag == 1">
							<view>
								<view v-if="index + 1 == list.length && index > 0 && isShowLeftLoading" class="left_animate g_flex_row_start">
									<view class="g_flex_row_start g_bg_f g_pl_16 g_pr_16 g_pt_10 g_pb_10"
										style="border-radius: 12px;"
									>
										<view class="g_c_6 g_flex_column_center" style="font-size: 17px;" v-if="leftAnimate1">
											搜索中
										</view>
										<view class="g_c_6 g_flex_column_center" style="font-size: 17px;" v-if="leftAnimate2">
											已搜索{{jobnum}}个职位
										</view>
										<view class="g_c_6 g_flex_column_center" style="font-size: 17px;" v-if="leftAnimate3">
											智能匹配中
										</view>
										<view class="g_flex_column_center" hover-class="none" hover-stop-propagation="false"
												  style="height: 25px;"
													v-if="!leftAnimate2"
										>
											<view class="loader">
												<text class="dot"></text>
												<text class="dot"></text>
												<text class="dot"></text>
											</view>
										</view>
									</view>
								</view>
								<view v-else>
									<view class="msg  g_c_0 left" 
												:class="item.chat_type == 'markdown' ? '' : (item.chat_type ? 'g_bg_f g_pl_10 g_pr_10 g_pt_10 g_pb_10' : '')"
												@longpress="handleLongPress(item)"
												:style="{
													'max-width':item.chat_type == 'text' ? (index == 0 && item.messageType == 98 && !helloText ? 'calc(100vw - 20px)' : '80vw') : 'calc(100vw - 20px)',
													'min-width': item.chat_type == 'text' ? 'auto' : 'calc(100vw - 20px)',
												}"
									>
										<view v-if="gptType == 'ai' || gptType == 'ai-text'">


												<view class="" v-if="item.chat_type == 'text' && index == 0 && item.messageType == 98">
													<g-chat-gree v-if="!helloText" />
													<view v-if="helloText" style="font-size: 17px;">
														你好，我是{{ helloText }}机器人
													</view>
												</view>
												<view class="" v-if="item.chat_type == 'text' && index == 0 && item.messageType != 98">
													<g-chat-message :cusMessage="item.msg" :isRender="0" />
												</view>
											

												<view class="" v-if="item.chat_type == 'text' && index > 0">
													<g-chat-message :cusMessage="item.msg" v-if="index > 0" :isRender="isRender && index == list.length - 1 ? 1 : 0" />
												</view>

												<view class="" v-if="item.chat_type == 'markdown'">
													<g-chat-markdown :cusList="item.comList"
														:isbor="item.isRecordJobEnd ? 1 : 0"
														@exportMore.stop="goHotMore(item)"
													/>
													<div v-if="item.isRecordJobEnd">
														<view class="markgroup g_bg_f">
															<div class="g_flex_row_between g_h_all" 
																	 style="margin: 0 10px;border-top: 1px solid #eee;width: calc(100% - 20px);">
																<div class="g_flex_row_start"  @click.stop="getReload(item)" style="width: 50%;">
																	<div class="g_flex_column_center g_pl_6 g_mr_4"
																	>
																		<i class="iconfont icon-sync" style="color: #666666;font-size: 12px;position: relative;top: 1px;"></i>
																	</div>
																	<div class="g_flex_column_center" style="color: #666666;font-size: 14px;">换一批</div>
																</div>
																<div class="g_flex_row_end" @click.stop="goHotMore(item)" style="width: 50%;">
																	<div class="g_flex_column_center" style="color: #666666;font-size: 14px;">查看更多</div>
																	<div class="g_flex_column_center g_pr_6 g_ml_4">
																		<i class="iconfont icon-gengduo11" style="color: #666666;font-size: 12px;"></i>
																	</div>
																</div>
															</div>
														</view>
														<view class="g_h_16" v-if="index == list.length - 1"></view>
													</div>
												</view>
										</view>
									</view>
								</view>
								<view class="g_h_16" v-if="index == list.length - 1"></view>
							</view>
						</view>

						<view class="m-time g_text_c g_fs_12" v-else-if="item.robotTag == 2" 
							style="color: #b3b7bc;"	
						>
							{{ formatMessageTime(item.message) }} 
						</view>

						<view class="m-item chat-right" v-else style="max-width: 80vw">
							<view class="msg g_bg_mais g_c_f g_fs_17 g_pl_16 g_pr_16 g_pt_10 g_pb_10" 
										@longpress="handleLongPress(item)" style="min-height: 25px;"
										v-if="!item.isHidden"
							>
								<g-chat-message :cusMessage="item.msg" style="max-width: 80%" v-if="item.msg" :data-msg='item.msg' />
								
								<view v-if="index == (list.length - 1) && isShowRightLoading && !item.msg" class="right_animate g_flex_row_end g_mr_10 obj_4">
									<view class="g_flex_row_end" style="border-radius: 12px;">
										<view class="g_c_f g_flex_column_center" style="font-size: 17px;margin-right: 4px;" v-if="rightAnimate1">
											识别中
										</view>
										<view class="g_c_f g_flex_column_center" style="font-size: 17px;margin-right: 4px;" v-if="rightAnimate2">
											转写中
										</view>
										<view class="g_flex_column_center" style="height: 25px;">
											<view class="loades">
												<text class="dos"></text>
												<text class="dos"></text>
												<text class="dos"></text>
											</view>
										</view>
									</view>
								</view>
							</view>
							<view class="g_h_16" v-if="index == list.length - 1"></view>
						</view>
					</view>
				</view>
			</scroll-view>
		</view>
		<view class="chat-operate g_flex_c g_bg_f_5" :style="writeStyle"
		      :class="hasSafeArea ? 'optrue' : 'opfalse'"
		>
			<view class="g_bg_f m-input g_flex_row_center g_position_rela"
				:class="hasTopPadding && msgType == 'text' ? 'hasTopPadding' : ''" :style="{
					height: msgType == 'voice' ? '56px' : `${textareaHeight + 16}px`,
					maxHeight: '240px',
					overflow: 'auto',
				}" style="align-items: flex-end; min-height: 56px">
				<!-- 左侧 -->
				<view class="g_flex_none g_flex_c g_h_56 g_w_56 g_posi_relative" @click.stop="handleUpdateMsgType()"
					:class="voiceStatus == 0 && spec ? 'g_bg_mais' : voiceStatus == 1 ? 'g_bg_f0a' : voiceStatus == -2 ? 'g_c_t g_bg_mais' : ''"
					style="border-radius: 40px 0px 0px 40px;position: relative;" v-if="gptType != 'ai-text'">
					<i class="iconfont"
						:class="msgType == 'text' ? 'icon-huatongyuyin  g_fs_22' : 'icon-weixinjianpan2  g_fs_26'"
						style="position: absolute;"
						:style="{
							'left':msgType == 'text' ? '19px' :'17px',
							'top':msgType == 'text' ? '17px' :'15px'
						}"
						v-if="voiceStatus == -1"></i>
				</view>
				<!-- 中部 -->
				<view class="g_flex_1 g_flex_column_end">
					<view v-if="msgType == 'text'" class="m-input-point g_w_all g_h_56 g_flex_column_center">
						<div class="container g_flex_column_center g_h_32" ref="container">
							<input  cursor-spacing="50" class="g_fs_17 g_c_0"
								:class="hasTopPadding ? 'g_mt_0' : ''" id="textarea" placeholder="请输入内容"
								placeholder-class="mplace"
								v-model="sendMsg"
								style="position: absolute; width: calc(100vw - 140px); top: 50%; transform: translateY(-50%); padding: 0 0 0 0px;height: 32px;line-height: 32px;"
								@input="onInput" @focus="onFocus" @blur="onBlur"
								:adjust-position="isIosWxapp ? false : true"
								@keyboardheightchange="keyboardheightchange" @linechange="linechange" />
						</div>
					</view>
					<view v-else>
						<view v-if="voiceStatus == 0"
								 class="voice-tip g_flex_c"
								 style="color: #666666;
												font-size: 12px;
												position: fixed;
												left: 50%;
												transform: translateX(-50%);
												bottom: 104px;
												width: 100vw;
												height: 30px;
												background-color: rgba(237,237,237,1);
								 "
						>
							松手发送，上移取消
						</view>
						<view v-if="voiceStatus == 1"
								 class="voice-tip g_flex_c"
								 style="color: #fe0000;
												font-size: 12px;
												position: fixed;
												left: 50%;
												transform: translateX(-50%);
												bottom: 104px;
												width: 100vw;
												height: 30px;
												background-color: rgba(237,237,237,1);
								 "
						>
							松手取消
						</view>
						<view class="g_w_all g_h_56 m-voice-point g_flex_c g_fw_700 g_fs_17"
							@touchstart="onTouchStart" @touchend="onTouchEnd" @touchmove="onTouchMove"
							:class="voiceStatus == 1 ? 'g_c_f g_bg_f0a' : voiceStatus == 0 ? 'g_bg_mais' : voiceStatus == -2 ? 'g_bg_mais' : ''">
							{{ voiceStatus == 1 ? "" : voiceStatus == -1 ? "按住 说话" : "" }}
						</view>
					</view>
				</view>
				<!-- 发送 -->
				<view class="g_flex_none g_flex_c g_h_56 g_w_56 g_position_rela" @click.stop="handleSendMsg"
					:class="voiceStatus == 0 && spec ? 'g_bg_mais' : voiceStatus == 1 ? 'g_bg_f0a' : voiceStatus == -2 ? 'g_c_t g_bg_mais' : ''"
					style="border-radius: 0 40px 40px 0;position: relative;">
					<i class="iconfont icon-fasong g_fs_32"
						:class="sendIconStatus ? '' : voiceStatus == -2 ? 'g_c_t g_bg_mais' : 'g_c_b'"
						:style="sendIconStatus ? {color: themeColor} : {}"
						style="position: absolute;right: 13px;top: 12px;"
						v-if="voiceStatus == -1"></i>
				</view>

				<!-- 清屏 -->
				<i class="iconfont icon-close-circle g_fs_26 g_c_9"
					style="position: absolute; right: 22px; top: 50%; transform: translateY(-80%)"
					v-if="textareaHeight > 80 && msgType == 'text'" @click.stop="clearMsg"></i>

				<!-- 录音交互动画 -->
				<view class="longpress-mask" :data-status="voiceStatus" @touchend="onTouchEnd">
					<view class="longpress-top-mask g_h_56 g_flex_c"
						style="bottom: 47px"
						v-if="voiceStatus == 0 || voiceStatus == 1 || voiceStatus == -2">
						<div class="column-voice g_flex_row_center">
							<div v-for="(item, index) in 20" :key="index" class="g_flex_column_center">
								<div class="column-item g_bg_f" :style="{
										animation: 'voi_animate 1.5s infinite ' + 0.1 * index + 's',
										'-webkit-animation': 'voi_animate 1.5s infinite ' + 0.1 * index + 's',
									}"></div>
							</div>
						</div>
					</view>
				</view>
			</view>
			<view style="font-size: 12px; color: #999999;position: absolute;left: 50%;transform: translateX(-50%);top: 72px;">
				内容由AI生成，仅供参考
			</view>
		</view>


		<!-- <view class="g_w_50 g_h_50 g_flex_c" 
		  style="position: fixed;right: 20px;bottom: 140px;border-radius: 50%;background-color: red;"
			@click="delAll"
		>
			<i class="iconfont icon-clear g_c_f" style="font-size: 20px;"></i>
		</view> -->

		<gao-ChatSSEClient
			ref="chatSSEClientRef"
			@onOpen="openCore"
			@onError="errorCore"
			@onMessage="messageCore"
			@onFinish="finishCore"
		/>
	</view>
</template>
<!-- #ifdef APP -->
<script module="yourModuleName" lang="renderjs">
	//此模块内部只能用选项式API风格，vue2、vue3均可用，请照抄这段代码；不可改成setup组合式API风格，否则可能不能import vue导致编译失败
	/**需要编译成App时，你需要添加一个renderjs模块，然后一模一样的import上面那些js（微信的js除外）
	    ，因为App中默认是在renderjs（WebView）中进行录音和音频编码
	    。如果配置了 RecordApp.UniWithoutAppRenderjs=true 且未调用依赖renderjs的功能时（如nvue、可视化、仅H5中可用的插件）
	    ，可不提供此renderjs模块，同时逻辑层中需要将相关import的条件编译去掉**/
	import 'recorder-core'
	import RecordApp from 'recorder-core/src/app-support/app'
	import './Recorder-UniCore/app-uni-support.js' //renderjs中似乎不支持"@/"打头的路径，如果编译路径错误请改正路径即可

	//按需引入你需要的录音格式支持文件，和插件
	import 'recorder-core/src/engine/mp3'
	import 'recorder-core/src/engine/mp3-engine'
	//按需引入你需要的录音格式支持文件，如果需要多个格式支持，把这些格式的编码引擎js文件统统引入进来即可
	import "recorder-core/src/engine/wav";
	import 'recorder-core/src/extensions/waveview'

	export default {
		mounted() {
			//App的renderjs必须调用的函数，传入当前模块this
			RecordApp.UniRenderjsRegister(this);
		},
		methods: {
			//这里定义的方法，在逻辑层中可通过 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接调用
			//调用逻辑层的方法，请直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 调用，二进制数据需转成base64来传递
		}
	}
</script>
<!-- #endif -->
<script>
	import Ajax from "../../utils/ajax.js";
	import coziAjax from "../utils/cozi.js";
	import gChatMessage from "../components/chatEvent/message.vue";
	import gChatGree from "../components/chatEvent/greeting.vue";
	import gChatMarkdown from "../components/chatEvent/markdown.vue";
	import {
		AsrClient
	} from "../utils/AsrClient.js";
	//必须引入的Recorder核心（文件路径是 /src/recorder-core.js 下同），使用import、require都行
	import Recorder from "recorder-core"; //注意如果未引用Recorder变量，可能编译时会被优化删除（如vue3 tree-shaking），请改成 import 'recorder-core'，或随便调用一下 Recorder.a=1 保证强引用

	//必须引入的RecordApp核心文件（文件路径是 /src/app-support/app.js）
	import RecordApp from "recorder-core/src/app-support/app";

	//所有平台必须引入的uni-app支持文件（如果编译出现路径错误，请把@换成 ../../ 这种）
	import "./Recorder-UniCore/app-uni-support.js";

	/** 需要编译成微信小程序时，引入微信小程序支持文件 **/
	// #ifdef MP-WEIXIN
	import "recorder-core/src/app-support/app-miniProgram-wx-support.js";
	// #endif

	/** H5、小程序环境中：引入需要的格式编码器、可视化插件，App环境中在renderjs中引入 **/
	// 注意：如果App中需要在逻辑层中调用Recorder的编码/转码功能，需要去掉此条件编译，否则会报未加载编码器的错误
	// #ifdef H5 || MP-WEIXIN
	//按需引入你需要的录音格式支持文件，如果需要多个格式支持，把这些格式的编码引擎js文件统统引入进来即可
	import "recorder-core/src/engine/wav";

	//可选的插件支持项，把需要的插件按需引入进来即可
	import "recorder-core/src/extensions/waveview";
	// #endif
	var _wsTimer = null;
	let defaultMsg = '你好，我是智能匹配AI' + (uni.getStorageSync("ai-name") ? uni.getStorageSync('ai-name') : '助手') + '，可以帮您快速匹配工作（支持语音输入）。为了匹配更准确，需您提供需求信息，例如：1. 性别2. 年龄3. 意向城市4. 工作要求(如吃住、班次等)示例：我今年32岁，女性，想去常州找个长白班的工作。'
	export default {
		components: {
			gChatMessage,
			gChatGree,
			gChatMarkdown,
		},
		onShareAppMessage() {
			return this.G.shareFun();
		},
		data() {
			return {
				themeColor: getApp().globalData.themeColor,
				hasSafeArea: false,
				isHidden:false,
				jobnum:0,
				rightAnimate1:false,
				rightAnimate2:false,
				defaultChat:[
					{
						msg:defaultMsg,
						chat_type:'text',
						robotTag:1,
						messageType:98
					}
				],
				previousHeight:0,
				stesttest:0,
				writeStyle: 'bottom:0',
				isIosWxapp: false,
				scrollIntoView: '',
				wh: uni.getSystemInfoSync().screenHeight + 'px',
				isFinish: 1,
				isFluency: false,
				isAside: {
					isShow: false,
				},
				content: "",
				textareaHeight: 30,
				initialHeight: 0,
				isShowLeftLoading:false,
				leftAnimate1:false,
				leftAnimate2:false,
				leftAnimate3:false,
				localBaseImg: this.G.store().localBaseImg,
				scrollTop: 0,
				list: [],

				dzj: "",
				msgType: "voice",
				sendMsg: "",
				sendIconStatus: false,
				voiceMsg: "按住 说话",
				voiceStatus: -1, // -1 录音前 & 录音结束 0 录音时且在指定范围 1录音时但不在指定范围 -2点击
				longPressDelay: 230, // 设定长按所需时间，单位毫秒
				spec: true,
				isAuth: false,
				content: "", // 内容
				hasTopPadding: false,
				allJob: [],
				talkId: 0,
				gptType: "",
				bottomHeight: 100,
				longPressTimer: null,
				isStartRecord: false,
				sendMsgGroup: [],
				socketTask: null,
				sequenceCounter: 1,
				innerAudioContext: null,
				cid: -1,
				hisPage: 1,
				ws_send_ready: false,
				reconnectCount: 0,
				isSending: false,
				form: 'chat',
				codeGroup: [],
				stip: 'text',
				isShowRightLoading: false,
				isReturn: false,
				isShowWelcome:false,
				lastClickTime: 0, // 记录上一次点击时间
    		isFastClick: false, // 是否是快速点击
				hotObj:{},
				isjob:false,
				aiPage:0,
				ishide:false,
				isShowFirst:false,
				helloText:'',
				isShowDel:false,
				jobRendered:false,
				endType:'text',
				sendInfo:{
					chat_id:'',
					conversation_id:''
				},
				isLiuSend:false,
				isCancel:false,
				isRender:false,
				jobnus:5000
			};
		},
		onLoad(options) {
			let that = this;
			console.log('聊天页获取参数',options)
			this.checkSafeArea();
			that.cid = options.cid;
			that.form = options.form;
			that.stip = options.stip;
			that.helloText = options.title;

			if (options.type) {
				that.gptType = options.type;
			} else {
				that.gptType = "ai";
			}

			// 初始化音频上下文
			that.innerAudioContext = uni.createInnerAudioContext();
			that.innerAudioContext.autoplay = false; // 设置为 false，手动控制播放
			that.innerAudioContext.onPlay(() => {
			});
			that.innerAudioContext.onError((res) => {});
			this.isMounted = true;
			//页面onShow时【必须调用】的函数，传入当前组件this
			RecordApp.UniPageOnShow(this);
			uni.setNavigationBarTitle({
				title: (uni.getStorageSync("ai-name") ? uni.getStorageSync('ai-name') : '助手') + '',
			})
		},
		onShow() {
			let that = this;
			that.themeColor = getApp().globalData.themeColor;
			that.G.Get(that.api.get_job_updateNum, {hour:48}, (resNum) => {
				that.jobNus = resNum;
				that.isHidden = false;
				uni.removeStorageSync('ls_obj')
				that.checkRecordingPermission();

				if (this.isMounted) RecordApp.UniPageOnShow(this);

				that.initASRClient();
				// 监听ws状态
				uni.$on("ws_send_ready", function(data) {
					that.ws_send_ready = data.data;
				});

				// 异常监听
				uni.$on("asrEvent_close", function(data) {
					that.isShowRightLoading = false;
					that.rightAnimate1 = false;
					that.rightAnimate2 = false;
					if (data.code == 400) {
						// 链接超限，重连
					} else {
						that.endType = 'text'
						that.isHidden = true;
						that.list[that.list.length - 1].isHidden = true;
						uni.showToast({
							icon: "error",
							title: data.data,
						});
					}
				});
				// 监听ws事件
				uni.$on("asrEvent_message", function(data) {
					let _asrData = {};
					if (data.data) {
						_asrData = JSON.parse(data.data);
						if (_asrData.sequence == 1) {
							// 开始录音
						} else if (_asrData.sequence < 0) {
							// 将 获取的_asrData.sequence 推进数组并去重，然后遍历该数组，判断哪个元素是负值，在负值中执行结束录音的操作
							// 将当前 sequence 推入数组
							that.codeGroup.push(_asrData.sequence);
							// 去重
							that.codeGroup = [...new Set(that.codeGroup)];
							// 遍历数组，检查是否有负值
							for (let i = 0; i < that.codeGroup.length; i++) {
								if (that.codeGroup[i] < 0) {
									// 结束录音
									that.asrClient.asr_close();
									if (_asrData.result && _asrData.result.length > 0) {
										let asrStr = _asrData.result[0].text;
										that.$nextTick(()=>{
											that.scrollToBottom(()=>{
												that.$nextTick(()=>{
													that.animate();
													that.sendAudioAI(asrStr);
												})
											},'拿到一句话识别',100)
										})
									}
									break;
								}
							}
						} else {
							// 发送中
						}
					}
				});
				setTimeout(() => {
					that.hisPage = 1;
				}, 10);



				

				// #ifdef MP-WEIXIN
				const accountInfo = uni.getAccountInfoSync();
				const env = accountInfo.miniProgram.envVersion;

				if (env === 'develop') {
					that.isShowDel = true;
				} else if (env === 'trial') {
					that.isShowDel = true;
				} else if (env === 'release') {
					that.isShowDel = false;
				}
				// #endif
				// #ifdef APP-PLUS
				that.isShowDel = false;
				// #endif

				if(uni.getStorageSync('isExecute') == 0){
					return false;
				}

				uni.showLoading({
					title: '加载中',
				})
				// that.list = [];
				that.G.Post(that.api.chat_getConversationld, {
					robotId:uni.getStorageSync('robot_id'),
					agencyId:uni.getStorageSync("apply-agencyId")
				}, (res) => {
					uni.hideLoading();
					that.talkId = res;
					that.cid = res; 
					that.invokeGetCoziInfoIfAllowed((coziRes)=>{
						if (that.cid && String(that.cid).length > 4) {
							that.talkId = that.cid;
							that.list = [];
							that.isShowWelcome = false;
							that.isShowFirst = false
							that.getHistory();
						} else {
							that.isShowWelcome = true;
							that.list = that.defaultChat;
							that.initSocket();
							that.isShowFirst = true;
						}


						if(that.ishide){
							that.ishide = false;
							that.scrollToBottom()
						}
						that.previousHeight = 0;
						that.codeGroup = [];
						const isWxApp = uni.getSystemInfoSync().uniPlatform == 'mp-weixin'
						const isIosWxapp = uni.getSystemInfoSync().platform == 'ios' && isWxApp
						that.isIosWxapp = isIosWxapp;

						that.isFinish = 1;
						that.voiceStatus = -1;
						that.isStartRecord = false;
						// 创建查询对象
						const query = uni.createSelectorQuery();
						// 选择指定的 DOM 元素
						query.select(".chat-operate").boundingClientRect();
						// 执行查询
						query.exec((res) => {
							if (res && res[0]) {
								const height = res[0].height;
								that.bottomHeight = height;
								that.wh = `calc(${uni.getSystemInfoSync().windowHeight}px - ${that.bottomHeight}px)`;
							} 
						});
					})
				});
			});
		},
		onHide(){
			this.ishide = true;
			this.leaveEvent()
		},
		onUnload() {
			this.leaveEvent()
		},
		watch: {
			sendMsg(val) {
				if (val) {
					this.sendIconStatus = true;
				} else {
					this.sendIconStatus = false;
				}
			},
			isShowRightLoading(val) {
				let that = this;
				if(val == true){
					setTimeout(() => {
						that.$nextTick(()=>{
							that.scrollToBottom(()=>{},'watch 监听 右侧loading',300)
						})
					}, 100);
				}
			},
			isShowLeftLoading(val){
				let that = this;
				if(val == true){
					setTimeout(() => {
						that.$nextTick(()=>{
							that.scrollToBottom(()=>{},'watch 监听 左侧loading',300)
						})
					}, 101);
				}
			},
		},
		methods: {
			checkSafeArea() {
			try {
				const systemInfo = uni.getSystemInfoSync();
				console.log('安全域 systemInfo',systemInfo)
				if (systemInfo.safeArea) {
					this.hasSafeArea = true;
				} else {
					this.hasSafeArea = false;
				}
			} catch (error) {
				console.error('获取系统信息失败:', error);
			}
		},
			shouldCallGetCoziInfo() {
				const lastCalledTime = uni.getStorageSync('last_called_getCoziInfo');
				const now = new Date().getTime();

				if (!lastCalledTime || now - lastCalledTime >= 60 * 60 * 1000) {
					return true;
				}
				return false;
			},

			invokeGetCoziInfoIfAllowed(callback=()=>{}) {
				if (this.shouldCallGetCoziInfo()) {
					this.getCoziInfo((coziRes) => {
						callback();
					});

					uni.setStorageSync('last_called_getCoziInfo', new Date().getTime());
				} else{
					callback();
				}
			},
			delAll(){
				let that = this;
				uni.showModal({
					title: '提示',
					content: '确定要删除该机器人的全部记录吗？',
					success: (res) => {
						if (res.confirm) {
							that.G.Post(
								that.api.chat_delMsg, {
									deleteAll:1,
									conversationId: that.cid,
								},() => {
									uni.showToast({
										icon:'success',
										title:'删除成功'
									})
									uni.navigateBack();
								}
							)
						}else{}
					}
				});
			},
			leaveEvent(){
				let that = this;
				that.spec = false;
				that.hisPage = 1;
				this.previousHeight = 0;
				// this.stesttest = 0;
				this.clearHeartbeat();
				this.asrClient.asr_close();
				_wsTimer = null;
				uni.$off('asrEvent_message')
				uni.hideLoading();
				uni.removeStorageSync('test_file')
				this.isShowRightLoading = false;
				that.rightAnimate1 = false;
				that.rightAnimate2 = false;
				this.isShowLeftLoading = false;
				this.leftAnimate1 = false;
				this.leftAnimate2 = false;
				this.leftAnimate3 = false;
				this.G.startAbort(1)
			},
			initFormPageInfo() {
				let that = this;

				that.isShowLeftLoading = false;
				that.leftAnimate1 = false;
				that.leftAnimate2 = false;
				that.leftAnimate3 = false;

				that.isShowRightLoading = true;
				that.rightAnimate1 = false;
				that.rightAnimate2 = false;

				that.list.push({
					msg: "",
					isGood: false,
					isDown: false,
					chat_type: "",
					robotTag: 0,
				})
				that.startRightAnimate();
				that.asrClient.asr_sync_connect('main');
				let _wsTimer = setInterval(() => {
					if (that.ws_send_ready) {
						var audioChunks_copy = uni.getStorageSync('test_file').split(',').map(item => {
							return item * 1
						});
						var audioChunks = new Int8Array(audioChunks_copy)
						const CHUNK_SIZE = 1024 * 20;
						for (let i = 0; i < audioChunks.length; i += CHUNK_SIZE) {
							const end = Math.min(i + CHUNK_SIZE, audioChunks.length);
							const chunk = audioChunks.subarray(i, end); // 关键修改
							that.asrClient.asr_send(chunk, end === audioChunks.length);
						}
						that.$nextTick(()=>{
							that.scrollToBottom(()=>{
								that.$nextTick(()=>{
									clearInterval(_wsTimer); // 停止值的更新
								})
							},'解析文件结束',100)
						})
					} else {
						if (that.reconnectCount < 10) {
							that.reconnectCount++;
							that.asrClient.asr_close();
							uni.removeStorageSync('asytip');
							that.asrClient.asr_sync_connect('main');
						} else {
							clearInterval(_wsTimer);
							_wsTimer = null;
							that.asrClient.asr_close();
							setTimeout(() => {
								uni.hideToast();
							}, 800);
						}
					}
				}, 1000);
			},


			//请求录音权限
			recReq() {
				var that = this;
				//编译成App时提供的授权许可（编译成H5、小程序为免费授权可不填写）；如果未填写授权许可，将会在App打开后第一次调用请求录音权限时，弹出“未获得商用授权时，App上仅供测试”提示框
				//RecordApp.UniAppUseLicense='我已获得UniAppID=*****的商用授权';

				RecordApp.RequestPermission_H5OpenSet = {
					audioTrackSet: {
						noiseSuppression: true,
						echoCancellation: true,
						autoGainControl: true
					}
				}; //这个是Start中的audioTrackSet配置，在h5（H5、App+renderjs）中必须提前配置，因为h5中RequestPermission会直接打开录音

				RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
				RecordApp.RequestPermission(
					() => {
						console.log("已获得录音权限，可以开始录音了");
						that.isAuth = true;
					},
					(msg, isUserNotAllow) => {
						if (isUserNotAllow) {
							//用户拒绝了录音权限
							//这里你应当编写代码进行引导用户给录音权限，不同平台分别进行编写
							uni.showModal({
								title: '提示',
								content: '需要录音权限才能使用语音功能，请前往设置开启权限',
								success: function (res) {
									if (res.confirm) {
										uni.openSetting({
											success: (settingData) => {
												if (settingData.authSetting['scope.record']) {
													uni.showToast({ title: '授权成功' });
													that.msgType = "voice";
													that.isAuth = true;
													that.checkRecordingPermission(); // 重新尝试请求权限
												} else {
													uni.showToast({ icon: 'none', title: '授权失败' });
												}
											},
										});
									}
								},
							});
						}
						console.error("请求录音权限失败：" + msg);
						that.msgType = 'text'
					}
				);
			},

			//开始录音
			recStart() {
				this.codeGroup = [];
				//Android App如果要后台录音，需要启用后台录音保活服务（iOS不需要），需使用配套原生插件、或使用第三方保活插件
				//RecordApp.UniNativeUtsPluginCallAsync("androidNotifyService",{ title:"正在录音" ,content:"正在录音中，请勿关闭App运行" }).then(()=>{...}).catch((e)=>{...}) 注意必须RecordApp.RequestPermission得到权限后调用
				// const params_msg = this.asrClient.asr_send_full_client_req();

				//录音配置信息
				var set = {
					type: "wav",
					sampleRate: 16000,
					bitRate: 16, //mp3格式，指定采样率hz、比特率kbps，其他参数使用默认配置；注意：是数字的参数必须提供数字，不要用字符串；需要使用的type类型，需提前把格式支持文件加载进来，比如使用wav格式需要提前加载wav.js编码引擎
					/*,audioTrackSet:{ //可选，如果需要同时播放声音（比如语音通话），需要打开回声消除（并不一定会生效；打开后声音可能会从听筒播放，部分环境下（如小程序、App原生插件）可调用接口切换成扬声器外放）
						//注意：H5、App+renderjs中需要在请求录音权限前进行相同配置RecordApp.RequestPermission_H5OpenSet后此配置才会生效
						echoCancellation:true,noiseSuppression:true,autoGainControl:true} */
					onProcess: (buffers, powerLevel, duration, sampleRate, newBufferIdx, asyncEnd) => {
						//全平台通用：可实时上传（发送）数据，配合Recorder.SampleData方法，将buffers中的新数据连续的转换成pcm上传，或使用mock方法将新数据连续的转码成其他格式上传，可以参考Recorder文档里面的：Demo片段列表 -> 实时转码并上传-通用版；基于本功能可以做到：实时转发数据、实时保存数据、实时语音识别（ASR）等

						//注意：App里面是在renderjs中进行实际的音频格式编码操作，此处的buffers数据是renderjs实时转发过来的，修改此处的buffers数据不会改变renderjs中buffers，所以不会改变生成的音频文件，可在onProcess_renderjs中进行修改操作就没有此问题了；如需清理buffers内存，此处和onProcess_renderjs中均需要进行清理，H5、小程序中无此限制
						//注意：如果你要用只支持在浏览器中使用的Recorder扩展插件，App里面请在renderjs中引入此扩展插件，然后在onProcess_renderjs中调用这个插件；H5可直接在这里进行调用，小程序不支持这类插件；如果调用插件的逻辑比较复杂，建议封装成js文件，这样逻辑层、renderjs中直接import，不需要重复编写

						//H5、小程序等可视化图形绘制，直接运行在逻辑层；App里面需要在onProcess_renderjs中进行这些操作
						// #ifdef H5 || MP-WEIXIN
						if (this.waveView) this.waveView.input(buffers[buffers.length - 1], powerLevel,
						sampleRate);
						// #endif

						/*实时释放清理内存，用于支持长时间录音；在指定了有效的type时，编码器内部可能还会有其他缓冲，必须同时提供takeoffEncodeChunk才能清理内存，否则type需要提供unknown格式来阻止编码器内部缓冲，App的onProcess_renderjs中需要进行相同操作
						if(this.clearBufferIdx>newBufferIdx){ this.clearBufferIdx=0 } //重新录音了就重置
						for(var i=this.clearBufferIdx||0;i<newBufferIdx;i++) buffers[i]=null;
						this.clearBufferIdx=newBufferIdx; */
					},
					onProcess_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
					//App中在这里修改buffers会改变生成的音频文件，但注意：buffers会先转发到逻辑层onProcess后才会调用本方法，因此在逻辑层的onProcess中需要重新修改一遍
					//本方法可以返回true，renderjs中的onProcess将开启异步模式，处理完后调用asyncEnd结束异步，注意：这里异步修改的buffers一样的不会在逻辑层的onProcess中生效
					//App中是在renderjs中进行的可视化图形绘制，因此需要写在这里，this是renderjs模块的this（也可以用This变量）；如果代码比较复杂，请直接在renderjs的methods里面放个方法xxxFunc，这里直接使用this.xxxFunc(args)进行调用
					if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
					
					/*和onProcess中一样进行释放清理内存，用于支持长时间录音
					if(this.clearBufferIdx>newBufferIdx){ this.clearBufferIdx=0 } //重新录音了就重置
					for(var i=this.clearBufferIdx||0;i<newBufferIdx;i++) buffers[i]=null;
					this.clearBufferIdx=newBufferIdx; */
				}`,
					onProcessBefore_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx){
					//App中本方法会在逻辑层onProcess之前调用，因此修改的buffers会转发给逻辑层onProcess，本方法没有asyncEnd参数不支持异步处理
					//一般无需提供本方法只用onProcess_renderjs就行，renderjs的onProcess内部调用过程：onProcessBefore_renderjs -> 转发给逻辑层onProcess -> onProcess_renderjs
				}`,

					takeoffEncodeChunk: true ?
						null :
						(chunkBytes) => {
							//全平台通用：实时接收到编码器编码出来的音频片段数据，chunkBytes是Uint8Array二进制数据，可以实时上传（发送）出去
							//App中如果未配置RecordApp.UniWithoutAppRenderjs时，建议提供此回调，因为录音结束后会将整个录音文件从renderjs传回逻辑层，由于uni-app的逻辑层和renderjs层数据交互性能实在太拉跨了，大点的文件传输会比较慢，提供此回调后可避免Stop时产生超大数据回传
							//App中使用原生插件时，可方便的将数据实时保存到同一文件，第一帧时append:false新建文件，后面的append:true追加到文件
							//RecordApp.UniNativeUtsPluginCallAsync("writeFile",{path:"xxx.mp3",append:回调次数!=1, dataBase64:RecordApp.UniBtoa(chunkBytes.buffer)}).then(...).catch(...)
						},
					takeoffEncodeChunk_renderjs: true ?
						null :
						`function(chunkBytes){
					//App中这里可以做一些仅在renderjs中才生效的事情，不提供也行，this是renderjs模块的this（也可以用This变量）
				}`,

					start_renderjs: `function(){
					//App中可以放一个函数，在Start成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
					//放一些仅在renderjs中才生效的事情，比如初始化，不提供也行
				}`,
					stop_renderjs: `function(arrayBuffer,duration,mime){
					//App中可以放一个函数，在Stop成功时renderjs中会先调用这里的代码，this是renderjs模块的this（也可以用This变量）
					//放一些仅在renderjs中才生效的事情，不提供也行
				}`,
				};

				RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
				RecordApp.Start(
					set,
					() => {
						// that.codeGroup = [];
						console.log("已开始录音");
						//【稳如老狗WDT】可选的，监控是否在正常录音有onProcess回调，如果长时间没有回调就代表录音不正常
						//var wdt=this.watchDogTimer=setInterval ... 请参考示例Demo的main_recTest.vue中的watchDogTimer实现

						//创建音频可视化图形绘制，App环境下是在renderjs中绘制，H5、小程序等是在逻辑层中绘制，因此需要提供两段相同的代码
						//view里面放一个canvas，canvas需要指定宽高（下面style里指定了300*100）
						//<canvas type="2d" class="recwave-WaveView" style="width:300px;height:100px"></canvas>
						// RecordApp.UniFindCanvas(this,[".recwave-WaveView"],`
						//     this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
						// `,(canvas1)=>{
						//     this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
						// });
					},
					(msg) => {
						console.error("开始录音失败：" + msg);
					}
				);
			},

			//暂停录音
			recPause() {
				if (RecordApp.GetCurrentRecOrNull()) {
					RecordApp.Pause();
				}
			},
			//继续录音
			recResume() {
				if (RecordApp.GetCurrentRecOrNull()) {
					RecordApp.Resume();
				}
			},

			//停止录音
			recStop() {
				//RecordApp.UniNativeUtsPluginCallAsync("androidNotifyService",{ close:true }) //关闭Android App后台录音保活服务
				let that = this;
				RecordApp.Stop(
					(arrayBuffer, duration, mime) => {
						if (that.spec) {
							that.list.push({
								msg: "",
								isGood: false,
								isDown: false,
								chat_type: "",
								robotTag: 0,
							})
							that.startRightAnimate(()=>{});
							that.$nextTick(()=>{
								that.scrollToBottom(()=>{
									//全平台通用：arrayBuffer是音频文件二进制数据，可以保存成文件或者发送给服务器
									//App中如果在Start参数中提供了stop_renderjs，renderjs中的函数会比这个函数先执行
							
									//注意：当Start时提供了takeoffEncodeChunk后，你需要自行实时保存录音文件数据，因此Stop时返回的arrayBuffer的长度将为0字节
							
									//如果是H5环境，也可以直接构造成Blob/File文件对象，和Recorder使用一致
									// #ifdef H5
									var blob = new Blob([arrayBuffer], {
										type: mime
									});
									var file = new File([arrayBuffer], "recorder.wav");
									//uni.uploadFile({file:file, ...}) //参考demo中的test_upload_saveFile.vue
									// #endif
							
									//如果是App、小程序环境，可以直接保存到本地文件，然后调用相关网络接口上传
									// #ifdef APP || MP-WEIXIN
									var audioChunks = new Int8Array(arrayBuffer);
									_wsTimer = setInterval(() => {
										if (that.ws_send_ready) {
											const CHUNK_SIZE = 1024 * 20;
											for (let i = 0; i < audioChunks.length; i += CHUNK_SIZE) {
												const end = Math.min(i + CHUNK_SIZE, audioChunks.length);
												const chunk = audioChunks.subarray(i, end); // 关键修改
												that.asrClient.asr_send(chunk, end === audioChunks.length);
											}
											that.$nextTick(()=>{
												that.scrollToBottom(()=>{
													that.$nextTick(()=>{
														clearInterval(_wsTimer); // 停止值的更新
													})
												},'当前页解析结束',100)
											})
										} else {
											if (that.reconnectCount < 10) {
												that.reconnectCount++;
												that.asrClient.asr_close();
												uni.removeStorageSync('asytip');
												that.asrClient.asr_sync_connect();
											} else {
												clearInterval(_wsTimer);
												_wsTimer = null;
												that.asrClient.asr_close();
												// uni.showToast({
												// 	title: "识别异常，请重试",
												// 	icon: "none",
												// });
												setTimeout(() => {
													uni.hideToast();
												}, 800);
											}
										}
									}, 1000);
									// #endif
								},100,100)
							})
						} 
					},
					(msg) => {
						console.error("结束录音失败：" + msg);
					}
				);
			},
			getMore() {
				let that = this;
				if (that.isFinish == 1) {
					that.hisPage++;
					uni.setStorageSync('isExecute',1)
					that.getHistory("concat");
				}
			},
			formatMessageTime(dateStr) {
				const now = new Date();
				const date = new Date(dateStr);
				
				// 判断是否为有效日期
				if (isNaN(date.getTime())) return "";

				const year = date.getFullYear();
				const month = date.getMonth() + 1;
				const day = date.getDate();
				const hour = date.getHours().toString().padStart(2, "0");
				const minute = date.getMinutes().toString().padStart(2, "0");

				// 计算时间差（单位：毫秒）
				const diffMs = now - date;

				// 1. 刚刚（1分钟以内）
				if (diffMs < 60000) {
					return "刚刚";
				}

				// 2. 今天的消息（显示时间 HH:mm）
				if (
					now.getFullYear() === year &&
					now.getMonth() + 1 === month &&
					now.getDate() === day
				) {
					return `${hour}:${minute}`;
				}

				// 3. 昨天的消息
				const yesterday = new Date(now);
				yesterday.setDate(yesterday.getDate() - 1);
				if (
					yesterday.getFullYear() === year &&
					yesterday.getMonth() + 1 === month &&
					yesterday.getDate() === day
				) {
					return `昨天 ${hour}:${minute}`;
				}

				// 4. 今年的消息（不跨年）
				if (now.getFullYear() === year) {
					return `${month}月${day}日 ${hour}:${minute}`;
				}

				// 5. 去年的消息或更早（跨年）
				return `${year}年${month}月${day}日 ${hour}:${minute}`;
			},
			getHistory($type = "init") {
				let that = this;
				const query = uni.createSelectorQuery().in(this);
				if(uni.getStorageSync('isExecute') == 0){
					return false;
				}
				// 获取当前滚动位置
				query.select(".chat-content .chatBox").boundingClientRect(res => {
					
					let currentScrollTop = res ? res.height : 0;

					if ($type == "concat") {
						uni.showToast({
							title: "加载中...",
							icon: "loading",
							duration: 1000,
						});
					}

					that.G.Post(
						that.api.chat_getHistory, {
							classify: 0,
							conversationId: that.cid,
							pageNum: that.hisPage,
							pageSize: 10,
						},
						(historyRes) => {
							
							uni.setStorageSync('isExecute',0)
							if ($type == "concat") {
								uni.hideToast();
							}
							console.log("获取历史记录：", historyRes,' that.hisPage:',that.hisPage);

							if (historyRes && historyRes.length > 0) {
								let _array = historyRes.map((item) => {
									item.chatType = "text";
									item.ids = '';
									item.comList = [];
									if(item.messageType == 97 && 
											item.attr1 == '' && 
											item.attr2 == '' && 
											item.attr3 == '' && 
											item.message
									){
										try {
												// 检查是否是有效的JSON字符串
												const parsedMessage = JSON.parse(item.message);
												if (Array.isArray(parsedMessage)) {
														// 如果是数组，检查是否包含职位信息
														if (parsedMessage.length > 0 && parsedMessage.some(el => el && typeof el === 'object' && '职位ID' in el)) {
																item.chatType = "markdown";
																item.ids = parsedMessage.map(itm => itm['职位ID']).filter(id => id).join(',');
														} else {
																// 普通数组或不包含职位ID的数组
																item.chatType = "text";
																item.message = item.message
														}
												}else{
													item.chatType = "text";
													item.message = item.message
												}
										} catch (e) {
												item.chatType = "text";
												item.message = item.message
										}
									}else if(item.messageType == 99 && 
														item.message == '推荐职位' &&
														item.attr2 &&
														item.attr3 == "jobcard"
									){
										item.chatType = "markdown";
										item.ids = item.attr2;
									}
									return {
										classify: item.classify,
										ids: item.ids,
										msg: item.message,
										id: item.id,
										message: item.message,
										isGood: false,
										isDown: false,
										chat_type: item.chatType,
										robotTag: item.robotTag,
										comList: item.comList,
										createTime: item.createTime,
										messageType:item.messageType || 0,
										attr1:item.attr1 || '',
										attr2:item.attr2 || '',
									};
								});
								console.log('0811 001')
								if ($type != "concat") {
										uni.showLoading({ title: '加载中' });
										setTimeout(()=>{
											uni.hideLoading();
										},300)
										that.isShowWelcome = false;
								}
								console.log('0811 002')
								const promises = _array.map(item => {
										if (item.ids && item.ids!='undefined' && item.ids.replace(/,/g, "")) {
											console.log('0811 003 ids',item.ids)
												return new Promise((resolve, reject) => {
														that.getHomeList(item.ids, (hotList) => {
																item.comList = hotList;
																resolve();
														}, 1, 'hostory');
												});
										} else {
												console.log('0811 003 null',item)
												return Promise.resolve(); // 如果没有 ids，直接返回已解决的 Promise
										}
								});
								console.log('0811 003')
								Promise.all(promises).then(() => {
									console.log('0811 004')
									if ($type != "concat") {
											uni.hideLoading();
									}
									if ($type == "concat") {
											if (historyRes && historyRes.length < 10) {
													that.isFinish = 2;
											} else {
													that.isFinish = 1;
											}
											// 向上拼接
											that.list = [..._array, ...that.list];

											that.$nextTick(() => {
													const queryRestore = uni.createSelectorQuery().in(this);
													queryRestore.select(".chatBox").boundingClientRect(resNew => {
															if (resNew) {
																	const heightDiff = resNew.height - currentScrollTop;
																	that.stesttest = heightDiff > 0 ? heightDiff : 0;
															}
													}).exec();
											});

									} else {
											that.isFinish = 1;
											that.list = _array;
											if(that.aiPage <= 1){
												that.hotObj = {};
												that.isjob = false;
												function parseStringToObject(str) {
													const obj = {};
													const pairs = str.split(',').map(pair => pair.trim());
													pairs.forEach(pair => {
														const [key, value] = pair.split(':').map(part => part.trim());
														obj[key] = value.replace(/^['"]|['"]$/g, '');
													});
													return obj;
												}
												that.handleRecordJobEnd(()=>{
													that.list.forEach((item,index) => {
														if(item.messageType == 99 && item.isRecordJobEnd){
															let _objs = parseStringToObject(item.attr1);
															that.isjob = true;
															that.hotObj['sex'] = _objs['sex'];
															that.hotObj['ageRangeStr'] = _objs['ageRangeStr'];
															that.hotObj['cityName'] = _objs['cityName'];
															that.hotObj['labelNames'] = _objs['labelNames'];
															let _oa = {};
															_oa['sex'] = _objs['sex'];
															_oa['ageRangeStr'] = _objs['ageRangeStr'];
															_oa['cityName'] = _objs['cityName'];
															_oa['labelNames'] = _objs['labelNames'];
															uni.setStorageSync('ls_obj', JSON.stringify(_oa))
															item.ids = item.attr2; 
														}
													});
												});
											}
									};
									
									if(uni.getStorageSync('btn_form') == 1){
										that.startRightAnimate(()=>{});
										uni.removeStorageSync('btn_form')
									}
									that.$nextTick(() => {
										that.initFormPage()
									});
								}).catch((rea)=>{
									console.log('reaaaa',rea)
								});
							} else {
								that.isFinish = 2;
								that.$nextTick(()=>{
									that.initFormPage()
									if ($type != "concat") {
										that.scrollToBottom(()=>{},'当前页-无记录',300);
									}
									if($type == "init"){
										that.list = that.defaultChat;
									}
								})
							}
						}
					);
				}).exec();
			},
			initFormPage(){
				let that = this;
				// 页面-获取文字
				if (that.form == 'msgdata') {
					that.sendAI('msgdata');
				}
				// 页面-获取音频
				if (that.form == 'audiodata') {
					that.initFormPageInfo()
				}
				// 页面-查看会话
				if (that.form == 'viwdata') {
					that.scrollToBottom(()=>{},'查看会话',300);
				}
			},
			getHomeList(ids, callback = () => {}, $pageNum = 1,$form='') {
				let that = this;
				let _url = that.api.yi_job_list;
				let params = {}
				if(!ids || ids == 'undefined'){
					return false;
				}
				if(that.aiPage <= 1){
					params = {
						shareJobIds: ids,
						recruitment: 1,
						pageNum: that.aiPage
					}
				}else{
					params = Object.assign(that.hotObj,{
						recruitment: 1,
						pageNum: that.aiPage,
						pageSize:5
					})
				}
				if(params.pageNum == 0){
					params.pageNum = 1;
				}
				params.checkStore = true;
				that.G.Post(_url, params, (res) => {
					let resData = {};
					resData = res.pageBean;
					if (resData.recordList && resData.recordList.length > 0) {
						resData.recordList = that.G.toGetAddressv3(resData.recordList);
						resData.recordList = that.G.toGetAge(resData.recordList);
						that.G.Post("/yishoudan/labels/type/app/80", {}, (res) => {
							uni.setStorageSync("JOB_REQUIRE_LIST", {
								data: res.labels,
								time: Date.now()
							});
							resData.recordList = that.G.yijobCopy(resData.recordList);
						});
					}
					resData.recordList.forEach(item => {
						item.gender = that.G.getGenderByMinAge(item);
						item.fuWuFei = that.G.setReturnFee(item.returnFee, item.returnFeeType);
						item.baoNum = uni.getStorageSync("lin-bao") ? uni.getStorageSync("lin-bao") / 10 :
							Math.ceil(item.liuNum / 10);
						item.cus_price = item.salaryClassify != 7 ? that.G.getSalaryClassifyValueHtml(item
							.salaryClassify, item.salaryClassifyValue) : "月薪";
						item.newadd = that.G.setJobInfoPositionv3(item.storeDistrict || item.storeAddr);
					})
					callback(resData.recordList)
				});
			},
			handlePlayAudio() {
				let that = this;
				if (that.audio_url) {
					that.innerAudioContext.src = that.audio_url; // 设置音频文件路径
					that.innerAudioContext.play(); // 开始播放
					that.innerAudioContext.onPlay(() => {
					});
					that.innerAudioContext.onError((res) => {});
				} else {}
			},
			initASRClient() {
				let that = this;
				try {
					// 初始化 ASR 客户端
					this.asrClient = new AsrClient("wss://openspeech.bytedance.com/api/v2/asr");
				} catch (error) {
					console.error("Error initializing ASR client:", error);
				}
			},
			readAudioFileAsArrayBuffer(filePath) {
				var that = this;
				return new Promise((resolve, reject) => {
					uni.getFileSystemManager().readFile({
						filePath: filePath,
						responseType: "arraybuffer", // 指定响应类型为数组缓冲区
						success: (res) => {
							resolve(new Int8Array(res.data));
						},
						fail: (err) => {
							reject(err);
						},
					});
				});
			},
			clearHeartbeat() {
				clearInterval(this.heartbeatInterval);
			},
			// 获取扣子信息
			getCoziInfo(callback=()=>{}) { 
				let that = this;
				// 获取扣子 token
				that.G.Get("/yishoudan/common/structure/getConfig", {}, (res) => {
					uni.setStorageSync("cozi_token", res.token);
					callback(res.token);
				});
			},
			// 创建会话
			coziCreate(callback=()=>{}){
				let that = this;
				coziAjax.coziPost('v1/conversation/create',{
					"bot_id": uni.getStorageSync('robot_id'),
					"messages": [
						{
							"content_type": "text",
							"role": "user",
							"type": "question"
						}
					],
					"custom_variables":{
						"appId":uni.getAccountInfoSync().miniProgram.appId
					}
				},(sdkRes) =>{
					callback(sdkRes)
				});
			},
			// 发起会话
			coziChat($sendMessage,callback=()=>{}){ 
				let that = this;
				that.jobRendered = false;
				that.$refs.chatSSEClientRef.startChat({
					url: "https://api.coze.cn/v3/chat?conversation_id=" + that.cid,
					// 请求头
					headers: {
						Authorization: "Bearer " + uni.getStorageSync("cozi_token"),
						"Content-Type": "application/json;charset=UTF-8",
					},
					// 默认为 post
					method: "post",
					body: {
						"bot_id": uni.getStorageSync('robot_id'),
						"user_id": "user",
						"stream": true,
						"additional_messages": [
							{
								"content": $sendMessage,
								"content_type": "text",
								"role": "user",
								"type": "question"
							}
						],
						"custom_variables":{
							"appId":uni.getAccountInfoSync().miniProgram.appId,
							'aiName':uni.getStorageSync("ai-name") ? uni.getStorageSync('ai-name') : 'ai助手'
						}
					},
				});
				callback()
			},
			// 取消会话
			coziCancelChat(callback=()=>{}){
				let that = this;
				that.isRender = false;
				if(that.sendInfo.conversation_id && that.sendInfo.chat_id){
					that.isCancel = true;
					coziAjax.coziPost('v3/chat/cancel',{
						"conversation_id":that.sendInfo.conversation_id,
						"chat_id":that.sendInfo.chat_id
					},(sdkRes) => {
						that.isCancel = false;
						that.sendInfo = {};
						callback(sdkRes)
					});
				}else{
					that.sendInfo = {};
					callback({
						"code": 400,
						"message": "会话不存在"
					})
				}
			},
			stopCore($form='default'){
				let that = this;
				that.list = that.list.slice(0, -1);
				that.$refs.chatSSEClientRef.stopChat();
				// 调用发送消息
				that.handleSendMsg()
			},
			openCore(err){
			},
			errorCore(err){
			},
			messageCore(msg){
				let that = this;
				if(that.isCancel){
					that.isRender = false;
					that.stopCore('停止流式输出');
					return false;
				}
				if(JSON.parse(msg.data) == '[DONE]'){
					that.isRender = false;
					that.isLiuSend = false;
					that.handleEnd();
				}else{
					that.isRender = true;
					that.isLiuSend = true;
					console.log('000000000000000000000',JSON.parse(msg.data))
					if(JSON.parse(msg.data) && JSON.parse(msg.data).type == 'answer'){
						that.sendInfo = {
							chat_id:JSON.parse(msg.data).chat_id,
							conversation_id:JSON.parse(msg.data).conversation_id
						}

						if(JSON.parse(msg.data).content && JSON.parse(msg.data).content != ' ' && !JSON.parse(msg.data).updated_at && JSON.parse(msg.data).content.length < 5){
							// console.log('文本类型**************************************回复：',JSON.parse(msg.data).content)
							// 流式输出增量渲染
							that.endType = 'text';
							that.handleTextRender(JSON.parse(msg.data))
						}else{
							that.$nextTick(()=>{
								that.scrollToBottom(()=>{},'类型异常',3);
							})
							try {
								const parsedData = JSON.parse(msg.data);
								try {
									const contentData = JSON.parse(parsedData.content);
									if (Array.isArray(contentData)) {
										// 处理数组内容，如渲染到页面或更新状态
										// console.log('推荐职位类型**************************************回复：',contentData)
										that.endType = 'markdown';
										that.handleJobRender(contentData)
									}else {}
								} catch (contentError) {}
							} catch (dataError) {}
						}
					}else if(JSON.parse(msg.data) && JSON.parse(msg.data).type == 'verbose'){
						that.$nextTick(()=>{
							that.scrollToBottom(()=>{},'errr',10);
						})
					}else if(JSON.parse(msg.data) && JSON.parse(msg.data).type == 'tool_response' && JSON.parse(msg.data).content == '暂未找到匹配的岗位'){
						// 异常
						that.isShowLeftLoading = false;
						uni.showToast({
							title: '暂未找到匹配的岗位',
							icon: 'none',
							duration:2000
						})
						that.list.splice(that.list.length - 1, 1);
					}
				}
			},
			finishCore(err){
			},
			handleTextRender($smg){
				let that = this;
				const targetIndex = that.list.length - 1;
				const parsed = $smg;
				that.list[targetIndex].chat_type = "text";
				that.list[targetIndex].robotTag = 1;
				that.list[targetIndex].ids = '';
				const newContent = parsed.content;
				// 增量追加内容
				that.$set(that.list[targetIndex], 'msg', (that.list[targetIndex].msg || '') + newContent);
				that.isSending = false;
				that.isShowLeftLoading = false;
				that.leftAnimate1 = false;
				that.leftAnimate2 = false;
				that.leftAnimate3 = false;
				that.$nextTick(()=>{
					that.scrollToBottom(()=>{},'流式输出中',10);
				})
			},
			handleJobRender($array){
				let that = this;
				if (that.jobRendered) return; // 已执行过则返回

  			that.jobRendered = true;
				that.hotObj = {};
				that.isjob = false;
				try {
					const parsedContent = $array;
					that.aiPage = 1;

					that.list.forEach((ita,ina) => {
						ita.opbtn = 0 
					})
					that.list[that.list.length - 1].opbtn = 1;

					that.list[that.list.length - 1].msg = parsedContent;
					that.list[that.list.length - 1].chat_type = "markdown";
					that.list[that.list.length - 1].robotTag = 1;
					that.list[that.list.length - 1].ids = parsedContent.map((itm,inx) => {
						if(inx == 0){
							that.isjob = true;
							that.hotObj['sex'] = itm['sex'];
							that.hotObj['ageRangeStr'] = itm['ageRangeStr'];
							that.hotObj['cityName'] = itm['cityName'];
							that.hotObj['labelNames'] = itm['labelNames'];

							let _oa = {};
							_oa['sex'] = itm['sex'];
							_oa['ageRangeStr'] = itm['ageRangeStr'];
							_oa['cityName'] = itm['cityName'];
							_oa['labelNames'] = itm['labelNames'];
							uni.setStorageSync('ls_obj', JSON.stringify(_oa))
						}
						return itm['职位ID']
					}).join(',');
					that.getHomeList(that.list[that.list.length - 1].ids, (hotList) => {
						that.list[that.list.length - 1].comList = [];
						that.list[that.list.length - 1].comList = hotList;
					},1,'send');
				} catch (e) {}
			},
			handleEnd(){
				let that = this;
				that.saveHistory(1, that.list[that.list.length - 1].msg, (historyData) => {
					console.log('最后一条消息保存成功',that.endType)
					that.list[that.list.length - 1].id = historyData.id;
					that.isSending = false;
					that.handleSet(that.list[that.list.length - 1].msg, "", 0, 300);
				},'messageEnd');
			},

			initSocket() {
				let that = this;
				that.coziCreate((sdkRes)=>{
					that.talkId = sdkRes.id;
					that.cid = sdkRes.id; 
					
					that.saveHistory(1, that.helloText ? '你好，我是' + that.helloText + '机器人' : '你好，我是伯才智能匹配AI' + (uni.getStorageSync("ai-name") ? uni.getStorageSync('ai-name') : '助手') + '，可以帮老乡快速匹配工作（支持语音输入）。为了匹配更准确，需多提供老乡需求信息，例如:1. 性别2. 年龄3. 意向城市4. 工作要求(如吃住、班次等)示例：有位32岁大姐，想去常州找个长白班的工作。快告诉我老乡需求，开始匹配吧!', (historyData) => {
						that.defaultChat.id = historyData.id;
						that.list = that.defaultChat;
					},'welcome');
				})
			},

			keyboardheightchange(e) {
				var that = this;
				if (e.target.dataset.height == 0 && this.sendMsg == "") {
					this.textareaHeight = 30;
				}
				if (this.isIosWxapp) {
					if (e.detail.height == 0) {
						this.writeStyle = `bottom:0`
						this.wh = `calc(${uni.getSystemInfoSync().windowHeight}px - ${this.bottomHeight}px)`
						// this.ghHeight = 'height:84px'
					} else {
						this.writeStyle = `bottom: calc(${e.detail.height}px - env(safe-area-inset-bottom) + 12rpx)`
						// this.ghHeight = `height:calc(84px + ${e.detail.height}px)`
						this.wh =
							`calc(${uni.getSystemInfoSync().windowHeight}px - ${this.bottomHeight}px - ${e.detail.height}px)`
					}
					that.scrollToBottom(()=>{},'键盘',100);
				}

			},
			onInput(e) {
				this.content = e.target.value;
				this.updateTextareaHeight();
			},
			onFocus() {
				this.initialHeight = this.textareaHeight;
			},
			onBlur() {
				this.updateTextareaHeight();
			},
			updateTextareaHeight() {},
			linechange(e) {
				// if (e.detail.lineCount > 1) {
				// 	this.hasTopPadding = true;
				// } else {
				// 	this.hasTopPadding = false;
				// }
			}, 
			getScrollInfo(e){
				// console.log('滚动信息：',e.detail)
			},
			scrollToBottom(callback=()=>{},$from='',$time=300) {
				let that = this;
				const query = uni.createSelectorQuery().in(this);
				setTimeout(() => {
					query.select(".chatBox").boundingClientRect(res => {
						that.$nextTick(()=>{
							if (res) {
								let newHeight = res.height;
								if (newHeight === that.previousHeight) {
										newHeight += 1;
								}
								that.previousHeight = newHeight; 
								if ($from == 100) {
										that.stesttest = newHeight + 41;
								} else if ($from == 100) {
										that.stesttest = newHeight + 42;
								} else {
										that.stesttest = newHeight + 40;
								}
							} else {
								that.previousHeight = 0;
							}
							// console.log('滚动动画：',that.stesttest, '备注：',$from,' 延迟：',$time)
							callback();
						})
					}).exec();
				}, $time);
			},
			handleUpdateGood($item, $tip) {
				if ($tip == "good") {
					if ($item.isGood) {
						$item.isGood = false;
					} else {
						$item.isGood = true;
					}
				} else {
					if ($item.isDown) {
						$item.isDown = false;
					} else {
						$item.isDown = true;
					}
				}
				this.animate();
			},
			handleClickCopy($content = "") {
				let that = this;
				uni.setClipboardData({
					data: $content,
					success: () => {},
					fail: (err) => {},
				});
				that.animate();
			},
			handleUpdateMsgType() {
				let that = this;
				that.form = '';
				this.animate();
				if (this.msgType == "text") {
					this.msgType = "voice";
					this.checkRecordingPermission();
				} else {
					this.msgType = "text";
				}
				that.writeStyle = `bottom:0`
				that.wh = `calc(${uni.getSystemInfoSync().windowHeight}px - ${this.bottomHeight}px)`
			},
			handleNextMsg($type=0){
				let that = this;
				if($type == 0){
					that.stopCore(' 流式 取消会话');
				}
				// 取消会话
				that.coziCancelChat((res)=>{
					if(res.code == 400){
						return false
					}else{
						// 再次发送
						// that.coziChat(that.sendMsg,()=>{
						// 	that.sendMsg = '';
						// })
					}
				})
			},
			handleSendMsg() {
				let that = this;
				if (that.msgType == "voice") {
					return false;
				}
				if(that.isShowLeftLoading){
					uni.showToast({
						title:'匹配中，请稍候',
						icon:'none'
					})
					return false;
				}
				if (that.isLiuSend) {
					that.isLiuSend = false;
					that.handleNextMsg();
					return false;
				}
				if (that.sendMsg == "") {
					uni.showToast({
						icon: "none",
						title: "请输入内容",
					});
					return false;
				}
				that.animate();
				that.sendAI();
				that.writeStyle = `bottom:0`
				that.wh = `calc(${uni.getSystemInfoSync().windowHeight}px - ${this.bottomHeight}px)`
				that.$nextTick(()=>{
					that.sendMsg = "";
					that.updateTextareaHeight();
					that.textareaHeight = 30;
					that.$nextTick(()=>{
						that.textareaHeight = 30;
					})
				})
			},

			checkRecordingPermission() {
				this.recReq();
			},
			onTouchMove(e) {
				let that = this;
				if (!that.isAuth) {
					that.voiceStatus = -1;
					return false;
				}
				const touch = e.touches[0];
				let _x = touch.clientX,
					_y = touch.clientY;

				if (_y > uni.getSystemInfoSync().windowHeight - that.bottomHeight) {
					this.voiceStatus = 0;
					this.spec = true;
				} else {
					this.voiceStatus = 1;
					this.spec = false;
				}
			},

			onTouchStart() {
				let that = this;
				that.isHidden = false;
				if (!that.isAuth) {
					uni.showToast({
						icon: "none",
						title: "授权中，请稍候",
					});
					return false;
				}
				if(that.isShowLeftLoading){
					uni.showToast({
						title:'匹配中，请稍候',
						icon:'none'
					})
					return false;
				}
				if (that.isLiuSend) {
					that.isLiuSend = false;
					that.handleNextMsg();
					return false;
				}
				that.animate("heavy");
				uni.removeStorageSync('asytip');
				that.reconnectCount = 0;
				that.voiceStatus = -2;
				that.isStartRecord = false;
				that.longPressTimer = setTimeout(() => {
					that.asrClient.asr_sync_connect();
					that.isStartRecord = true;
					that.spec = true;
					that.startRecording();
				}, that.longPressDelay);
			},
			onTouchEnd() {
				let that = this;
				if (!that.isAuth) {
					that.voiceStatus = -1;
					return false;
				}
				clearTimeout(that.longPressTimer);
				if (that.isAuth) {
					const currentTime = new Date().getTime();
					const timeDiff = currentTime - that.lastClickTime;
					that.isShowRightLoading = false;
					that.rightAnimate1 = false;
					that.rightAnimate2 = false;
					if (timeDiff > 0 && timeDiff < 300) { 
						that.isFastClick = true;
					} else {
						that.isFastClick = false;
					}
					that.lastClickTime = currentTime;
					that.scrollToBottom(()=>{
						that.stopRecording();
					},'触摸离开',100)
				} else {
					uni.showToast({
						icon: "none",
						title: "授权中，请稍候",
					});
					return false;
				}
			},
			startRecording() {
				let that = this;
				setTimeout(() => {
					that.voiceStatus = 0; // 标记为正在录音
					if (!that.isFluency) {
						that.isSending = false;
						// 语音识别开始
						that.recStart();
					}
				}, 100);
			},
			stopRecording() {
				let that = this;
				that.baseEnd();
				setTimeout(
					() => {
						that.baseEnd();
					},
					that.isFluency ? 500 : 0
				);
			},
			baseEnd() {
				let that = this;
				that.voiceStatus = -1;
				if (that.isStartRecord) {
					that.recStop();
					that.isStartRecord = false;
					that.isReturn = true;
				} else {
					that.isReturn = false;
				}
				that.$forceUpdate();
			},
			sendAudioAI($msg) {
				let that = this;
				that.isHidden = false;
				if (that.isSending) {
					return;
				}
				that.isSending = true;
				that.$nextTick(()=>{
					that.scrollToBottom(()=>{
						that.voiceStatus = -1;
						that.sendBaseData($msg,'','audio');
					},'发送语音',300)
				})
			},
			sendAI($form = "", $value = "") {
				let that = this;
				that.isHidden = false;
				that.textareaHeight = 30;
				if ($form == 'msgdata') {
					that.sendBaseData(uni.getStorageSync('ls-chat-text'), $form);
				} else {
					that.sendBaseData(that.sendMsg,'','text');
				}
			},
			sendBaseData($sendMessage = "", $form = '',$msgtype='') {
				let that = this;
				uni.removeStorageSync('ls_obj')
				if ($form == 'msgdata') {
					uni.removeStorageSync('ls-chat-text')
				}
				that.isShowRightLoading = false;
				that.rightAnimate1 = false;
				that.rightAnimate2 = false;
				let currentTime = new Date(); 
				let shouldInsertNewRecord = true; 
				if (that.list.length > 0) {
						let lastItem = that.list[that.list.length - 1];
						if (lastItem.createTime) {
								let lastCreateTime = new Date(lastItem.createTime); 
								let timeDifference = (currentTime - lastCreateTime) / (1000 * 60); 
								if (timeDifference <= 5) {
									shouldInsertNewRecord = false; 
								}else{
									shouldInsertNewRecord = true; 
								}
						}else{
							shouldInsertNewRecord = false; 
						}
				}
				
				if($msgtype == 'audio'){
					that.rightPush(shouldInsertNewRecord,'','audio');
					const targetIndex = shouldInsertNewRecord ? that.list.length - 1 : that.list.length - 1;
					let index = 0;
					const typingSpeed = 88; 

					const typingInterval = setInterval(() => {
							if (index < $sendMessage.length) {
									this.$set(that.list[targetIndex], 'msg', that.list[targetIndex].msg + $sendMessage[index]);
									index++;
									this.scrollToBottom();
							} else {
									clearInterval(typingInterval);
									that.thenResult($sendMessage);
							}
					}, typingSpeed);
				}else{
					that.rightPush(shouldInsertNewRecord,$sendMessage,'text');
					that.thenResult($sendMessage);
				}
			},
			rightPush(shouldInsertNewRecord,$sendMessage,$type=''){
				let that = this;
				if($type == 'audio'){
					that.list[that.list.length - 1].msg = $sendMessage;
					that.list[that.list.length - 1].chat_type = "job";
					that.list[that.list.length - 1].robotTag = 0;
				}else{
					if (shouldInsertNewRecord) {
						that.list.push(
							{
								msg: new Date().getTime(),
								message: new Date().getTime(),
								chat_type: "",
								robotTag: 2,
							},
							{
								msg: $sendMessage,
								chat_type: "job",
								robotTag: 0,
							}
						);
					}else{
						that.list.push({
							msg: $sendMessage,
							chat_type: "job",
							robotTag: 0,
						});
					}
				}
			},
			thenResult($sendMessage=''){
				let that = this;
				that.scrollToBottom(()=>{
					that.list.push({
						msg: "",
						isGood: false,
						isDown: false,
						chat_type: "",
						robotTag: 1,
					});
					that.startLeftAnimate(()=>{});
					that.scrollToBottom(()=>{
						if (!$sendMessage) {
							return false;
						}
						that.saveHistory(0, $sendMessage, (historyData) => {
							that.list[that.list.length - 2].id = historyData.id;
							// sdk-聊天
							that.coziChat($sendMessage,()=>{
								$sendMessage = "";
							});
						},'sendmsg')
					},'发送消息',300);
				},'显示loading',100)
			},
			saveHistory(robotTag = 0, $message = "", callabck = () => {},$type='') {
				let that = this,
					  params = {
							classify: 0,
							conversationId: that.cid,
							userId: uni.getStorageSync("apply-uid"),
							agencyId: uni.getStorageSync("apply-agencyId"),
							robotTag: robotTag,
							message: $message,
							form: 'root'
						};
				if ($message) {
					that.form = '';
					if(that.endType == 'markdown'){
						params['messageType'] = 99;
						params['attr1'] = Object.entries(that.hotObj).map(([key, value]) => `${key}: '${value}'`).join(',')
						params['attr2'] = that.list[that.list.length - 1].ids;// ids
						params['attr3'] = 'jobcard'
						params['message'] = '推荐职位';
					}else{
						params['messageType'] = 97;
						params['attr3'] = '';
					}
					if($type == 'welcome'){
						params['messageType'] = 98;
					}
					params.robotId = uni.getStorageSync('robot_id')
					params.agencyId = uni.getStorageSync('apply-agencyId')
					that.G.Post(
						that.api.chat_addHistory, params,(res) => {
							that.handleRecordJobEnd();
							that.isjob = false;
							callabck(res);
						}
					);
				}
			},
			// 是否是推荐职位的最后一个
			handleRecordJobEnd(callback= ()=>{}) {
				let that = this;
				if (that.list.length > 0) {
					// 初始化所有项为 false
					that.list.forEach((item) => {
						item.isRecordJobEnd = false;
					});

					// 找到最后一个符合条件的项（chat_type 为 markdown）
					for (let i = that.list.length - 1; i >= 0; i--) {
						if (that.list[i].chat_type === 'markdown') {
							that.list[i].isRecordJobEnd = true;
							break; // 找到后退出循环
						}
					}

					callback();
				}
			},
			handleSet(str, result = "", index, time) {
				let that = this;
				that.$nextTick(()=>{
					that.isShowLeftLoading = false;
					that.animate()
					that.leftAnimate1 = false;
					that.leftAnimate2 = false;
					that.leftAnimate3 = false;
					that.sendMsg = '';
					that.$nextTick(()=>{
						that.scrollToBottom(()=>{},'handleSet方法',300);
					})
				})
			},
			getRandomElements(array, count) {
				let shuffled = array.slice();
				for (let i = shuffled.length - 1; i > 0; i--) {
					const j = Math.floor(Math.random() * (i + 1));
					[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
				}
				return shuffled.slice(0, count);
			},

			animate($type = "heavy") {
				const systemInfo = uni.getSystemInfoSync();
				if(systemInfo.platform === 'ios'){
					
				}else{
					uni.vibrateShort({
						type: $type,
						fail(err) {
							console.log("震动失败：", err);
						},
					});
				}
			},
			clearMsg() {
				this.sendMsg = "";
				setTimeout(() => {
					this.textareaHeight = 30;
				}, 100);
			},
			goHotMore($item) {
				let that = this;
				if(this.hotObj && this.hotObj['sex']){
					console.log('流程1')
					uni.navigateTo({
						url: `/root/other/channelPage?jobparams=${JSON.stringify(this.hotObj)}`,
					});
				}else{
					console.log('流程2')
					if(uni.getStorageSync('ls_obj') && JSON.parse(uni.getStorageSync('ls_obj'))){
						that.isjob = true;
						let itm = JSON.parse(uni.getStorageSync('ls_obj'));
						that.hotObj['sex'] = itm['sex'];
						that.hotObj['ageRangeStr'] = itm['ageRangeStr'];
						that.hotObj['cityName'] = itm['cityName'];
						that.hotObj['labelNames'] = itm['labelNames'];
					}else{
						console.log('流程3',$item)
						uni.navigateTo({
							url: `/root/other/channelPage`,
						});
					}
				}
			},
			getReload($item) {
				let that = this;
				that.aiPage++;
				that.list.push({
					msg: "",
					isGood: false,
					isDown: false,
					chat_type: "",
					robotTag: 1,
				});
				that.$nextTick(()=>{
					that.startLeftAnimate(()=>{
						that.scrollToBottom(()=>{
							that.list.forEach((ita,ina) => {
								ita.opbtn = 0 
							})
							that.list[that.list.length - 1].msg = $item.msg;
							that.list[that.list.length - 1].chat_type = "markdown";
							that.list[that.list.length - 1].robotTag = 1;
							that.list[that.list.length - 1].ids = $item.ids;
							that.list[that.list.length - 1].opbtn = 1;
							that.getHomeList(that.list[that.list.length - 1].ids, (hotList) => {
								that.list[that.list.length - 1].comList = [];
								that.list[that.list.length - 1].comList = hotList;
						
								let _art = [];
								if (hotList && hotList.length > 0) {
									_art = hotList.map(item => {
										return {
											'职位ID': item.id
										}
									})
								} else {
									_art = []
								}
								that.saveHistory(1, JSON.stringify(_art), (historyData) => {
									that.list[that.list.length - 1].id = $item.id;
									that.isSending = false;
									that.handleSet(JSON.stringify(_art), "", 0, 300);
								},'update');
							}, $item.page,'more')
						},'换一批',300);
					});
				})
			},
			startLeftAnimate(callback=()=>{}){
				let that = this;
				that.animate()
				that.jobnum = 0;
				that.isShowLeftLoading = true;
				setTimeout(()=>{
					that.animate()
					that.leftAnimate1 = true;
					that.scrollToBottom(()=>{
						setTimeout(()=>{
							that.animate()
							that.leftAnimate1 = false;
							console.log('endType',that.endType)
							that.jobnum = that.getRandomNumber(Math.ceil(Number(that.jobNus) / 10),Math.ceil(Number(that.jobNus) / 8));
							that.leftAnimate2 = true;
							that.scrollToBottom(()=>{
								setTimeout(()=>{
									that.jobnum = that.getRandomNumber(Math.ceil(Number(that.jobNus) / 8),Math.ceil(Number(that.jobNus) / 4));
									setTimeout(()=>{
										that.jobnum = that.getRandomNumber(Math.ceil(Number(that.jobNus) / 4),Math.ceil(Number(that.jobNus) / 2));
										setTimeout(()=>{
											that.jobnum = that.getRandomNumber(Math.ceil(Number(that.jobNus) / 2),Number(that.jobNus));
											setTimeout(()=>{
												that.animate()
												that.leftAnimate2 = false;
												that.leftAnimate3 = true;
												that.scrollToBottom(()=>{
													setTimeout(()=>{
														callback();
													},800)
												},'左3',10)
											},800)
										},400)
									},400)
								},400)
							},'左2',10)
						},800)
					},'左1',10);
				},800)
			},
			startRightAnimate(callback=()=>{}){
				let that = this;
				that.animate()
				that.isShowRightLoading = true;
				setTimeout(()=>{
					that.animate()
					that.rightAnimate1 = true;
					that.scrollToBottom(()=>{
						setTimeout(()=>{
							that.animate()
							that.rightAnimate1 = false;
							that.rightAnimate2 = true;
							that.scrollToBottom(()=>{
								setTimeout(()=>{
									callback();
								},800)
							},'右2',10)
						},800)
					},'右1',10);
				},800)
			},
			getRandomNumber(min, max) {
				return Math.floor(Math.random() * (max - min + 1)) + min;
			},
			handleLongPress($item) {
				let that = this,
				    _array = [];
				if($item.messageType == 99){
					_array = ['删除'];
				}else{
					_array = ['删除','复制']
				}
				uni.showActionSheet({
					itemList: _array,
					success: function (res) {
						if(res.tapIndex == 0){
							that.handleDelete($item);
						}else{
							that.handleCopy($item);
						}
					},
					fail: function (res) {
					}
				});
			},
			handleCopy($item){
				uni.setClipboardData({
					data: $item.msg,
					success: () => {
						uni.showToast({ title: '复制成功' });
					},
					fail: () => {
						uni.showToast({ title: '复制失败', icon: 'none' });
					}
				});
			},
			handleDelete($item){
				let that = this;
				uni.showModal({
					title: '提示',
					content: '确定要删除此条消息吗？',
					success: (res) => {
						if (res.confirm) {
							that.handleDelMsg($item);
						}else{}
					}
				});
			},
			handleDelMsg($item){
				let that = this;
				if($item.id){
					that.G.Post(
						that.api.chat_delMsg, {
							deleteAll:0,
							ids: $item.id,
							classify:$item.classify,
							conversationId: that.cid,
						},() => {
							that.list.splice(that.list.findIndex(item => item.id === $item.id), 1);
							// that.$nextTick(()=>{
							// 	that.scrollToBottom(()=>{},'删除消息',300);
							// })
						}
					)
				}else{
					uni.showToast({
						icon:'none',
						title:'请重试'
					})
				}
			}
		},
	};
</script>

<style lang="scss">
	.g_c_b {
		color: #bbb;
	}

	.p-home-chat {
		// background-color: #f5f5f5;
		min-height: 100vh;

		.g_bg_f0a {
			background-color: #fe0000;
		}

		.chat-content {
			width: calc(100% - 0px);
			margin: 0 auto;
			padding-bottom: 0px;

			.chat-left {
				padding: 0 10px;

				.msg {
					border-radius: 12px;
					line-height: 1.5;
					// letter-spacing: 1.5px;
					word-break: break-all;
					min-height: 25px;
				}
			}

			.chat-right {
				padding: 0 10px;

				.msg {
					border-radius: 12px;
					line-height: 1.5;
					// letter-spacing: 1.5px;
					word-break: break-all;
					min-height: 25px;
				}
			}
		}

		.chat-operate {
			position: fixed;
			width: 100%;
			left: 0;
			bottom: 0;
			z-index: 1;
			padding-top: 12px;
			// background-color: #f5f5f5;

			.m-input {
				width: calc(100% - 20px);
				margin: 0 auto;
				border-radius: 40px;
				height: 56px;
				font-size: 16px;
			}

			input {
				height: 56px;
			}
		}

		.optrue{
			padding-bottom: 48px;
			// padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
		}
		.opfalse{
			// padding-bottom: calc(64rpx + constant(safe-area-inset-bottom));
			padding-bottom:48px;
		}

		.btn-share {
			position: absolute;
			right: 0;
			top: 0;
			z-index: 1;
			width: 100%;
			height: 100%;
			opacity: 0;
		}

		.longpress-top-mask {
			position: fixed;
			left: 0;
			// bottom: 120px;
			width: 100vw;
			// height: 170px;
			z-index: 99;
			background-color: transparent;
			box-shadow: 0 -5px 10px rgba(245, 245, 245, 0.5);
		}

		.longpress-bottom-mask {
			position: fixed;
			left: 0;
			bottom: 0;
			width: 100vw;
			// height: 170px;
			z-index: 99;
			background-color: rgba(245, 245, 245, 0.5);
			box-shadow: 0 -5px 10px rgba(245, 245, 245, 0.5);
		}

		.longpress-bottom-down {
			position: fixed;
			left: 0;
			bottom: 0;
			width: 100vw;
			// height: 170px;
			z-index: 99;
			background-color: #3578f6;
			box-shadow: 0 -5px 10px rgba(245, 245, 245, 0.5);
		}

		@keyframes voi_animate {
			0% {
				height: 50%;
				background-color: #ffffff;
			}

			20% {
				height: 50%;
				background-color: #ffffff;
			}

			50% {
				height: 100%;
				background-color: #ffffff;
			}

			80% {
				height: 50%;
				background-color: #ffffff;
			}

			100% {
				height: 50%;
				background-color: #ffffff;
			}
		}

		.column-voice {
			width: 100%;
			height: 22px;
			overflow: hidden;
			// max-width: calc(100% - 140px);
			max-width: calc(100% - 140px);
			margin: 0 auto;

			.column-item {
				width: 3px;
				height: 100%;
				margin-left: 6px;
				border-radius: 10px;
				background-color: #ffffff;
				vertical-align: middle;
				display: inline-block;
			}
		}
	}

	/* 容器样式 */
	.loader {
		display: flex;
	}

	/* 单个点的样式 */
	.dot {
		width: 10px;
		height: 10px;
		margin: 0 2px;
		border-radius: 50%;
		background-color: #666;
		animation: dotPulse 1s infinite ease-in-out;
	}

	/* 容器样式 */
	.loades {
		display: flex;
	}

	/* 单个点的样式 */
	.dos {
		width: 10px;
		height: 10px;
		margin: 0 2px;
		border-radius: 50%;
		background-color: #fff;
		animation: dotPulse 1s infinite ease-in-out;
	}

	/* 动画定义 */
	@keyframes dotPulse {

		0%,
		80%,
		100% {
			transform: scale(0.9);
		}

		40% {
			transform: scale(1.1);
		}
	}

	/* 第二个点的延时 */
	.dot:nth-child(2) {
		animation-delay: -0.33s;
	}

	/* 第三个点的延时 */
	.dot:nth-child(3) {
		animation-delay: -0.66s;
	}

		/* 第二个点的延时 */
		.dos:nth-child(2) {
			animation-delay: -0.33s;
		}

		/* 第三个点的延时 */
		.dos:nth-child(3) {
			animation-delay: -0.66s;
		}

	.container {
		// position: relative;
		// overflow-y: auto; /* 设置滚动条 */
		// height: 100%; /* 设置容器高度 */
	}

	textarea {
		resize: none;
		/* 禁止手动调整大小 */
		overflow: hidden;
		/* 隐藏超出部分 */
		width: 100%;
		/* 设置宽度 */
	}

	.hasTopPadding {
		padding-top: 8px !important;
		box-sizing: content-box !important;
	}

	.biggerSize::after {
		content: "";
		/* display: inline-block; */
		width: 60px;
		height: 60px;
		position: absolute;
		left: 50%;
		top: 50%;
		z-index: 99;
		transform: translate(-50%, -50%);
	}

	.markgroup {
		height: 56px;
		border-bottom-left-radius: 8px;
		border-bottom-right-radius: 8px;
	}
	.g_fs_32 {
		font-size: 32px;
	}
	.mplace{
		line-height: 32px;
	}

	.g_bg_mais{
		background-color: #6a81ff;
	}
</style>