viewlayout.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. <template src="./viewlayout.html">
  2. </template>
  3. <script>
  4. // const util = require('@/static/utils/util.js');
  5. const config = require('@/services/urlConfig.js');
  6. // import Bus from '@/common/bus';
  7. // import commonMethod from '@/common/commonMethod.js';
  8. // import requestConfig from '@/static/lib/requestConfig';
  9. // import { language } from '@/static/utils/conf.js'
  10. // const plugin = requirePlugin("WechatSI");
  11. // 获取**全局唯一**的语音识别管理器**recordRecoManager**
  12. // const manager = plugin.getRecordRecognitionManager()
  13. // import bgLoading from "@/components/bgLoading/bgLoading.vue"
  14. // import { nextTick } from "vue";
  15. // const app = getApp(); //获取应用实例
  16. // let positions = new Set();
  17. export default {
  18. data: function() {
  19. return {
  20. seedLayoutList: [],
  21. selectSeedId: null, //当前选中的种子户型id
  22. currentTranslate: {
  23. // 当前语音输入内容
  24. create: '04/27 15:37',
  25. text: '等待说话',
  26. },
  27. recording: false, // 正在录音
  28. startX:0,
  29. startY:0,
  30. clientX:0,
  31. clientY:0,
  32. defaultIndex:0,//默认选中的户型大类
  33. carefulList:[],
  34. lastSpace:null, //上一个语音操作的空间对象
  35. bigWord:"变大,放大,大一点,变宽",
  36. bigWordPY:"bianda,fangda,dayidian,biankuan",
  37. smaillWord:"变小,缩放,小一点,变窄",
  38. smaillWordPY:"bianxiao,suofang,xiaoyidian,bianzhai",
  39. changeRate:0.05, //每次变化的比例
  40. }
  41. },
  42. props: {
  43. houseList: {//当前户型所有的户型详情,可以切换
  44. type: Array,
  45. default: () => {
  46. return []
  47. }
  48. },
  49. curHouseObj: {//当前展示的户型
  50. type: Object,
  51. default: () => {
  52. return null
  53. }
  54. },
  55. overChange: {//当前选中的户型类型
  56. type: Boolean,
  57. default: false,
  58. },
  59. styleType:{
  60. type: [String, Number],
  61. default: '',
  62. }
  63. },
  64. watch: {
  65. houseList: {
  66. handler(newVal) {
  67. if (newVal) {
  68. console.warn("***houseList-change***", newVal)
  69. this.initData(newVal);
  70. }
  71. },
  72. },
  73. curHouseObj: {
  74. handler(newVal,oldVal) {
  75. if (newVal) {
  76. console.warn("***curHouseObj-CHANGE-layout***", newVal)
  77. if((oldVal && oldVal.id != newVal.id) || !oldVal){
  78. this.initSpanceData();
  79. }
  80. }
  81. },
  82. },
  83. },
  84. async mounted() {
  85. // this.getRecordAuth();//获取录音权限
  86. // this.initRecord();
  87. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  88. // currPage.updateSpanceData = this.initSpanceData;//页面注册变更方法
  89. },
  90. // 页面被展示时执行
  91. onPageShow: function() {
  92. },
  93. //页面被隐藏时执行
  94. onPageHide: function() {
  95. console.warn("***detached-hide***")
  96. },
  97. methods: {
  98. initSpanceData(){
  99. this.carefulList = [];
  100. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  101. const spaceDetail = this.curHouseObj;
  102. const spaceList = JSON.parse(spaceDetail.houseJson);
  103. spaceList && spaceList.forEach(async (item,index)=>{
  104. let curSpaceArea = parseFloat(
  105. (item.spaceWidth * item.spaceHeight) / 10000
  106. ).toFixed(1);
  107. let minArea = 0;
  108. let maxArea = 100;
  109. if(item.hasOwnProperty('spaceWidthMin') && item.hasOwnProperty('spaceHeightMin')){
  110. minArea = parseFloat((item.spaceWidthMin * item.spaceHeightMin) / 10000).toFixed(1);
  111. }
  112. if(item.hasOwnProperty('spaceWidthMax') && item.hasOwnProperty('spaceHeightMax')){
  113. maxArea = parseFloat((item.spaceWidthMax * item.spaceHeightMax) / 10000).toFixed(1);
  114. }
  115. let text = item.spaceName;
  116. if(text && !item.isSizeLock){
  117. // let res = await requestConfig("chineseToPinyin", {chinese:text},true);
  118. // let pinyin = res.single;
  119. let data = {
  120. spaceId:item.spaceId,
  121. index:this.carefulList.length,
  122. name:text,
  123. namePY:'',
  124. area:curSpaceArea,
  125. percent:null,
  126. minArea:minArea, //最小面积
  127. maxArea:maxArea, //最大面积
  128. }
  129. this.carefulList.push(data)
  130. }
  131. })
  132. console.warn("***viewlayout-init***", this.carefulList)
  133. },
  134. initData(houseList){
  135. this.seedLayoutList = [];
  136. houseList && houseList.forEach(item=>{
  137. let data = {
  138. spaceStructure: item.spaceStructure,
  139. spaceName: item.spaceName,
  140. set: false, //是否已经设置过
  141. };
  142. this.seedLayoutList.push(data);
  143. })
  144. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  145. // if(currPage.curHouseType){//获取当前页面选中的户型类型
  146. // this.selectSeedId = currPage.curHouseType
  147. // } else if(this.seedLayoutList && this.seedLayoutList[this.defaultIndex]){//默认选中第一个
  148. // this.selectSeedId = this.seedLayoutList[this.defaultIndex].spaceStructure;
  149. // }
  150. this.selectSeedId = this.seedLayoutList[this.defaultIndex].spaceStructure;
  151. if(this.selectSeedId){
  152. let item = this.seedLayoutList.find(it=>{
  153. return it.spaceStructure == this.selectSeedId
  154. })
  155. this.$emit("seedChange", item);//通知父组件-当前已经选中了户型大类
  156. let param = {
  157. type: 'CLK', //埋点类型
  158. clkId: 'clk_2cmina_23080402', //点击ID
  159. clkName: 'seedroom_clk', //点击前往的页面名称
  160. clkParams: {
  161. type: item.spaceName,
  162. locusValue: item.spaceStructure,
  163. locusName: "切换种子户型",
  164. }
  165. };
  166. // util.trackRequest(param);
  167. }
  168. console.warn("***curHouseType-init***",this.seedLayoutList)
  169. },
  170. // seedItemCheck(item) {
  171. // if (!item || !item.spaceStructure) {
  172. // return false;
  173. // }
  174. // if (item.spaceStructure == this.selectSeedId) {
  175. // return false;
  176. // }
  177. // this.selectSeedId = item.spaceStructure;
  178. // this.$emit("seedChange", item);
  179. // let param = {
  180. // type: 'CLK', //埋点类型
  181. // clkId: 'clk_2cmina_23080402', //点击ID
  182. // clkName: 'seedroom_clk', //点击前往的页面名称
  183. // clkParams: {
  184. // type: item.spaceName,
  185. // locusValue: item.spaceStructure,
  186. // locusName: "切换种子户型",
  187. // }
  188. // };
  189. // // util.trackRequest(param);
  190. // },
  191. //上划触发
  192. upCom() {
  193. console.warn("***upCom***")
  194. this.$emit("upCom");
  195. let param = {
  196. type: 'CLK', //埋点类型
  197. clkId: 'clk_2cmina_23080403', //点击ID
  198. clkName: 'adjust_clk', //点击前往的页面名称
  199. clkParams: {
  200. locusName: "精细调整",
  201. }
  202. };
  203. // util.trackRequest(param);
  204. },
  205. //获取录音权限
  206. getRecordAuth: function() {
  207. uni.getSetting({
  208. success(res) {
  209. console.log("succ")
  210. console.log(res)
  211. if (!res.authSetting['scope.record']) {
  212. uni.authorize({
  213. scope: 'scope.record',
  214. success() {
  215. // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
  216. console.log("succ auth")
  217. },
  218. fail() {
  219. console.log("fail auth")
  220. }
  221. })
  222. } else {
  223. console.log("record has been authed")
  224. }
  225. },
  226. fail(res) {
  227. console.log("fail")
  228. console.log(res)
  229. }
  230. })
  231. },
  232. //求最长公共子集
  233. findSubStr(str1, str2){
  234. if (str1.length > str2.length) {
  235. var temp = str1;
  236. str1 = str2;
  237. str2 = temp;
  238. }
  239. let len1 = str1.length;
  240. let len2 = str2.length;
  241. for (var j = len1; j > 0; j--) {
  242. for (var i = 0; i < len1 - j; i++) {
  243. var current = str1.substr(i, j);
  244. if (str2.indexOf(current) >= 0) {
  245. return current;
  246. }
  247. }
  248. }
  249. return "";
  250. },
  251. //声音变化
  252. async textChange(text) {
  253. if(this.overChange){
  254. uni.showToast({
  255. title: '请慢一点',
  256. icon: 'none',
  257. duration: 2000
  258. })
  259. return false;
  260. }
  261. let res = await requestConfig("chineseToPinyin", {chinese:text});
  262. let pinyin = res.single;
  263. console.warn("****pinyin***",pinyin)
  264. text = pinyin;
  265. //全匹配轮一遍
  266. let curSpace = this.carefulList.find(space=>{
  267. return text.includes(space.namePY)
  268. })
  269. if(!curSpace){
  270. let list = this.carefulList.map((space,index)=>{
  271. let comStr = this.findSubStr(text, space.namePY + ' ');
  272. return {
  273. spaceId:space.spaceId,
  274. namePY:space.namePY,
  275. name:space.name,
  276. comStr,
  277. index,
  278. }
  279. })
  280. //寻找5个字符串以上的
  281. let tmpList = list.filter(it=>{
  282. return it.comStr.length > 5;
  283. })
  284. if(tmpList && tmpList.length>0){
  285. tmpList.sort((a, b) => a.comStr.length - b.comStr.length);
  286. let index = tmpList[tmpList.length-1].index;//最大值在carefulList的序号
  287. curSpace = this.carefulList[index];//
  288. }else{
  289. curSpace = this.lastSpace;
  290. }
  291. }
  292. //没有找到语音操作对象
  293. if(!curSpace){
  294. uni.showToast({
  295. title: '请再说一次',
  296. icon: 'none',
  297. duration: 2000
  298. })
  299. return false;
  300. }
  301. this.lastSpace = curSpace;
  302. console.log("textChange:", curSpace,this.carefulList,text,this.bigWordPY,this.smaillWordPY);
  303. let biglist = this.bigWordPY.split(',').map(word=>{
  304. return text.lastIndexOf(word)
  305. })
  306. let smalllist = this.smaillWordPY.split(',').map(word=>{
  307. return text.lastIndexOf(word)
  308. })
  309. let a = Math.max(...biglist);
  310. let b = Math.max(...smalllist);
  311. let big = false;
  312. if(a==-1 && b==-1){//都没命中
  313. uni.showToast({
  314. title: '请再说一次',
  315. icon: 'none',
  316. duration: 2000
  317. })
  318. return false;
  319. }else if(a>-1 && b>-1){//两个都命中了
  320. if(a > b){//放大靠后-命中靠后
  321. big = true;
  322. }else{
  323. big = false;
  324. }
  325. }else if(a>-1){
  326. big = true;
  327. }
  328. let _area = parseFloat(curSpace.area) * this.changeRate;
  329. let data = {
  330. spaceId:curSpace.spaceId,
  331. area:_area,
  332. isZoomIn:big,//true 放大 false 缩放
  333. }
  334. console.log("viewlayout-发送消息-空间变化: ",data,curSpace.area,big);
  335. uni.showToast({
  336. title: '正在变化,请稍后',
  337. icon: 'none',
  338. duration: 2000
  339. })
  340. // this.sendMessageAction(JSON.stringify(parmas));
  341. this.$emit("curSpaceChange",data);//通知父组件-当前已经选中了户型大类
  342. },
  343. /**
  344. * 初始化语音识别回调
  345. * 绑定语音播放开始事件
  346. */
  347. initRecord: function() {
  348. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  349. //有新的识别内容返回,则会调用此事件
  350. manager.onRecognize = (res) => {
  351. let currentData = Object.assign({}, this.currentTranslate, {
  352. text: res.result,
  353. })
  354. this.currentTranslate = currentData;
  355. console.warn("***manager-正在录音***",this.currentTranslate)
  356. }
  357. // 识别结束事件
  358. manager.onStop = (res) => {
  359. console.warn("***manager-识别结束0***",this.recording,res)
  360. // this.textChange("客厅大一点");
  361. if(this.recording==false){//已经强制结束识别了
  362. return false;//不识别
  363. }
  364. let text = res.result
  365. if (text == '') {//识别内容为空时的反馈
  366. this.showRecordEmptyTip()
  367. return
  368. }
  369. console.warn("***manager-识别结束***",text);
  370. let param = {
  371. type: 'CLK', //埋点类型
  372. clkId: 'clk_2cmina_23080407', //点击ID
  373. clkName: 'voice_clk', //点击前往的页面名称
  374. clkParams: {
  375. locusName: "语音调整",
  376. text:text
  377. }
  378. };
  379. // util.trackRequest(param);
  380. text = text.replaceAll(/,|。/ig, "");
  381. this.textChange(text);
  382. this.stopRecordHandle();
  383. //翻译
  384. // this.translateText(currentData, this.dialogList.length)
  385. }
  386. // 识别错误事件
  387. manager.onError = (res) => {
  388. console.warn("***manager-识别错误***",this.recording,res)
  389. if(this.recording == false){
  390. return false;
  391. }
  392. this.stopRecordHandle();
  393. uni.showToast({
  394. title: '请再说一次',
  395. icon: 'none',
  396. duration: 2000
  397. })
  398. }
  399. // 语音播放开始事件
  400. uni.onBackgroundAudioPlay(res => {
  401. const backgroundAudioManager = uni.getBackgroundAudioManager()
  402. let src = backgroundAudioManager.src
  403. this.currentTranslateVoice = src;
  404. })
  405. },
  406. //执行停止录音的方法
  407. stopRecordHandle(){
  408. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  409. this.recording = false;
  410. this.$emit("streamRecordEnd");//通知父组件
  411. // currPage.voiceMaskChange(false);//关闭蒙层
  412. },
  413. //用户语音为空
  414. showRecordEmptyTip(){
  415. this.stopRecordHandle();
  416. uni.showToast({
  417. title: '告诉我您的想法',
  418. icon: 'none',
  419. duration: 2000
  420. })
  421. },
  422. catchTapEvent:function(){
  423. return false;
  424. },
  425. /**
  426. * 按住按钮开始语音识别
  427. */
  428. streamRecord: function(e) {
  429. // this.getRecordAuth();//获取录音权限
  430. console.warn("streamrecord", e)
  431. let currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  432. // let buttonItem = detail.buttonItem || {}
  433. manager.start({
  434. lang: language[0].lang_content,
  435. })
  436. // this.recordStatus = 0;
  437. this.clientX = 0;
  438. this.clientY = 0;
  439. this.startX = e.changedTouches[0].clientX;
  440. this.startY = e.changedTouches[0].clientY;
  441. this.recording = true;//录音中
  442. currPage.voiceMaskChange(true);//显示蒙层
  443. this.$emit("streamRecord");
  444. },
  445. mytouchmove(e) {
  446. let startX = this.startX // 开始x坐标
  447. let startY = this.startY //开始y坐标
  448. let touchMoveX = e.changedTouches[0].clientx //滑动变化坐标
  449. let touchMoveY = e.changedTouches[0].clientY //滑动变化坐标
  450. this.clientX = touchMoveX - startX;
  451. this.clientY = touchMoveY - startY;
  452. },
  453. angle(start,end){
  454. let _X = end.X - start.X;
  455. let _Y = end.Y - start.Y;
  456. if(_X == 0) return 90;
  457. return 360 * Math.atan((_Y / _X) / (2*Math.PI))
  458. },
  459. /**
  460. * 松开按钮结束语音识别
  461. */
  462. streamRecordEnd: function(e) {
  463. console.warn("streamRecordEnd" ,this.recording,e)
  464. // let detail = e.detail || {} // 自定义组件触发事件时提供的detail对象
  465. // let buttonItem = detail.buttonItem || {}
  466. // 防止重复触发stop函数
  467. if (this.recording==false) {
  468. console.warn("has finished!")
  469. return
  470. }
  471. let startX = this.startX; // 开始x坐标
  472. let startY = this.startY; //开始y坐标
  473. let touchMoveX = e.changedTouches[0].clientX; //滑动变化坐标
  474. let touchMoveY = e.changedTouches[0].clientY; //滑动变化坐标
  475. let angle = this.angle(
  476. {
  477. X: startX,
  478. Y: startY
  479. }, {
  480. X: touchMoveX,
  481. Y: touchMoveY
  482. })
  483. //滑动角度超过45retrun
  484. // console.log(Math.abs(angle), "Math.abs(angle)")
  485. if (Math.abs(angle) > 45){//上下滑动
  486. if (startY > touchMoveY && (startY - touchMoveY)>20) { //上滑
  487. console.warn("***touchend-上滑***",startY - touchMoveY);
  488. this.stopRecordHandle();//停止录音了
  489. manager.stop()
  490. uni.showToast({
  491. title: '识别已取消!',
  492. icon: 'none',
  493. duration: 2000
  494. })
  495. }else{
  496. this.stopRecordHandle();//停止录音了
  497. manager.stop()
  498. console.warn("streamRecordEnd-stop1" ,this.recording)
  499. }
  500. }else{
  501. this.stopRecordHandle();//停止录音了
  502. manager.stop();
  503. console.warn("streamRecordEnd-stop2" ,this.recording)
  504. }
  505. },
  506. }
  507. }
  508. </script>
  509. <style lang="css" scoped>
  510. @import "./viewlayout.css";
  511. /* @import "@/common/css/common.css"; */
  512. </style>