<template>
	<view class="maincontent contentBg">
		<!-- 文字转语音 -->
		<view v-if="Status.pageType==='Txt'">
			<view>
				<view class="importTxt fright" @click="importDoc">导入文档</view>
				<view class="clear"></view>
			</view>
			<view class="text-content">
				<view class="uni-textarea">
					<textarea class="textarea" v-model="formData.txt" placeholder-class="placehoderClass"
						placeholder="请输入要转换的文本" :auto-height="true" maxlength="100" cursor-color="#BBE600" />
				</view>
				<view class="line"></view>
				<view class="footBtn">
					<view class="fright convert" @click.stop="txtToAudio()">转换</view>
					<view class="fright audioSett" @click.stop="formData.txt=''">清空</view>
					<view class="clear"></view>
				</view>
			</view>
		</view>

		<!-- 获取到的语音信息 -->
		<view class="cEdit"
			:class="{'displayNone':(!AudioData.tempFilePath && Status.pageType!=='Txt')|| (AudioData.hexLength===0 && Status.pageType==='Txt')}">
			<view class="audioRemark">
				<view>
					<view>
						<input type="text" class="txtName" v-model="cEdit.name" placeholder="音频名称"
							placeholder-class="placehoderClass" />
					</view>
					<view>
						<text>{{cEdit.createTime}}</text>
						<text>{{getFormatSeconds(cEdit.time,true)}}</text>
					</view>
				</view>
				<view class="btnSave" v-if="Status.pageType!=='Txt'" @click.stop="uploadLuYin">保存</view>
			</view>
			<view class="slide" v-if="Status.pageType!=='Txt'">
				<view class="circle" :style="{'left':PlayProgress}"></view>
				<view class="line"></view>
				<view class="fleft">
					{{getFormatSeconds(cEdit.currTime)}}
				</view>
				<view class="fright">
					{{getFormatSeconds(cEdit.time)}}
				</view>
				<view class="clear"></view>
			</view>
			<view class="control" v-if="Status.pageType!=='Txt'">
				<view class="playControl">
					<view class="seek" @click.stop="seek(-10)">
						<image class="img" src="/static/images/common/prev.png" mode="aspectFit"></image>
					</view>
					<view class="play" @click="playToggle()">=
						<image class="img"
							:class="{'displayNone':Status.playState!=='ready' && Status.playState!=='pause'}"
							src="/static/images/common/play.png" mode="aspectFit"></image>
						<image class="img" :class="{'displayNone':!Status.playState || Status.playState!=='play'}"
							src="/static/images/common/pause.png" mode="aspectFit"></image>
					</view>
					<view class="seek" @click.stop="seek(10)">
						<image class="img" src="/static/images/common/next.png" mode="aspectFit"></image>
					</view>
				</view>
				<view class="drop" v-if="Status.pageType!=='Txt'" @click.stop="drop()">
					<uni-icons type="trash" size="30" color="#e03434"></uni-icons>
				</view>
			</view>
		</view>
		<view class="txtBtns" v-if="Status.pageType==='Txt'" :class="{'displayNone':AudioData.hexLength===0}">
			<view class="btnSave fright" @click.stop="SaveTTS()">保存</view>
			<view class="audioSett fright" @click.stop="CancelTTS">取消</view>
			<view class="clear"></view>
		</view>
		<!-- 录音的提示 -->
		<view v-if="Status.pageType==='Record'">
			<view class="tips" :class="{'displayNone':Status.isRecord || AudioData.tempFilePath}">
				点击下方红色录制按钮开始录音，吐字清晰，语句流畅
			</view>
		</view>
		<!-- 录音、选择文件操作 -->
		<view class="footer" v-if="Status.pageType!=='Txt'">
			<view class="opt">
				<view class="recording" :class="{'displayNone':Status.pageType!=='Record'}">
					<view class="recordTitle">语音录制{{Status.RecordName}}</view>
					<view class="recordName" :class="{'visibilityHidden':!formatSecondsToDHMS}">
						{{formatSecondsToDHMS?formatSecondsToDHMS:"00:00"}}
					</view>
				</view>
				<view class="btnRecord center" @click.stop="toggleRecord()"
					:class="{'displayNone':Status.pageType!=='Record'}">
					<view class="start" :class="{'active':Status.isRecord}"></view>
				</view>
				<view class="btnRemark" :class="{'displayNone':Status.pageType!=='Record'}">
					{{Status.isRecord?'录制中':'录制'}}
				</view>
				<view class="btnCheckFile center" @click.stop="checkFile()"
					:class="{'displayNone':Status.pageType!=='File'}">
					<view class="polygon center">
						<uni-icons type="plusempty" size="45" color="#ffffff99"></uni-icons>
					</view>
				</view>
			</view>
		</view>

		<!-- 自定义弹出层 -->
		<MessagePopup :visible="Status.Pop.showPop" :type="Status.Pop.popType" :bgColor="Status.Pop.bgColor"
			:borderColor="Status.Pop.borderColor" :textColor="Status.Pop.textColor"
			:buttonBgColor="Status.Pop.buttonBgColor" :buttonTextColor="Status.Pop.buttonTextColor"
			:iconUrl="Status.Pop.iconUrl" :message="Status.Pop.message" :buttonText="Status.Pop.buttonText"
			@buttonClick="HidePop" :visiblePrompt="Status.Pop.visiblePrompt" :promptTitle="Status.Pop.promptTitle"
			v-model="Status.Pop.modelValue" @closePop="closePop" :buttonCancelText="Status.Pop.buttonCancelText"
			:showCancel="Status.Pop.showCancel" @cancelPop="closePop" :showSlot="Status.Pop.showSlot">
			<view class="popup-prompt">
				<input type="text" class="popup-prompt-input" placeholder="请输入名称" v-model="cEdit.name" />
			</view>
		</MessagePopup>
		<global-loading ref="loading" />
		<xe-upload ref="XeUpload" :options="uploadOptions" @callback="handleUploadCallback"></xe-upload>
	</view>
</template>

<script>
	var eventChannel = null;
	var these = null;
	var innerAudioContext = null;
	var AudeoRecoder = null;
	var audioTime = null;
	var hexs = null;
	import request, {
		baseURL
	} from '@/utils/request';
	import {
		showLoading,
		hideLoading,
		updateLoading
	} from '@/utils/loading.js';
	import Common from '@/utils/Common.js';
	import {
		cache100JVoiceFileForBle
	} from '@/api/100J/HBY100-J.js';

	export default {
		data() {
			return {
				Status: {
					playState: '', //播放状态
					pageType: '', //页面类型，用于区分录音、选择文件、文字转语音
					pageValid: false, //页面状态，是否已销毁
					recoderIntval: null, //录音的定时器
					isRecord: false, //是否正在录音
					RecordTime: null, //已录间的时长
					ID: '',
					Pop: { //弹出框的配置
						showPop: false, //是否显示弹窗
						popType: 'custom',
						bgColor: '#383934bd',
						borderColor: '#BBE600',
						textColor: '#ffffffde',
						buttonBgColor: '#BBE600',
						buttonTextColor: '#232323DE',
						iconUrl: '',
						message: '您确定要这样做吗？',
						buttonText: '确定',
						clickEvt: '',
						visiblePrompt: false,
						promptTitle: '设备名称',
						modelValue: '',
						visibleClose: false,
						okCallback: null,
						buttonCancelText: '',
						showCancel: false,
						showSlot: false
					},
				},
				cEdit: {

					Id: "", //编号 
					name: "", //名称
					createTime: "", //创建时间
					localPath: "", //本地地址
					webPath: "", //网络地址
					statu: "", //状态,是否公开
					isApply: "", //是否使用中
					time: "", //音频总长度
					currTime: '', //当前播放进度
					type: ''
				},
				AudioData: {
					tempFilePath: '',
					hexLength: 0
				},
				uploadOptions: {

				},
				formData: {
					txt: '祝我暴富，发财吧'
				}
			}
		},

		computed: {
			formatSecondsToDHMS() {
				let seconds = this.Status.RecordTime;

				return this.getFormatSeconds(seconds);

			},
			PlayProgress() {
				return this.cEdit.currTime / (this.cEdit.time === 0 ? 1 : this.cEdit.time) * 100 + '%';
			}
		},
		onLoad(opt) {
			eventChannel = this.getOpenerEventChannel();
			these = this;
			this.Status.pageType = opt.pageType;
			console.log('id:', opt.id); // 输出：123
			these.Status.ID = opt.id
			let title = ""
			if (opt.pageType === 'Record') {
				title = "录制语音";
			} else if (opt.pageType === 'Txt') {
				title = '文字转语音';
			} else {
				title = "文件上传";
			}
			uni.setNavigationBarTitle({
				title: title
			});
		},
		onUnload() {
			this.destoryAudioPlayer();
			clearInterval(audioTime);
			eventChannel.emit('RecordOver', {
				data: '从音频页面返回,刷新数据'
			});
		},
		onBackPress(e) {
			if (this.Status.isRecord) { //如果正在录音，提示是否放弃
				this.showMsg("正在录音,是否放弃?", false, true, () => {
					these.Status.pageValid = true;
					these.stopLuYin();
					uni.navigateBack();
				});
				return true;
			} else {
				if (this.AudioData.tempFilePath) {
					this.showMsg("录音没有保存是否放弃?", false, true, () => {
						these.Status.pageValid = true;
						this.dropTmpFile();
						this.AudioData.tempFilePath = "";
						AudeoRecoder = null;
						uni.navigateBack();
					});
					return true;
				}

			}

		},
		methods: {
			CancelTTS() {
				this.cEdit.name = '';
				this.cEdit.Id = "";
				this.cEdit.createTime = "";
				this.cEdit.currTime = "";
				this.cEdit.isApply = "";
				this.cEdit.localPath = "";
				this.cEdit.statu = "";
				this.cEdit.time = "";
				this.cEdit.webPath = "";
				this.AudioData.hexLength = 0;
				this.cEdit.type = this.Status.pageType;
				hexs = [];
			},
			SaveTTS() {
				if (!this.cEdit.name) {
					this.showMsg("请输入语音名称");
					return;
				}

				this.cEdit.localPath = "";
				this.cEdit.Id = Common.guid();
				this.cEdit.createTime = Common.DateFormat(new Date(), "yyyy年MM月dd日");
				this.cEdit.isApply = false;
				this.cEdit.statu = false;
				this.cEdit.type = this.Status.pageType;
				this.cEdit.webPath = "";

				let pro1 = new Promise((resolve, reject) => {
					uni.setStorage({
						key: Common.pcmStorageKey + "_" + this
							.cEdit.Id,
						data: hexs,
						success() {
							resolve();
						},
						fail(ex) {
							reject(ex)
						}
					});
				});
				let pro2 = new Promise((resolve, reject) => {
					let array = uni.getStorageSync(Common
						.audioStorageKey);
					if (!array) {
						array = [this.cEdit];
					} else {
						array.unshift(this.cEdit);
					}
					uni.setStorage({
						key: Common.audioStorageKey,
						data: array,
						success() {
							resolve();
						},
						fail(ex) {
							reject(ex)
						}
					});
				});
				Promise.allSettled([pro1, pro2]).then(res => {
					if (res[0].status == 'fulfilled' && res[1]
						.status == 'fulfilled') {
						updateLoading(these, {
							text: "操作成功"
						});
						this.AudioData.tempFilePath = "";
						this.Status.isRecord = false;
						uni.navigateBack();
						return;
					} else {
						updateLoading(these, {
							text: "操作没有成功"
						});

					}
					this.timeOutCloseLoad();

				}).catch(ex => {
					updateLoading(these, {
						text: "出现异常" + JSON.stringify(ex)
					});
					this.timeOutCloseLoad();
				});

			},
			importDoc() {
				this.checkFile();
			},
			txtToAudio() {
				let msg = "";
				if (!this.formData.txt) {
					msg = '请输入语音内容';
				}
				if (this.formData.txt.length > 100) {
					msg = "内容限制在100字以内";
				}
				if (msg) {
					this.showMsg(msg);
					return;
				}
				hexs = [];
				this.AudioData.hexLength = 0;
				showLoading(this, {
					text: '正在生成语音'
				});

				let closeWaiting = () => {
					setTimeout(() => {
						hideLoading(this);
					}, 2000)
				}
				let task = () => {
					return new Promise((succ, err) => {
						request({
							url: "/app/video/ttsToOss",
							method: 'post',
							data: {
								deviceId: these.Status.ID,
								text: this.formData.txt
							}
						}).then(res => {
							if (res && res.code && res.code === 200) {
								succ(res.data);
								console.log('这是成功了吗');
								uni.navigateBack()
							} else {
								err(res);
							}
						}).catch(ex => {
							console.error("出现异常", ex);
							err(res);
						});
					})
				}
				task().then(res => {
					try {
						console.log("文本转语音成功", res);
						hexs = res;
						this.AudioData.hexLength = hexs.length;
						this.AudioData.tempFilePath = "";
						this.cEdit.localPath = "";
						this.cEdit.time = "";
						this.playInit("");
						updateLoading(this, {
							text: '文本转语音成功'
						});
					} catch (error) {
						console.error("出现错误,", error)
					}
				}).catch(ex => {
					console.error("出现异常", ex);
					updateLoading(this, {
						text: '生成失败'
					});
				}).finally(closeWaiting);
			},
			timeOutCloseLoad() {
				setTimeout(() => {
					hideLoading(these);
				}, 1200);
			},
			// 无网络时保存到本地，供蓝牙直接发送（不依赖 OSS）
			// 当前部分机型 PUBLIC_DOWNLOADS 在读取阶段会出现 requestFileSystem/resolve 长时间无回调，
			// 因此本地语音优先落到 _doc/100J_audio，后续蓝牙下发走 PRIVATE_DOC 分支更稳定。
			saveLocalForBle(filePath) {
				const deviceId = these.Status.ID;
				if (!deviceId) {
					uni.showToast({ title: '缺少设备信息，请从语音列表进入录音页', icon: 'none', duration: 2500 });
					return;
				}
				const warmCacheNow = (srcPath) => {
					if (!srcPath) return;
					// 像 HBY100 一样优先写 uni 存储：后续「使用」先读缓存，尽量不再依赖当场读文件
					cache100JVoiceFileForBle(deviceId, 'local_' + these.cEdit.Id, srcPath);
				};
				const doSave = (persistentPath) => {
					const item = {
						...these.cEdit,
						localPath: persistentPath,
						fileUrl: '',
						deviceId,
						id: 'local_' + these.cEdit.Id,
						_createTime: these.cEdit.createTime || Common.DateFormat(new Date(), "yyyy年MM月dd日"),
						_isLocal: true
					};
					const key = `100J_local_audio_${deviceId}`;
					let list = uni.getStorageSync(key) || [];
					list.unshift(item);
					uni.setStorageSync(key, list);
					these.AudioData.tempFilePath = "";
					these.Status.isRecord = false;
					// 再用持久路径补写一遍缓存（若前面已成功则覆盖同 key）
					cache100JVoiceFileForBle(deviceId, item.id, persistentPath);
					uni.navigateBack();
				};
				const toPlusUrl = (p) => {
					if (!p) return p;
					try {
						if (plus.io.convertLocalFileSystemURL) {
							const c = plus.io.convertLocalFileSystemURL(p);
							if (c) return c;
						}
					} catch (e) {}
					return p;
				};
				const copyToDocByReadWrite = (srcPath, fileName, onOk, onFail) => {
					plus.io.resolveLocalFileSystemURL(toPlusUrl(srcPath), (srcEntry) => {
						srcEntry.file((file) => {
							const reader = new plus.io.FileReader();
							reader.onloadend = (e) => {
								const buf = e.target.result;
								if (!buf || !(buf.byteLength > 0)) {
									onFail(new Error('读取录音文件为空'));
									return;
								}
								plus.io.requestFileSystem(plus.io.PRIVATE_DOC, (fs) => {
									fs.root.getDirectory('100J_audio', { create: true }, (dirEntry) => {
										dirEntry.getFile(fileName, { create: true }, (newEntry) => {
											newEntry.createWriter((writer) => {
												writer.onwrite = () => onOk();
												writer.onerror = (ex) => onFail(ex || new Error('写入失败'));
												try {
													const blob = new Blob([buf], { type: 'application/octet-stream' });
													writer.write(blob);
												} catch (wex) {
													writer.write(buf);
												}
											}, onFail);
										}, onFail);
									}, onFail);
								}, onFail);
							};
							reader.onerror = () => onFail(new Error('读取录音失败'));
							reader.readAsArrayBuffer(file);
						}, onFail);
					}, onFail);
				};
				const fallbackDocSubdir = () => {
					if (typeof plus === 'undefined' || !plus.io) {
						doSave(filePath);
						return;
					}
					const fileName = 'audio_' + (these.cEdit.Id || Date.now()) + '.mp3';
					const docRel = '_doc/100J_audio/' + fileName;
					const tryRwFallback = (reason) => {
						console.warn('[100J] saveLocalForBle 复制失败，尝试读写落盘:', reason || '');
						copyToDocByReadWrite(filePath, fileName, () => doSave(docRel), () => doSave(filePath));
					};
					plus.io.resolveLocalFileSystemURL(toPlusUrl(filePath), (entry) => {
						plus.io.resolveLocalFileSystemURL('_doc/', (docEntry) => {
							docEntry.getDirectory('100J_audio', { create: true }, (dirEntry) => {
								entry.copyTo(dirEntry, fileName, () => {
									doSave(docRel);
								}, () => { tryRwFallback('copyTo'); });
							}, () => { tryRwFallback('getDirectory'); });
						}, () => { tryRwFallback('resolve _doc'); });
					}, () => { tryRwFallback('resolve src'); });
				};
				if (typeof plus === 'undefined' || !plus.io) {
					doSave(filePath);
					return;
				}
				const rawPath = (filePath && String(filePath).trim()) || '';
				// 保存流程开始时即尝试缓存一次（通常是 _doc/uniapp_temp 源路径）
				warmCacheNow(rawPath);
				// 已是 _doc 路径时直接保存；其余路径统一转存到 _doc/100J_audio
				if (rawPath.indexOf('_doc/') === 0) {
					doSave(rawPath);
					return;
				}
				fallbackDocSubdir();
			},
			// 保存录音并上传（已修复文件格式问题）
			uploadLuYin() {
				// 文件类型验证
				if (!this.AudioData.tempFilePath) {
					this.showMsg("请先录制或选择音频文件");
					return;
				}
				// 检查文件扩展名
				const validExtensions = ['.mp3', '.wav', '.aac', '.m4a'];
				let uploadFilePath = this.AudioData.tempFilePath;
				const hasValidExtension = validExtensions.some(ext =>
					uploadFilePath.toLowerCase().endsWith(ext)
				);
				if (!hasValidExtension) {
					// 如果没有有效扩展名，添加.mp3扩展名
					uploadFilePath = uploadFilePath + '.mp3';
					console.log("自动添加.mp3扩展名，新路径:", uploadFilePath);
				}

				const startOssUpload = () => {
					console.log("上传文件路径:", uploadFilePath);
					plus.io.resolveLocalFileSystemURL(uploadFilePath, (entry) => {
						entry.getMetadata((metadata) => {
							console.log("文件大小:", metadata.size, "字节");
							console.log("文件类型验证通过");
							this.doUpload(uploadFilePath);
						}, (err) => {
							console.error("获取文件元数据失败:", err);
							this.doUpload(this.AudioData.tempFilePath);
						});
					}, (err) => {
						console.error("文件不存在或路径错误:", err);
						this.doUpload(this.AudioData.tempFilePath);
					});
				};

				// 无网络时不调 OSS，直接落本地列表，避免 uploadFile 白失败；列表里点「使用」走蓝牙下发
				uni.getNetworkType({
					success: (res) => {
						if (res.networkType === 'none') {
							this.saveLocalForBle(uploadFilePath);
							uni.showToast({
								title: '无网络，已保存到本地。请在列表连接蓝牙后点「使用」下发；有网后可再保存上传云端',
								icon: 'none',
								duration: 4000
							});
							return;
						}
						startOssUpload();
					},
					fail: () => {
						startOssUpload();
					}
				});
			},

			// 执行上传操作
			doUpload(filePath) {
				const key = `${Common.pcmStorageKey}_${this.cEdit.Id}`;
				const store = uni.getStorageInfoSync();
				if (store.keys.includes(key)) return;
				const token = uni.getStorageSync('token');
				const clientid = uni.getStorageSync('clientID');
				const these = this;
				showLoading(this, {
					text: "文件上传中"
				});
				console.log("最终上传文件路径:", filePath);
				uni.uploadFile({
					url: baseURL + "/app/video/uploadAudioToOss",
					filePath: filePath,
					name: 'file',
					header: {
						"Authorization": `Bearer ${token}`,
						"clientid": clientid
					},
					formData: {
						deviceId: these.Status.ID
					},
					success: (res) => {
						try {
							if (!res.data) {
								throw new Error('res.data is empty');
							}
							const resData = JSON.parse(res.data);
							if (resData.code === 200) {
								// 缓存本地路径，Apply 时优先用本地文件走蓝牙，避免下载失败
								const deviceId = these.Status.ID;
								if (deviceId) {
									const cacheKey = `100J_local_path_cache_${deviceId}`;
									const d = resData.data;
									const fileUrl = (d && typeof d === 'object' && d.fileUrl) || (typeof d === 'string' ? d : '');
									if (filePath) {
										let cache = uni.getStorageSync(cacheKey) || {};
										if (fileUrl) cache[fileUrl] = filePath;
										if (d && typeof d === 'object' && d.id) cache[d.id] = filePath;
										uni.setStorageSync(cacheKey, cache);
										if (d && typeof d === 'object' && d.id) {
											cache100JVoiceFileForBle(deviceId, d.id, filePath);
										}
									}
								}
								// 合并两个存储操作
								Promise.all([
									new Promise((resolve, reject) => {
										uni.setStorage({
											key,
											data: resData.data,
											success: resolve,
											fail: reject
										});
									}),
									new Promise((resolve, reject) => {
										let array = uni.getStorageSync(Common.audioStorageKey) ||
										[];
										array.unshift(these.cEdit);
										uni.setStorage({
											key: Common.audioStorageKey,
											data: array,
											success: resolve,
											fail: reject
										});
									})
								]).then(() => {
									updateLoading(these, {
										text: "操作成功"
									});
									these.AudioData.tempFilePath = "";
									these.Status.isRecord = false;
									uni.navigateBack();
								}).catch(ex => {
									updateLoading(these, {
										text: `出现异常${JSON.stringify(ex)}`
									});
									these.timeOutCloseLoad();
								});
								return;
							} else {
								console.log('上传失败:', resData.msg);
								uni.showToast({
									title: resData.msg,
									icon: 'none',
									duration: 3000
								});
								these.timeOutCloseLoad();
							}
						} catch (error) {
							uni.showToast({
								title: '服务器响应格式错误',
								icon: 'none',
								duration: 3000
							});
							these.timeOutCloseLoad();
						}
					},
					fail: (err) => {
						console.error('上传文件失败:', err);
						// 无网络时保存到本地，供蓝牙直接发送
						these.saveLocalForBle(filePath);
						uni.showToast({
							title: '网络不可用，已保存到本地，可通过蓝牙发送',
							icon: 'none',
							duration: 3000
						});
						these.timeOutCloseLoad();
					},
					complete: () => {
						console.log('上传操作完成');
					}
				});
			},

			drop() {
				this.showMsg("您确定删除该音频吗?", false, true, () => {
					these.dropTmpFile();
					this.cEdit = {
						Id: "", //编号 
						name: "", //名称
						createTime: "", //创建时间
						localPath: "", //本地地址
						webPath: "", //网络地址
						statu: "", //状态,是否公开
						isApply: "", //是否使用中
						time: "", //音频总长度
						currTime: '' //当前播放进度
					};
					this.Status.playState = "";

				})
			},
			seek(intval) { //快进快退
				let tmp = this.cEdit.currTime + intval;
				console.log("tmp=" + tmp)
				if (tmp < 0) {

					this.cEdit.currTime = 0;
					innerAudioContext.seekTo(0);
					innerAudioContext.play();
				} else if (tmp > this.cEdit.time) {
					this.cEdit.currTime = this.cEdit.time;
					innerAudioContext.seekTo(this.cEdit.time);
					innerAudioContext.stop();
					clearInterval(audioTime);
				} else {
					this.cEdit.currTime = tmp;
					innerAudioContext.seekTo(tmp);
				}
			},
			playToggle() {
				if (this.Status.playState === '') {
					this.showMsg("音频未就绪");
					return;
				}
				if (innerAudioContext) {
					if (this.Status.playState == 'play') {
						innerAudioContext.pause();
					} else {
						innerAudioContext.play();
					}
				} else {
					this.showMsg("播放器未就绪");
				}
			},
			getFormatSeconds(seconds, Ms) {
				if (!seconds) {
					return "";
				}
				let totalSeconds = Math.floor(seconds);
				let days = Math.floor(totalSeconds / 86400); // 1天=86400秒
				let remainingSeconds = totalSeconds % 86400;
				let hours = Math.floor(remainingSeconds / 3600);
				let minutes = Math.floor((remainingSeconds % 3600) / 60);
				let secs = remainingSeconds % 60;

				// 补零处理
				let paddedDays = String(days).padStart(2, '0');
				let paddedHours = String(hours).padStart(2, '0');
				let paddedMinutes = String(minutes).padStart(2, '0');
				let paddedSecs = String(secs).padStart(2, '0');
				if (Ms) {
					return `${paddedMinutes}分${paddedSecs}秒`;
				}
				return `${paddedMinutes}:${paddedSecs}`;
			},
			createAudioPlayer() {
				try {
					console.log("准备创建播放器");
					if (innerAudioContext) {
						this.destoryAudioPlayer();
						clearInterval(audioTime);
						this.cEdit.currTime = 0;
					}
					innerAudioContext = plus.audio.createPlayer({
						src: this.cEdit.localPath,
						autoplay: false,
						backgroundControl: false,
					});
					console.log('播放器创建成功');
					innerAudioContext.addEventListener('canplay', () => {
						console.log("准备就绪,可以播放了");
						this.Status.playState = 'ready';
						this.cEdit.time = innerAudioContext.getDuration();
						this.cEdit.time = Math.ceil(this.cEdit.time);
						console.log("音频长度:", this.cEdit.time);
					});
					console.log("canplay事件注册成功")
					//开始播放
					innerAudioContext.addEventListener("play", (res) => {
						if (this.Status.playState === 'ready') {
							this.cEdit.currTime = 0;
						}
						this.Status.playState = 'play';
						audioTime = setInterval(() => {
							this.cEdit.currTime += 1;
						}, 1000);
						console.log("播放中", res);
					});
					console.log("play事件注册成功")
					//播放结束 
					innerAudioContext.addEventListener("ended", (res) => {
						clearInterval(audioTime);
						this.cEdit.currTime = 0;
						this.Status.playState = 'ready';
						console.log("播放结束", res);
					});
					console.log("ended事件注册成功")
					//暂停播放
					innerAudioContext.addEventListener("pause", (res) => {
						clearInterval(audioTime);
						audioTime = null;
						this.Status.playState = 'pause';
						console.log("暂停了", res);
					});
					console.log("pause事件注册成功")
					innerAudioContext.addEventListener("seeked", (res) => {
						console.log("seek完成了", res);
					})
					console.log("seeked事件注册成功")

					innerAudioContext.addEventListener('error', ex => {
						console.log("出错了", ex)
					});
					console.log("error事件注册成功");

					this.Status.playState = 'ready';
				} catch (ex) {
					// console.error("出现错误", ex);
				}
			},
			destoryAudioPlayer() { //销毁播放器
				if (innerAudioContext) {
					innerAudioContext.close();
					console.log("播放器已销毁");
				}
			},
			handleUploadCallback(res) {
				console.log("选择文件:", res);
				if (res && res.data) {
					if (this.Status.pageType === 'File') { //文件上传
						if (res.data[0].type.indexOf('audio') > -1) {
							this.cEdit.name = res.data[0].name;
							this.playInit(res.data[0].tempFilePath);
						} else {
							this.showMsg("只能选择音频文件");
						}
						return;
					}

					if (this.Status.pageType === 'Txt') { //文字转语音
						let file = res.data[0];
						let path = file.tempFilePath;
						let type = file.type;
						if (type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
							this.parseWord(path); //docx
							return;
						}
						if (type === 'text/plain') {
							this.parseTxt(path); //txt
							return;
						}
						if (type == "application/msword") { //doc
							this.showPop({
								showPop: true, //是否显示弹窗
								popType: 'custom',
								bgColor: '#383934bd',
								borderColor: '#BBE600',
								textColor: '#ffffffde',
								buttonBgColor: '#BBE600',
								buttonTextColor: '#232323DE',
								iconUrl: '',
								message: '打开文档后请手动复制文本内容',
								buttonText: '打开',
								clickEvt: '',
								visiblePrompt: false,
								promptTitle: '',
								modelValue: '',
								visibleClose: false,
								okCallback: () => {
									this.parseDoc(path);
								},
								showSlot: false,
								buttonCancelText: '取消',
								showCancel: true,
							});

							return;
						}
						this.showMsg("只能选择.txt、.docx、.doc文档");
						return;

					}
				} else {
					console.log("未选择任何文件");
				}
			},
			parseTxt(txtPath) { //读取txt文件
				showLoading(this, {
					text: "文档读取中"
				});
				let promise = new Promise((resolve, reject) => {
					plus.io.resolveLocalFileSystemURL(
						txtPath,
						(entry) => {
							// 2. 获取文件对象
							console.log("111111");
							entry.file(
								(file) => {
									console.log("22222")
									try {
										let reader = new plus.io.FileReader();
										reader.onloadend = function(e) {
											// Get data
											console.log("读取成功:", e.target.result);
											resolve(e.target.result);
										};
										reader.onerror = function(ex) {
											console.error("err=", ex)
											reject("reader.onerror");
										}
										reader.readAsText(file);
									} catch (err) {
										console.error("err=", err);
										reject(err.message)
									}
								},
								(err) => {
									console.error('获取文件对象失败：', err);
									reject('获取文件对象失败')
								}
							);
						},
						(err) => {
							console.error('解析文件路径失败：', err);
							reject('解析文件路径失败')
						}
					);
				});

				promise.then(txt => {
					this.formData.txt = txt;
					updateLoading(this, {
						text: '读取成功'
					});
				}).catch(ex => {
					updateLoading(this, {
						text: '无法读取文档'
					});
				}).finally(() => {
					setTimeout(() => {
						hideLoading(these);
					}, 500)
				})

			},
			parseDoc(filePath) {
				uni.openDocument({
					filePath: filePath,
					fail(err) {
						these.showMsg("无法打开文档");
					}
				});
			},
			parseWord(filePath) { //读取word文件
				const token = uni.getStorageSync('token');
				const clientid = uni.getStorageSync('clientID');
				showLoading(this, {
					text: "文档读取中"
				});
				let promise = new Promise((resolve, reject) => {
					uni.uploadFile({
						url: baseURL + "/app/video/extract",
						filePath: filePath,
						name: 'file',
						header: {
							"Method": "POST",
							"Content-Type": "multipart/form-data",
							"Authorization": 'Bearer ' + token,
							"clientid": clientid
						},
						timeout: 600000,
						fail: (ex) => {
							reject('文件无法读取,请手动复制文本内容');
						},
						success: (res) => {
							if (res.statusCode === 200) {
								res = JSON.parse(res.data);
								console.log("服务器响应=", res);
								if (res && res.data) {
									these.formData.txt = res.data;
									updateLoading(this, {
										text: '读取成功'
									});
									resolve();
									return;
								}
							}

							reject('文件无法读取,请手动复制文本内容');
						},
						complete() {
							setTimeout(() => {
								hideLoading(these);
							}, 500);
						}
					});

				});

				promise.then(res => {}).catch(ex => {
					updateLoading(these, {
						text: ex
					});
					uni.openDocument({
						filePath: filePath,
						fail(err) {
							console.error("无法打开文件", err);
						}
					});
				});
			},
			checkFile() {
				this.$refs.XeUpload.upload('file');
			},
			toggleRecord() {
				if (this.Status.recoderIntval) {
					this.stopLuYin();
				} else {
					this.startLuYin();
				}
			},
			playInit(tempFilePath) {
				let task = (path) => {
					try {
						console.log("最终播放路径=", path);
						// 确保路径有.mp3扩展名
						if (path && !path.toLowerCase().endsWith('.mp3')) {
							path = path + '.mp3';
							console.log("播放路径已添加.mp3扩展名:", path);
						}
						this.AudioData.tempFilePath = path;
						this.cEdit.localPath = path;
						this.cEdit.Id = Common.guid();
						this.cEdit.createTime = Common.DateFormat(new Date(), "yyyy年MM月dd日");
						this.cEdit.isApply = false;
						this.cEdit.statu = false;
						this.cEdit.type = this.Status.pageType;
						this.cEdit.webPath = "";
						if (path) {
							this.createAudioPlayer();
						} else {
							this.cEdit.time = "";
						}
					} catch (exx) {
						console.error("playInit错误:", exx)
					}
				}

				if (tempFilePath) {
					Common.moveFileToDownloads(tempFilePath).then(res => {
						console.log("文件移动成功", res);
						task(res);
					}).catch(ex => {
						console.error("文件移动失败了", ex);
						task(tempFilePath);
					});
				} else {
					task("");
				}
			},
			startLuYin() {
				this.destoryAudioPlayer();
				if (!AudeoRecoder) {
					// #ifdef APP
					try {
						AudeoRecoder = uni.getRecorderManager();
						AudeoRecoder.onStop(function(res) {
							try {
								console.log('录音停止:' + JSON.stringify(res));
								these.AudioData = res;
								these.cEdit.time = these.Status.RecordTime;
								these.cEdit.name = "语音录制" + these.Status.RecordName;
								if (these.Status.pageValid) {
									these.dropTmpFile();
									these.Status.pageValid = false;
									AudeoRecoder = null;

								} else {

									these.playInit(these.AudioData.tempFilePath);
								}
							} catch (ex) {
								console.error("录音停止回调错误:", ex);
							}
						});
					} catch (ex) {
						console.error("获取录音管理器错误:", ex);
					}
					// #endif
				}
				let startTask = () => {
					clearInterval(this.Status.recoderIntval);
					this.Status.recoderIntval = null;
					// #ifdef APP  
					try {
						AudeoRecoder.start({
							duration: 60000,
							sampleRate: 44100,
							format: 'mp3', // 确保这里是mp3格式
							frameSize: 16,
							encodeBitRate: 192000,
							numberOfChannels: 1
						});
					} catch (error) {
						console.error("开始录音错误:", error);
					}
					// #endif
					this.Status.RecordTime = 0;
					// 确保录音文件名包含.mp3扩展名
					this.Status.RecordName = Common.DateFormat(new Date(), "yyyyMMddHHmmss") + ".mp3";
					this.AudioData.tempFilePath = "";
					this.Status.recoderIntval = setInterval(() => {
						this.Status.RecordTime += 1;
						if (this.Status.RecordTime >= 60) {
							this.toggleRecord();
						}
					}, 1000);
					this.Status.isRecord = !this.Status.isRecord;
				}
				if (this.AudioData.tempFilePath) {
					this.showMsg("当前录音未保存,您要放弃该录音吗?", false, true, () => {
						these.dropTmpFile();
						startTask();
					})
				} else {
					startTask()
				}
			},
			stopLuYin() {
				clearInterval(this.Status.recoderIntval);
				this.Status.recoderIntval = null;
				try {
					AudeoRecoder.stop();
				} catch (ex) {
					console.error("停止录音错误:", ex);
					if (!these.Status.pageValid) {
						these.AudioData.tempFilePath = "_doc/" + this.Status.RecordName;
					}
				} finally {
					this.Status.isRecord = !this.Status.isRecord;
				}
			},
			dropTmpFile() {
				//删除丢弃的文件
				// #ifdef APP
				if (!these.AudioData.tempFilePath) {
					return;
				}
				try {
					plus.io.resolveLocalFileSystemURL(these.AudioData.tempFilePath, (entry) => {
						// 确认是文件类型
						if (entry.isFile) {
							entry.remove(
								() => {
									console.log('文件删除成功');
									// 删除成功后的逻辑
									these.AudioData.tempFilePath = "";
								},
								(err) => {
									console.error('文件删除失败：', err.message);
								}
							);
						} else {
							console.error('路径指向的不是文件');
						}
					}, (err) => {
						console.error('路径解析失败：', err.message);

					});
				} catch (error) {
					console.error("删除文件异常:", error);
				}
				// #endif
			},
			closePop: function() {
				this.Status.Pop.showPop = false;

				if (this.Status.Pop.cancelCallback) {
					this.Status.Pop.cancelCallback();
				}
			},
			HidePop: function() {
				this.Status.Pop.showPop = false;
				if (this.Status.Pop.okCallback) {
					this.Status.Pop.okCallback();
				}
			},
			showPop: function(option) {
				hideLoading(this);
				let def = {
					showPop: true, //是否显示弹窗
					popType: 'custom',
					bgColor: '#383934bd',
					borderColor: '#BBE600',
					textColor: '#ffffffde',
					buttonBgColor: '#BBE600',
					buttonTextColor: '#232323DE',
					iconUrl: '',
					message: '',
					buttonText: '确定',
					clickEvt: '',
					visiblePrompt: false,
					promptTitle: '',
					modelValue: '',
					visibleClose: false,
					okCallback: null,
					showSlot: false,
					buttonCancelText: '',
					showCancel: false,
				}

				let keys = Object.keys(def);

				for (let i = 0; i < keys.length; i++) {
					let key = keys[i];
					if (key in option) {
						continue;
					}
					this.Status.Pop[key] = def[key];
				}
				if (option) {
					keys = Object.keys(option);
					for (let i = 0; i < keys.length; i++) {
						let key = keys[i];
						this.Status.Pop[key] = option[key];
					}
				}
				if (!option.borderColor) {
					option.borderColor = '#BBE600';
					option.buttonBgColor = '#BBE600';
				}
				these.Status.Pop.showPop = true;
			},
			showMsg(msg, isSucc, showCancel, okCallback) {
				if (showCancel === undefined) {
					showCancel = false;
				}
				if (okCallback === undefined) {
					okCallback = null;
				}
				let icoUrl = '/static/images/6155/DeviceDetail/uploadErr.png';
				let borderColor = "#e034344d";
				let buttonBgColor = "#E03434";
				if (isSucc) {
					icoUrl = '/static/images/common/success.png';
					borderColor = "#BBE600";
					buttonBgColor = "#BBE600";
				}
				this.showPop({
					message: msg,
					iconUrl: icoUrl,
					borderColor: borderColor,
					buttonBgColor: buttonBgColor,
					buttonText: '确定',
					okCallback: okCallback,
					showCancel: showCancel,
				});
			}
		}
	}
</script>

<style>
	.footer .opt {
		display: flex;
		flex-direction: column;
		flex-wrap: wrap;
		align-content: center;
		align-items: center;
		justify-content: flex-start;
	}

	.footer .recordTitle {
		color: rgba(255, 255, 255, 0.87);

		font-family: PingFang SC;
		font-size: 28rpx;
		font-weight: 400;
		line-height: 40rpx;
		letter-spacing: 0.14rpx;
		text-align: center;
	}

	.footer .recordName {
		color: rgba(255, 255, 255, 0.6);

		font-family: PingFang SC;
		font-size: 24rpx;
		font-weight: 400;
		line-height: 34rpx;
		letter-spacing: 0.14px;
		text-align: center;
		margin-bottom: 40rpx;
	}

	.footer .btnRecord .start {
		background: rgba(224, 52, 52, 1);
		width: 80rpx;
		height: 80rpx;
		border-radius: 50%;
	}

	.footer .btnRecord .start.active {
		border-radius: 8rpx;
		background: rgba(224, 52, 52, 1);
		width: 40rpx;
		height: 40rpx;
	}

	.footer .btnRecord {

		width: 110rpx;
		height: 110rpx;
		box-sizing: border-box;
		border: 4rpx solid rgba(255, 255, 255, 0.6);
		border-radius: 50%;
	}

	.footer .btnRemark {
		color: rgba(255, 255, 255, 0.6);
		margin-top: 20rpx;
		font-family: PingFang SC;
		font-size: 28rpx;
		font-weight: 400;
		line-height: 40rpx;
		letter-spacing: 0.14px;
		text-align: center;

	}

	.footer {
		padding-top: 60rpx;
		padding-bottom: 60rpx;
		width: 100%;

		height: auto;
		position: fixed;
		z-index: 99;
		left: 0rpx;
		bottom: 0rpx;
		border-radius: 16rpx 16rpx 0px 0px;
		background: rgba(26, 26, 26, 1);
		display: flex;
		flex-direction: column;
		flex-wrap: nowrap;
		align-content: center;
		align-items: center;
		justify-content: flex-start;
	}

	.popup-prompt {
		width: 100%;
		margin-top: 40rpx;
	}



	.popup-prompt-input {
		width: 100%;
		height: 80rpx;
		line-height: 80rpx;
		border: 1rpx solid #BBE60096;
		border-radius: 10rpx;
		padding: 0 20rpx;
		margin-bottom: 30rpx;
		font-size: 26rpx;
		box-sizing: border-box;
		text-align: left;

	}


	.tips {
		color: rgba(255, 255, 255, 0.6);

		font-family: PingFang SC;
		font-size: 28rpx;
		font-weight: 400;
		line-height: 40rpx;
		letter-spacing: 0.14rpx;
		text-align: left;
	}

	.polygon {
		width: 300rpx;
		height: 150rpx;
		background-color: #3A3A3A;
		border-radius: 10rpx;
		color: rgba(255, 255, 255, 0.6);
		;
	}

	.cEdit {
		width: 100%;
		height: auto;
		border-radius: 8px;
		background: rgba(26, 26, 26, 1);
		box-sizing: border-box;
		padding: 40rpx 30rpx
	}

	.btnSave {
		width: 130rpx;
		height: 55rpx;
		line-height: 55rpx;
		text-align: center;
		color: rgba(23, 23, 23, 1);
		font-family: PingFang SC;
		font-size: 24rpx;
		font-weight: 400;
		letter-spacing: 12rpx;
		background-color: #BBE600;
		border-radius: 180rpx;
	}

	.txtName {
		color: rgba(174, 214, 0, 1);
		border-bottom: 1rpx solid rgba(174, 214, 0, 1);
		font-family: PingFang SC;
		font-size: 32rpx;
		font-weight: 400;
		line-height: 44rpx;
		letter-spacing: 0.14px;
		text-align: left;
		margin-bottom: 10rpx;
	}

	.audioRemark {
		display: flex;
		flex-wrap: nowrap;
		align-content: center;
		align-items: center;
		justify-content: space-between;
	}

	.slide {
		padding-top: 60rpx;
		width: 100%;
		position: relative;
	}

	.slide .line {
		width: 100%;
		height: 4rpx;
		border-radius: 12rpx;
		background: rgba(106, 106, 106, 1);
	}

	.slide .circle {
		position: absolute;
		margin-top: -4rpx;
		width: 12rpx;
		height: 12rpx;
		background: rgba(234, 234, 234, 1);
		border-radius: 50%;
	}

	.control {
		width: 100%;
		padding: 40rpx;
		position: relative;
	}

	.control .playControl {
		width: 100%;
		position: absolute;
		left: 0rpx;
		bottom: 0rpx;
		z-index: 1;
		display: flex;
		flex-direction: row;
		flex-wrap: nowrap;
		align-content: center;
		align-items: center;
		justify-content: center;
	}

	.control .drop {
		position: absolute;
		z-index: 2;
		bottom: 0rpx;
		right: 0rpx;
	}

	.playControl .seek .img {
		width: 32rpx;
		height: 32rpx;
	}

	.playControl .play .img {
		width: 38rpx;
		height: 44rpx;
		margin: 0rpx 80rpx;
	}

	.input {
		border-bottom: 1rpx solid #FFFFFF;
	}

	.placehoderClass {
		color: rgba(255, 255, 255, 0.6);

		font-family: PingFang SC;
		font-size: 32rpx;
		font-weight: 400;
		line-height: 44rpx;
		letter-spacing: 0.14px;
	}

	.text-content {
		border-radius: 16rpx;
		background: rgba(26, 26, 26, 1);
		width: 100%;
		height: auto;
		box-sizing: border-box;
		padding: 20rpx;
		margin-bottom: 20rpx;
	}

	.importTxt {
		color: rgba(174, 214, 0, 1);

		font-family: PingFang SC;
		font-size: 28rpx;
		font-weight: 400;
		height: 60rpx;
		line-height: 60rpx;
		letter-spacing: 0.14px;

	}

	.textarea {
		min-height: 300rpx;

		width: 100%;
		box-sizing: border-box;
	}

	.line {
		width: 100%;
		height: 0rpx;
		border-bottom: 1rpx solid rgba(255, 255, 255, 0.36);
		margin-bottom: 20rpx;
	}

	.footBtn {
		width: 100%;

	}

	.footBtn .convert {
		/* 组合 99 */
		width: 130rpx;
		height: 55rpx;
		line-height: 55rpx;
		border-radius: 180px;
		color: #232323;
		background-color: #AED600;
		text-align: center;
		font-family: PingFang SC;
		font-size: 24rpx;
		font-weight: 400;
		letter-spacing: 12rpx;
	}

	.footBtn .audioSett,
	.audioSett {
		margin-right: 50rpx;
		color: #FFFFFFDE;
		color: rgba(255, 255, 255, 0.87);

		font-family: PingFang SC;
		font-size: 28rpx;
		font-weight: 400;
		line-height: 55rpx;
		letter-spacing: 0px;
		text-align: center;
	}

	.txtBtns {
		box-sizing: border-box;
		width: 100%;
		padding: 20rpx;
	}
</style>