viewlayout.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. <template src="./viewlayout.html">
  2. </template>
  3. <script>
  4. const util = require('@/utils/util.js').default;
  5. const config = require('@/services/urlConfig.js');
  6. import {
  7. Toast
  8. } from 'mint-ui';
  9. // import Bus from '@/common/bus';
  10. // import commonMethod from '@/common/commonMethod.js';
  11. // import requestConfig from '@/static/lib/requestConfig';
  12. // import { language } from '@/static/utils/conf.js'
  13. // const plugin = requirePlugin("WechatSI");
  14. // 获取**全局唯一**的语音识别管理器**recordRecoManager**
  15. // const manager = plugin.getRecordRecognitionManager()
  16. // import bgLoading from "@/components/bgLoading/bgLoading.vue"
  17. // import { nextTick } from "vue";
  18. // const app = getApp(); //获取应用实例
  19. // let positions = new Set();
  20. export default {
  21. data: function() {
  22. return {
  23. seedLayoutList: [],
  24. selectSeedId: null, //当前选中的种子户型id
  25. currentTranslate: {
  26. // 当前语音输入内容
  27. create: '04/27 15:37',
  28. text: '等待说话',
  29. },
  30. recording: false, // 正在录音
  31. startX: 0,
  32. startY: 0,
  33. clientX: 0,
  34. clientY: 0,
  35. defaultIndex: 0, //默认选中的户型大类
  36. carefulList: [],
  37. lastSpace: null, //上一个语音操作的空间对象
  38. bigWord: "变大,放大,大一点,多,宽,大",
  39. bigWordPY: "bianda,fangda,dayidian,duo,kuan,da",
  40. smaillWord: "变小,缩放,小一点,小,少,窄",
  41. smaillWordPY: "bianxiao,suofang,xiaoyidian,xiao,shao,zhai",
  42. changeRate: 0.05, //每次变化的比例
  43. spaceList: [],
  44. showX: false,
  45. webAudioSpeechRecognizer: null, //语音识别的对象
  46. speechText: '', //语音识别的结果-文字
  47. recording: false, //语音识别是否开始
  48. isCanStop:false, //socket是否已经链接好了
  49. }
  50. },
  51. props: {
  52. // houseList: {//当前户型所有的户型详情,可以切换
  53. // type: Array,
  54. // default: () => {
  55. // return []
  56. // }
  57. // },
  58. curHouseObj: { //当前展示的户型
  59. type: Object,
  60. default: () => {
  61. return null
  62. }
  63. },
  64. overChange: { //当前选中的户型类型
  65. type: Boolean,
  66. default: false,
  67. },
  68. styleType: {
  69. type: [String, Number],
  70. default: '',
  71. }
  72. },
  73. watch: {
  74. // houseList: {
  75. // handler(newVal) {
  76. // if (newVal) {
  77. // console.warn("***houseList-change***", newVal)
  78. // this.initData(newVal);
  79. // }
  80. // },
  81. // },
  82. curHouseObj: {
  83. handler(newVal, oldVal) {
  84. if (newVal) {
  85. console.warn("***curHouseObj-CHANGE-layout***", newVal)
  86. // if((oldVal && oldVal.id != newVal.id) || !oldVal){
  87. // this.initSpanceData();
  88. // }
  89. const spaceDetail = newVal;
  90. this.spaceList = JSON.parse(spaceDetail.houseJson);
  91. this.initSpanceData();
  92. }
  93. },
  94. },
  95. curSpaceId: {
  96. handler(newVal, oldVal) {
  97. if (newVal) {
  98. console.warn("***curSpaceId-CHANGE-layout***", newVal)
  99. let space = this.spaceList.find(it => it.spaceId == this.curSpaceId);
  100. if (space && space.spaceType == 15) { //X空间
  101. this.showX = true;
  102. } else {
  103. this.showX = false;
  104. }
  105. }
  106. },
  107. },
  108. },
  109. computed: {
  110. curSpaceId() {
  111. return this.$store.state.curSpaceId;
  112. },
  113. },
  114. async mounted() {
  115. // this.getRecordAuth();//获取录音权限
  116. // this.initRecord();
  117. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  118. // currPage.updateSpanceData = this.initSpanceData;//页面注册变更方法
  119. },
  120. // 页面被展示时执行
  121. onPageShow: function() {
  122. },
  123. //页面被隐藏时执行
  124. onPageHide: function() {
  125. console.warn("***detached-hide***")
  126. },
  127. methods: {
  128. initSpanceData() {
  129. this.carefulList = [];
  130. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  131. const spaceDetail = this.curHouseObj;
  132. const spaceList = JSON.parse(spaceDetail.houseJson);
  133. spaceList && spaceList.forEach(async (item, index) => {
  134. let curSpaceArea = parseFloat(
  135. (item.spaceWidth * item.spaceHeight) / 10000
  136. ).toFixed(1);
  137. let minArea = 0;
  138. let maxArea = 100;
  139. if (item.hasOwnProperty('spaceWidthMin') && item.hasOwnProperty('spaceHeightMin')) {
  140. minArea = parseFloat((item.spaceWidthMin * item.spaceHeightMin) / 10000).toFixed(1);
  141. }
  142. if (item.hasOwnProperty('spaceWidthMax') && item.hasOwnProperty('spaceHeightMax')) {
  143. maxArea = parseFloat((item.spaceWidthMax * item.spaceHeightMax) / 10000).toFixed(1);
  144. }
  145. let text = item.spaceName;
  146. if (text && !item.isSizeLock) {
  147. let res = await requestConfig("chineseToPinyin", {
  148. chinese: text
  149. }, true);
  150. let pinyin = res.single;
  151. let data = {
  152. spaceId: item.spaceId,
  153. index: this.carefulList.length,
  154. name: text,
  155. namePY: pinyin,
  156. area: curSpaceArea,
  157. percent: null,
  158. minArea: minArea, //最小面积
  159. maxArea: maxArea, //最大面积
  160. }
  161. this.carefulList.push(data)
  162. }
  163. })
  164. console.warn("***viewlayout-init***", this.carefulList)
  165. },
  166. initData(houseList) {
  167. this.seedLayoutList = [];
  168. houseList && houseList.forEach(item => {
  169. let data = {
  170. spaceStructure: item.spaceStructure,
  171. spaceName: item.spaceName,
  172. set: false, //是否已经设置过
  173. };
  174. this.seedLayoutList.push(data);
  175. })
  176. // var currPage = getCurrentPages()[getCurrentPages().length - 1] ? getCurrentPages()[getCurrentPages().length - 1].$vm : null;
  177. // if(currPage.curHouseType){//获取当前页面选中的户型类型
  178. // this.selectSeedId = currPage.curHouseType
  179. // } else if(this.seedLayoutList && this.seedLayoutList[this.defaultIndex]){//默认选中第一个
  180. // this.selectSeedId = this.seedLayoutList[this.defaultIndex].spaceStructure;
  181. // }
  182. this.selectSeedId = this.seedLayoutList[this.defaultIndex].spaceStructure;
  183. let keyWord = this.$route.query.layer;
  184. if (keyWord) { //如果存在结构特征,则定位到该模型大类下
  185. let item = this.seedLayoutList.find(it => keyWord.includes(it.spaceName));
  186. if (item) {
  187. this.selectSeedId = item.spaceStructure;
  188. }
  189. }
  190. if (this.selectSeedId) {
  191. let item = this.seedLayoutList.find(it => {
  192. return it.spaceStructure == this.selectSeedId
  193. })
  194. this.$emit("seedChange", item); //通知父组件-当前已经选中了户型大类
  195. // let param = {
  196. // type: 'CLK', //埋点类型
  197. // clkId: 'clk_2cmina_23080402', //点击ID
  198. // clkName: 'seedroom_clk', //点击前往的页面名称
  199. // clkParams: {
  200. // type: item.spaceName,
  201. // locusValue: item.spaceStructure,
  202. // locusName: "切换种子户型",
  203. // }
  204. // };
  205. // util.trackRequest(param);
  206. }
  207. console.warn("***curHouseType-init***", this.seedLayoutList)
  208. },
  209. //打开布局
  210. openLayout(style) {
  211. console.warn("***openLayout***", style, this.curSpaceId)
  212. let space = this.spaceList.find(it => it.spaceId == this.curSpaceId);
  213. if (space && space.spaceType == 15) { //X空间
  214. this.showX = true;
  215. } else {
  216. this.showX = false;
  217. }
  218. if (style == 3) {
  219. if (this.showX) { //X空间
  220. this.$emit("changeStyle", style);
  221. } else {
  222. Toast({
  223. message: '此空间无法更改功能',
  224. });
  225. return false
  226. }
  227. } else {
  228. this.$emit("changeStyle", style);
  229. }
  230. },
  231. goRoam() {
  232. this.$parent.$refs.viewCareful.goRoam();
  233. },
  234. //求最长公共子集
  235. findSubStr(str1, str2) {
  236. if (str1.length > str2.length) {
  237. var temp = str1;
  238. str1 = str2;
  239. str2 = temp;
  240. }
  241. let len1 = str1.length;
  242. let len2 = str2.length;
  243. for (var j = len1; j > 0; j--) {
  244. for (var i = 0; i < len1 - j; i++) {
  245. var current = str1.substr(i, j);
  246. if (str2.indexOf(current) >= 0) {
  247. return current;
  248. }
  249. }
  250. }
  251. return "";
  252. },
  253. async textChange(text) {
  254. // if (this.overChange) {
  255. // Toast({
  256. // message: '请慢一点',
  257. // });
  258. // return false;
  259. // }
  260. let res = await requestConfig("chineseToPinyin", {
  261. chinese: text
  262. });
  263. let pinyin = res.single;
  264. console.warn("****pinyin***", pinyin)
  265. text = pinyin;
  266. //全匹配轮一遍
  267. let curSpace = this.carefulList.find(space => {
  268. return text.includes(space.namePY)
  269. })
  270. if (!curSpace) {
  271. let list = this.carefulList.map((space, index) => {
  272. let comStr = this.findSubStr(text, space.namePY + ' ');
  273. return {
  274. spaceId: space.spaceId,
  275. namePY: space.namePY,
  276. name: space.name,
  277. comStr,
  278. index,
  279. }
  280. })
  281. //寻找5个字符串以上的
  282. let tmpList = list.filter(it => {
  283. return it.comStr.length > 5;
  284. })
  285. if (tmpList && tmpList.length > 0) {
  286. tmpList.sort((a, b) => a.comStr.length - b.comStr.length);
  287. let index = tmpList[tmpList.length - 1].index; //最大值在carefulList的序号
  288. curSpace = this.carefulList[index]; //
  289. } else {
  290. curSpace = this.lastSpace;
  291. }
  292. }
  293. //没有找到语音操作对象
  294. if (!curSpace) {
  295. curSpace = this.carefulList.find(it=>it.spaceId == this.curSpaceId);
  296. // Toast({
  297. // message: '请再说一次',
  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. Toast({
  314. message: '请再说一次',
  315. });
  316. return false;
  317. } else if (a > -1 && b > -1) { //两个都命中了
  318. if (a > b) { //放大靠后-命中靠后
  319. big = true;
  320. } else {
  321. big = false;
  322. }
  323. } else if (a > -1) {
  324. big = true;
  325. }
  326. let _area = parseFloat(curSpace.area) * this.changeRate;
  327. let data = {
  328. spaceId: curSpace.spaceId,
  329. area: _area,
  330. isZoomIn: big, //true 放大 false 缩放
  331. }
  332. console.log("viewlayout-发送消息-空间变化: ", data, curSpace.area, big);
  333. Toast({
  334. message: '正在变化,请稍后',
  335. });
  336. // this.sendMessageAction(JSON.stringify(parmas));
  337. this.$emit("curSpaceChange", data); //通知父组件-当前已经选中了户型大类
  338. },
  339. //语音识别
  340. speechRecognizer() {
  341. this.recording = true;
  342. console.warn('speechRecognizer', this.webAudioSpeechRecognizer,this.recording)
  343. if (!this.webAudioSpeechRecognizer) {
  344. const params = {
  345. // signCallback: signCallback, // 鉴权函数,若直接使用默认鉴权函数。可不传此参数
  346. // 用户参数
  347. secretid: $config.secretId,
  348. secretkey: $config.secretKey,
  349. appid: $config.txappId,
  350. // 临时密钥参数,非必填
  351. // token: config.token,
  352. // 实时识别接口参数
  353. engine_model_type: '16k_zh', // 因为内置WebRecorder采样16k的数据,所以参数 engineModelType 需要选择16k的引擎,为 '16k_zh'
  354. // 以下为非必填参数,可跟据业务自行修改
  355. // voice_format : 1,
  356. // hotword_id : '08003a00000000000000000000000000',
  357. // needvad: 1,
  358. // filter_dirty: 1,
  359. // filter_modal: 2,
  360. // filter_punc: 0,
  361. // convert_num_mode : 1,
  362. // word_info: 2
  363. }
  364. const webAudioSpeechRecognizer = new WebAudioSpeechRecognizer(params);
  365. let resultText = '';
  366. // 开始识别
  367. webAudioSpeechRecognizer.OnRecognitionStart = (res) => {
  368. console.log('开始识别',this.recording, res);
  369. };
  370. // 一句话开始 socket链接成功了
  371. webAudioSpeechRecognizer.OnSentenceBegin = (res) => {
  372. console.log('一句话开始',this.recording, res);
  373. this.speechText = "";
  374. this.isCanStop = true;
  375. };
  376. // 识别变化时
  377. webAudioSpeechRecognizer.OnRecognitionResultChange = (res) => {
  378. console.log('识别变化时',this.recording, res);
  379. const currentText = `${resultText}${res.result.voice_text_str}`;
  380. this.speechText = currentText;
  381. };
  382. // 一句话结束
  383. webAudioSpeechRecognizer.OnSentenceEnd = (res) => {
  384. console.log('一句话结束',this.recording, res);
  385. resultText = res.result.voice_text_str;
  386. let param = {
  387. type: 'CLK', //埋点类型
  388. clkId: 'clk_2cmina_23080407', //点击ID
  389. clkName: 'voice_clk', //点击前往的页面名称
  390. clkParams: {
  391. locusName: "语音调整",
  392. text: resultText
  393. }
  394. };
  395. util.trackRequest(param);
  396. let text = resultText.replaceAll(/,|。/ig, "");
  397. this.textChange(text);
  398. this.speechText += resultText;
  399. };
  400. // 识别结束
  401. webAudioSpeechRecognizer.OnRecognitionComplete = (res) => {
  402. console.log('识别结束', res);
  403. this.recording = false; //录音结束
  404. };
  405. // 识别错误
  406. webAudioSpeechRecognizer.OnError = (res) => {
  407. console.log('识别失败', res)
  408. this.recording = false; //录音结束
  409. };
  410. this.webAudioSpeechRecognizer = webAudioSpeechRecognizer;
  411. }
  412. this.webAudioSpeechRecognizer.start();
  413. },
  414. //结束识别
  415. streamRecordEnd() {
  416. this.recording = false; //录音结束
  417. console.log('主动结束识别', this.recording,this.isCanStop)
  418. if (this.isCanStop) {//链接成功才能关闭
  419. this.webAudioSpeechRecognizer.stop();//关闭
  420. this.isCanStop = false; //已经关闭了,不能在此打开
  421. this.webAudioSpeechRecognizer = null;
  422. }
  423. },
  424. }
  425. }
  426. </script>
  427. <style lang="scss" scoped>
  428. @import "./viewlayout.scss";
  429. </style>