index.vue 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. <template>
  2. <div v-if="info">
  3. <!-- <div v-if="isRenaming">
  4. <input ref="rename" type="text" @blur="onInputNewNameComplete" v-model="inputData.name" />
  5. </div> -->
  6. <!-- <button @click="addNode(null)">Add Node</button> -->
  7. <el-tree
  8. :highlight-current="true"
  9. ref="sceneTree"
  10. :data="info?.navigationTrees"
  11. :expand-on-click-node="false"
  12. node-key="id"
  13. class="custom-tree"
  14. :default-expand-all="false"
  15. @node-drag-start="handleDragStart"
  16. @node-drag-enter="handleDragEnter"
  17. @node-drag-leave="handleDragLeave"
  18. @node-drag-over="handleDragOver"
  19. @node-drag-end="handleDragEnd"
  20. @node-drop="handleDrop"
  21. @node-click="handlerGroup"
  22. @node-expand="handleNodeExpand"
  23. @node-collapse="handleNodeCollapse"
  24. draggable
  25. :allow-drop="allowDrop"
  26. :allow-drag="allowDrag"
  27. >
  28. <template slot-scope="{ node, data }">
  29. <div class="tree-msg" :class="data.type == 'group' ? 'group-item' : 'image-item'">
  30. <!-- <div class="line"></div> -->
  31. <div class="tree-info">
  32. <div v-if="data.type == 'group'" class="group-info">
  33. <i v-if="data.type == 'group' && !expandedNodes.includes(data.id)" class="iconfont icon-editor_folder_off folder_collapsed"></i>
  34. <!-- 拖拽图标 -->
  35. <i ref="drag-group" class="drag-icon iconfont icon-editor_folder_off folder_collapsed"></i>
  36. <i v-if="data.type == 'group' && expandedNodes.includes(data.id)" class="iconfont icon-editor_folder_on folder_expanded"></i>
  37. <span v-if="reNameId != data.id"> {{ fixTitle(data.name) }}</span>
  38. <input
  39. ref="reNameInput"
  40. v-model.trim="data.name"
  41. @blur="onInputNewNameComplete(data)"
  42. v-if="reNameId == data.id"
  43. maxlength="50"
  44. :placeholder="$i18n.t('navigation.enter_name')"
  45. class="group-title-input"
  46. />
  47. <div v-if="reNameId != data.id && deleteId == null" class="controls-btn">
  48. <i v-if="data.type == 'group' && data.level == 0" class="iconfont icon-editor_list_add icon-add" @click.stop="addNode(data)" v-tooltip="$i18n.t('navigation.add_two_group')"> </i>
  49. <i
  50. v-if="(data.type == 'group' && data.children.length && data.children[0].type != 'group') || (data.type == 'group' && !data.children.length)"
  51. class="iconfont icon-editor_list_image icon-image"
  52. @click.stop="onRequestForAddScene(data)"
  53. v-tooltip="$i18n.t('navigation.add_pano_or_scene')"
  54. >
  55. </i>
  56. <i @click="onClickForRename(data)" class="iconfont icon-editor_list_edit icon-edit" v-tooltip="$i18n.t('navigation.rename')"> </i>
  57. <i class="iconfont icon-editor_list_delete icon-delete" v-tooltip="$i18n.t('navigation.delete')" @click.stop="onDel(node, data)"> </i>
  58. </div>
  59. </div>
  60. <div class="image-info" v-else>
  61. <div class="cover-image" ref="drag-image">
  62. <img :id="`drag_image_${data.id}`" :src="data.icon + ossImagePreviewUrlSuffix()" alt="" />
  63. </div>
  64. <div class="image-name">
  65. <div class="name-top">
  66. <span v-if="reNameId != data.id">{{ data.name }}</span>
  67. <input
  68. ref="reNameInput"
  69. v-if="reNameId == data.id"
  70. v-model.trim="inputData.name"
  71. @blur="onInputNewNameComplete(data)"
  72. maxlength="50"
  73. :placeholder="$i18n.t('navigation.enter_name')"
  74. class="group-title-input"
  75. />
  76. </div>
  77. <span class="name-bottom">
  78. {{ data.type === "pano" ? $i18n.t("navigation.pano") : $i18n.t("navigation.scene") }}
  79. </span>
  80. </div>
  81. <div v-if="reNameId != data.id && deleteId == null" class="controls-btn">
  82. <i @click="onClickForRename(data)" class="iconfont icon-editor_list_edit icon-edit" v-tooltip="$i18n.t('navigation.rename')"> </i>
  83. <i class="iconfont icon-editor_list_delete icon-delete" v-tooltip="$i18n.t('navigation.delete')" @click.stop="onDel(node, data)"> </i>
  84. </div>
  85. </div>
  86. </div>
  87. <div class="deletion-confirm-wrap">
  88. <div class="deletion-confirm" :class="deleteId == data.id ? 'show' : 'hide'" v-clickoutside="onRequestForCancelDelete" @click.stop="onConfirmDelete(node, data)">
  89. {{ $i18n.t("navigation.delete") }}
  90. </div>
  91. </div>
  92. <!-- <div class="controls-btn">
  93. <i v-if="data.type == 'group' && data.level == 0" class="iconfont icon-editor_list_add icon-add" @click.stop="addNode(data)" v-tooltip="$i18n.t('navigation.add_two_group')"> </i>
  94. <i
  95. v-if="(data.type == 'group' && data.children.length && data.children[0].type != 'group') || (data.type == 'group' && !data.children.length)"
  96. class="iconfont icon-editor_list_image icon-image"
  97. @click.stop="onRequestForAddScene(data)"
  98. v-tooltip="$i18n.t('navigation.add_pano_or_scene')"
  99. >
  100. </i>
  101. <i @click="onClickForRename(data)" class="iconfont icon-editor_list_edit icon-edit" v-tooltip="$i18n.t('navigation.rename')"> </i>
  102. <i class="iconfont icon-editor_list_delete icon-delete" v-tooltip="$i18n.t('navigation.delete')" @click.stop="() => remove(node, data)"> </i>
  103. </div> -->
  104. </div>
  105. </template>
  106. </el-tree>
  107. <!-- 选择全景图 or 场景 组件 -->
  108. <div class="dialog" style="z-index: 2000" v-if="isShowSelectionWindow">
  109. <MaterialSelector
  110. :title="$i18n.t('gather.select_material')"
  111. @cancel="isShowSelectionWindow = false"
  112. @submit="onSubmitFromMaterialSelector"
  113. :selectableType="['pano', '3D']"
  114. :initialMaterialType="'pano'"
  115. :isMultiSelection="true"
  116. />
  117. </div>
  118. </div>
  119. </template>
  120. <script>
  121. // import { VueTreeList, Tree, TreeNode } from "vue-tree-list";
  122. import { mapGetters, mapMutations } from "vuex";
  123. import SceneInGroup from "@/components/sceneInGroupInEditor.vue";
  124. import MaterialSelector from "@/components/materialSelector.vue";
  125. import { isUpgradeAdapter } from "@/utils/fixVersion";
  126. import { ossImagePreviewUrlSuffix, getRandomSid } from "@/utils/other.js";
  127. export default {
  128. components: {
  129. // VueTreeList,
  130. MaterialSelector,
  131. },
  132. computed: {
  133. ...mapGetters({
  134. info: "base/baseInfo",
  135. sceneList: "base/sceneList",
  136. currentScene: "scene/currentScene",
  137. currentSecondId: "navigation/currentSecondId",
  138. currentRootId: "navigation/currentRootId",
  139. }),
  140. rootTabIndex() {
  141. return this.info.navigationTrees.findIndex((item) => item.id == this.currentRootId) == -1 ? 0 : this.info.navigationTrees.findIndex((item) => item.id == this.currentRootId);
  142. },
  143. secondTabIndex() {
  144. return this.info.navigationTrees[this.rootTabIndex].children.findIndex((item) => item.id == this.currentSecondId) == -1
  145. ? 0
  146. : this.info.navigationTrees[this.rootTabIndex].children.findIndex((item) => item.id == this.currentSecondId);
  147. },
  148. },
  149. watch: {
  150. "info.navigationTrees": {
  151. // immediate: true,
  152. handler: function (newVal, oldVal) {
  153. if (newVal) {
  154. //赋值新数据后保存展开状态
  155. // this.$nextTick(() => {
  156. // this.newNodesMap = [];
  157. // for (let key in this.$refs.sceneTree.store.nodesMap) {
  158. // this.newNodesMap.push(this.$refs.sceneTree.store.nodesMap[key]);
  159. // }
  160. // this.nodesMap.forEach((item, index) => {
  161. // this.newNodesMap.forEach((new_item, new_index) => {
  162. // if (index == new_index) {
  163. // new_item.expanded = item.expanded;
  164. // }
  165. // });
  166. // });
  167. // this.nodesMap = this.newNodesMap;
  168. // });
  169. this.$nextTick(() => {
  170. if (Object.keys(this.nodesMap).length) {
  171. for (let n_key in this.$refs.sceneTree.store.nodesMap) {
  172. let has = false;
  173. for (let key in this.nodesMap) {
  174. if (key == n_key) {
  175. has = true;
  176. this.$refs.sceneTree.store.nodesMap[n_key].expanded = !!this.nodesMap[key].expanded;
  177. }
  178. }
  179. if (!has) {
  180. this.$refs.sceneTree.store.nodesMap[n_key].expanded = true;
  181. }
  182. }
  183. }
  184. });
  185. }
  186. },
  187. deep: true,
  188. },
  189. sceneList: {
  190. // immediate: true,
  191. handler: function (newVal, oldVal) {
  192. if (newVal) {
  193. if (this.info.firstScene) {
  194. if (!newVal.some((item) => item.id == this.info.firstScene.id || (item.sid && item.sid == this.info.firstScene.sid)) && this.currentScene.id == this.info.firstScene.id) {
  195. //如果选择的当前场景,设置了初始场景,被删除后则需要更新初始场景
  196. this.$store.commit("base/setData", { firstScene: null });
  197. }
  198. }
  199. //监听数变化更新当前列表
  200. this.$nextTick(() => {
  201. if (this.currentRootId || this.currentSecondId) {
  202. if (this.currentRootId && this.currentSecondId) {
  203. if (this.info.navigationTrees[this.rootTabIndex].children[this.secondTabIndex]) {
  204. this.$store.commit("scene/setCurrentScenesList", this.info.navigationTrees[this.rootTabIndex].children[this.secondTabIndex].children);
  205. }
  206. } else if (this.currentRootId && !this.currentSecondId) {
  207. if (this.info.navigationTrees[this.rootTabIndex]?.children.length && this.info.navigationTrees[this.rootTabIndex]?.children[0].type == "group") {
  208. this.$store.commit("navigation/setData", { currentSecondId: this.info.navigationTrees[this.rootTabIndex].children[0].id });
  209. this.$store.commit("scene/setCurrentScenesList", this.info.navigationTrees[this.rootTabIndex].children[this.secondTabIndex].children);
  210. } else {
  211. this.$store.commit("scene/setCurrentScenesList", this.info.navigationTrees[this.rootTabIndex].children);
  212. }
  213. }
  214. }
  215. });
  216. }
  217. },
  218. deep: true,
  219. },
  220. "info.firstScene": {
  221. // immediate: true,
  222. handler: function (newVal, oldVal) {
  223. if (!newVal && oldVal) {
  224. if (oldVal.id == this.currentScene.id) {
  225. console.log("设置空", oldVal, this.currentScene);
  226. this.$store.commit("scene/setCurrentScene", null);
  227. }
  228. }
  229. },
  230. deep: true,
  231. },
  232. },
  233. data() {
  234. return {
  235. inputData: null,
  236. insertTag: null,
  237. isShowSelectionWindow: false,
  238. expandedNodes: [], // 用于存储已展开节点的数组
  239. nodesMap: {},
  240. newNodesMap: [],
  241. reNameId: null,
  242. backUpName: "",
  243. deleteId: null,
  244. timer: null,
  245. };
  246. },
  247. methods: {
  248. ossImagePreviewUrlSuffix,
  249. fixTitle(name) {
  250. if (name == "默认二级分组") {
  251. name = this.$i18n.t("navigation.default_group_two");
  252. } else if (name == "一级分组") {
  253. name = this.$i18n.t("navigation.group_one");
  254. } else if (name == "二级分组") {
  255. name = this.$i18n.t("navigation.group_two");
  256. } else {
  257. // eslint-disable-next-line no-self-assign
  258. name = name;
  259. }
  260. return name;
  261. },
  262. handleNodeExpand(data, node, instance) {
  263. console.log("节点展开", data);
  264. // 当节点展开时,将其id添加到数组中
  265. this.expandedNodes.push(data.id);
  266. this.nodesMap = {};
  267. for (let key in this.$refs.sceneTree.store.nodesMap) {
  268. this.nodesMap[key] = this.$refs.sceneTree.store.nodesMap[key];
  269. }
  270. },
  271. handleNodeCollapse(data, node, instance) {
  272. console.log("节点折叠", data);
  273. // 当节点折叠时,从数组中移除其id
  274. const index = this.expandedNodes.indexOf(data.id);
  275. if (index !== -1) {
  276. this.expandedNodes.splice(index, 1);
  277. }
  278. this.nodesMap = {};
  279. for (let key in this.$refs.sceneTree.store.nodesMap) {
  280. this.nodesMap[key] = this.$refs.sceneTree.store.nodesMap[key];
  281. }
  282. },
  283. handleDragStart(node, ev) {
  284. console.log("drag start", node);
  285. if (node.data.type == "group") {
  286. ev.dataTransfer.setDragImage(this.$refs["drag-group"], -10, -18);
  287. } else {
  288. // ev.dataTransfer.setDragImage(this.$refs["drag-image"], -10, -18);
  289. let dom = document.getElementById(`drag_image_${node.data.id}`);
  290. ev.dataTransfer.setDragImage(dom, -10, -18);
  291. }
  292. },
  293. handleDragEnter(draggingNode, dropNode, ev) {
  294. console.log("tree drag enter: ", dropNode);
  295. if (!this.timer) {
  296. if (dropNode.data.type == "group" && dropNode.data.children.length && !dropNode.expanded) {
  297. this.timer = setTimeout(() => {
  298. // console.error("可以展开");
  299. dropNode.expanded = true;
  300. this.clearTimer();
  301. }, 1000);
  302. }
  303. }
  304. },
  305. clearTimer() {
  306. clearTimeout(this.timer);
  307. this.timer = null;
  308. },
  309. handleDragLeave(draggingNode, dropNode, ev) {
  310. this.clearTimer();
  311. // if (dropNode.expanded) {
  312. // dropNode.expanded = false;
  313. // }
  314. // console.log("tree drag leave: ", dropNode.data.type);
  315. },
  316. handleDragOver(draggingNode, dropNode, ev) {
  317. // console.log("tree drag over: ", dropNode.data.type);
  318. },
  319. handleDragEnd(draggingNode, dropNode, dropType, ev) {
  320. // console.log("tree drag end: ", dropNode && dropNode.data.type, dropType);
  321. this.clearTimer();
  322. this.processTreeData("drag");
  323. },
  324. handleDrop(draggingNode, dropNode, dropType, ev) {
  325. // console.log("tree drop: ", dropNode.data.type, dropType);
  326. return false;
  327. },
  328. allowDrop(draggingNode, dropNode, type) {
  329. if (draggingNode.data.type != "group") {
  330. //拖拽场景
  331. if (dropNode.level == 1) {
  332. //不允许拖拽到第一层级
  333. if (!dropNode.data.children.length || (dropNode.data.children.length && dropNode.data.children[0].type != "group")) {
  334. return type == "inner";
  335. } else {
  336. return false;
  337. }
  338. } else if (dropNode.level == 2) {
  339. //不允许拖拽到和目录同级
  340. if (dropNode.data.type == "group") {
  341. return type == "inner";
  342. }
  343. }
  344. return type == "prev" || type == "next";
  345. } else {
  346. //拖拽组
  347. if (draggingNode.level == 2 || draggingNode.level == 1) {
  348. //当拖拽的是第一第二级目录的时候,只能拖拽到第二级目录的前后,不能拖拽到2级目录的里面
  349. if (dropNode.level == 3) {
  350. return false;
  351. }
  352. if (dropNode.level == 2) {
  353. if (dropNode.data.type != "group") {
  354. if (dropNode.parent.data.children.length && dropNode.parent.data.children[0].type != "group") {
  355. return type == "prev" || type == "next";
  356. } else {
  357. return false;
  358. }
  359. } else {
  360. if (draggingNode.level == 1 && draggingNode.data.children.length && draggingNode.data.children[0].type == "group") {
  361. //禁止含有二级目录的一级目录,拖拽到其他一级目录
  362. return false;
  363. }
  364. return type == "prev" || type == "next";
  365. }
  366. } else if (dropNode.level == 1) {
  367. //禁止含有二级目录的一级目录,拖拽到其他一级目录
  368. if (draggingNode.level == 1 && draggingNode.data.children.length && draggingNode.data.children[0].type == "group") {
  369. return false;
  370. }
  371. return type == "prev" || type == "next" || type == "inner";
  372. }
  373. }
  374. }
  375. },
  376. allowDrag(draggingNode) {
  377. // console.error(draggingNode.data.name)
  378. // return draggingNode.data.name.indexOf("三级 3-2-2") === -1;
  379. return true;
  380. },
  381. handlerGroup(data, note, e) {
  382. if (data.type == "group") {
  383. // if (data.children.length) {
  384. this.$refs.sceneTree.store.nodesMap[data.id].expanded = this.insertTag ? true : !!!this.$refs.sceneTree.store.nodesMap[data.id].expanded;
  385. if (this.$refs.sceneTree.store.nodesMap[data.id].expanded) {
  386. this.handleNodeExpand(data);
  387. } else {
  388. this.handleNodeCollapse(data);
  389. }
  390. this.insertTag = null;
  391. // }
  392. }
  393. },
  394. onRequestForAddScene(item) {
  395. this.insertTag = item;
  396. this.isShowSelectionWindow = true;
  397. },
  398. onSubmitFromMaterialSelector(selected) {
  399. let changeListLength = this.insertTag.children.length || 0;
  400. let newScenes = [];
  401. let roundId = new Date().getTime();
  402. for (const item of selected) {
  403. roundId += 1;
  404. if (item.materialType === "pano") {
  405. newScenes.push({
  406. children: [],
  407. fodderId: item.id,
  408. icon: item.icon,
  409. sceneCode: item.sceneCode,
  410. name: item.name,
  411. // category: this.level === 1 ? this.groupNode.children[0].id : this.groupNode.id,
  412. type: "pano",
  413. sort: changeListLength,
  414. parentId: null,
  415. level: this.insertTag.level + 1,
  416. id: "add_" + roundId,
  417. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  418. // id: "s_" + this.$randomWord(true, 8, 8),
  419. });
  420. } else if (item.materialType === "3D") {
  421. console.log("item.num", item.num);
  422. newScenes.push({
  423. children: [],
  424. icon: item.thumb,
  425. sceneCode: item.num,
  426. name: item.sceneName,
  427. sort: changeListLength,
  428. // category: this.level === 1 ? this.groupNode.children[0].id : this.groupNode.id,
  429. type: "4dkk",
  430. level: this.insertTag.level + 1,
  431. version: isUpgradeAdapter(item.isUpgrade), // 'V3' OR 'V4'. 全景看看v1.3新增
  432. id: "add_" + roundId,
  433. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  434. // id: "s_" + this.$randomWord(true, 8, 8),
  435. // fodderId: item.id,
  436. });
  437. }
  438. changeListLength++;
  439. }
  440. let allSuccess = true;
  441. newScenes.forEach((item, i) => {
  442. // let temp = this.info.scenes.find((eachScene) => {
  443. let temp = this.sceneList.find((eachScene) => {
  444. return eachScene.sceneCode === item.sceneCode;
  445. });
  446. if (temp) {
  447. setTimeout(() => {
  448. this.$msg.message(
  449. `${item.type == "4dkk" ? this.$i18n.t("navigation.scene_name") : this.$i18n.t("navigation.pano")}${this.$i18n.t("navigation.already_exists", {
  450. msg: item.sceneTitle,
  451. })}`
  452. );
  453. }, i * 100);
  454. allSuccess = false;
  455. return;
  456. }
  457. // this.info.scenes.push(item);
  458. this.insertTag.children.push(item);
  459. });
  460. this.isShowSelectionWindow = false;
  461. if (allSuccess) {
  462. this.handlerGroup(this.insertTag);
  463. this.$msg.success(this.$i18n.t("gather.success"));
  464. }
  465. },
  466. onClickForRename(data) {
  467. // this.isRenaming = true;
  468. this.inputData = data;
  469. this.backUpName = data.name;
  470. this.reNameId = data.id;
  471. if (this.inputData.name == "默认二级分组") {
  472. this.inputData.name = this.$i18n.t("navigation.default_group_two");
  473. } else if (this.inputData.name == "一级分组") {
  474. this.inputData.name = this.$i18n.t("navigation.group_one");
  475. } else if (this.inputData.name == "二级分组") {
  476. this.inputData.name = this.$i18n.t("navigation.group_two");
  477. } else {
  478. // this.inputData .name = data.name;
  479. }
  480. this.$nextTick(() => {
  481. this.$refs.reNameInput.focus();
  482. });
  483. // this.$nextTick(() => {
  484. // // this.$refs['input-for-rename'].focus()
  485. // this.$refs["input-for-rename"].select();
  486. // this.$refs["input-for-rename"].scrollIntoView({
  487. // behavior: "smooth",
  488. // });
  489. // });
  490. },
  491. onInputNewNameComplete(data) {
  492. if (this.inputData.name.trim() == "") {
  493. // data.name = this.backUpName;
  494. // data.name = data.name;
  495. this.reNameId = null;
  496. return;
  497. }
  498. let name = "";
  499. if (this.inputData.name == this.$i18n.t("navigation.default_group_two")) {
  500. name = "默认二级分组";
  501. } else if (this.inputData.name == this.$i18n.t("navigation.group_one")) {
  502. this.inputData.name = this.$i18n.t("navigation.group_one");
  503. name = "一级分组";
  504. } else if (this.inputData.name == this.$i18n.t("navigation.group_two")) {
  505. this.inputData.name = this.$i18n.t("navigation.group_two");
  506. name = "二级分组";
  507. } else {
  508. name = this.inputData.name;
  509. }
  510. data.name = name;
  511. this.reNameId = null;
  512. // this.isRenaming = false;
  513. // if (!this.inputData.name.trim()) {
  514. // return;
  515. // }
  516. // if (this.inputData.name !== this.groupNode.name) {
  517. // // this.$emit("renameGroup", this.groupNode.id, this.level, this.newName);
  518. // }
  519. // this.inputData = null;
  520. },
  521. onDel(node, data) {
  522. this.deleteId = data.id;
  523. },
  524. onRequestForCancelDelete() {
  525. this.deleteId = null;
  526. },
  527. onConfirmDelete(node, data) {
  528. // this.$emit("delete", this.sceneInfo.id);
  529. // this.isConfirmingDeletion = false;
  530. this.onRequestForCancelDelete();
  531. if (this.sceneList.length == 1 && data.type != "group") {
  532. this.$alert({
  533. title: this.$i18n.t("navigation.delete_init_scene"),
  534. content: this.$i18n.t("navigation.keep_one_scene"),
  535. });
  536. return;
  537. }
  538. if (this.info.navigationTrees.length == 1 && node.level == 1) {
  539. this.$alert({
  540. content: this.$i18n.t("navigation.keep_one_group"),
  541. });
  542. return;
  543. }
  544. if ((node.level == 1 || node.level == 2) && data.type == "group") {
  545. let delScenes = [];
  546. this.info.navigationTrees.forEach((item) => {
  547. item.children.forEach((s_item) => {
  548. if (s_item.type != "group" && (item.id == node.data.id || s_item.id == node.data.id)) {
  549. delScenes.push(s_item);
  550. }
  551. s_item.children.forEach((t_item) => {
  552. if (t_item.type != "group" && (item.id == node.data.id || s_item.id == node.data.id)) {
  553. delScenes.push(t_item);
  554. }
  555. });
  556. });
  557. });
  558. if (delScenes.length >= this.sceneList.length) {
  559. //如果要删除的场景大于等于 当前场景数量,则弹出提示 至少保留一个
  560. this.$alert({
  561. title: this.$i18n.t("navigation.delete_init_scene"),
  562. content: this.$i18n.t("navigation.keep_one_scene"),
  563. });
  564. return;
  565. }
  566. }
  567. const parent = node.parent;
  568. const children = parent.data.children || parent.data;
  569. const index = children.findIndex((d) => d.id === data.id);
  570. children.splice(index, 1);
  571. this.processTreeData("del");
  572. //如果删除当前选择的分组
  573. if (data.id == this.currentRootId || data.id == this.currentSecondId) {
  574. // console.error("如果删除当前选择的分组");
  575. this.$store.commit("navigation/setData", { currentRootId: null, currentSecondId: null });
  576. let firstScene = null;
  577. if (this.info.firstScene) {
  578. firstScene = this.info.firstScene;
  579. } else {
  580. // firstScene = this.info.navigationTrees[0].children[0];
  581. firstScene = this.sceneList[0];
  582. }
  583. if (!this.currentRootId && !this.currentSecondId) {
  584. // console.error("初始化");
  585. // this.$store.commit("scene/setCurrentScene", firstScene);
  586. let activeScene = null;
  587. this.info.navigationTrees.forEach((item, index) => {
  588. activeScene = item.children.find((pano) => pano.id == firstScene.id);
  589. if (activeScene) {
  590. this.$store.commit("scene/setCurrentScenesList", item.children);
  591. this.$store.commit("navigation/setData", { currentSecondId: null, currentRootId: item.id });
  592. // throw new Error("LoopTerminated");
  593. }
  594. item = item.children.forEach((s_item, s_index) => {
  595. activeScene = s_item.children.find((pano) => pano.id == firstScene.id);
  596. if (activeScene) {
  597. this.$store.commit("scene/setCurrentScenesList", s_item.children);
  598. this.$store.commit("navigation/setData", { currentSecondId: s_item.id, currentRootId: item.id });
  599. // throw new Error("LoopTerminated");
  600. }
  601. s_item = s_item.children.forEach((t_item, t_index) => {
  602. activeScene = t_item.children.find((pano) => pano.id == firstScene.id);
  603. if (activeScene) {
  604. this.$store.commit("scene/setCurrentScenesList", s_item.children);
  605. this.$store.commit("navigation/setData", { currentSecondId: s_item.id, currentRootId: item.id });
  606. // throw new Error("LoopTerminated");
  607. }
  608. });
  609. });
  610. });
  611. }
  612. }
  613. // if (parent.data.children.length == 1 && parent.data.children[0].type == "group") {
  614. // let newChild = children[0].children;
  615. // parent.data.children = newChild;
  616. // }
  617. // console.error(this.info.navigationTrees);
  618. },
  619. addNode(data) {
  620. let roundId = new Date().getTime();
  621. let group = {
  622. id: "add_" + roundId,
  623. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  624. name: data ? "二级分组" : "一级分组",
  625. type: "group",
  626. level: data ? 1 : 0,
  627. children: [],
  628. };
  629. if (data) {
  630. // if (data.children.length && data.children[0].type != "group") {
  631. // //新增子目录的时候,如果目录里面没有子目录,新增一个默认目录包含旧数据
  632. // let list = JSON.parse(JSON.stringify(data.children));
  633. // data.children = [];
  634. // let defaultDir = {
  635. // id: "add_" + (roundId + 1),
  636. // sort: 0,
  637. // name: this.$i18n.t("navigation.default_group_two"),
  638. // type: "group",
  639. // children: list,
  640. // };
  641. // data.children.push(defaultDir);
  642. // }
  643. data.children.push(group);
  644. this.$refs.sceneTree.store.nodesMap[data.id].expanded = true;
  645. } else {
  646. this.info.navigationTrees.push(group);
  647. }
  648. this.processTreeData("add");
  649. this.$nextTick(() => {
  650. this.onClickForRename(group);
  651. });
  652. },
  653. getRoundId() {
  654. return new Date().getTime();
  655. },
  656. processTreeData(type) {
  657. this.info.navigationTrees.forEach((item) => {
  658. //一级目录
  659. let panoList = item.children.filter((pano) => pano.type != "group");
  660. let groupList = item.children.filter((pano) => pano.type == "group");
  661. switch (type) {
  662. case "add":
  663. if (panoList.length && groupList.length) {
  664. //新增目录到二级目录。且二级目录只有场景的时候
  665. let list = [];
  666. let defaultDir = {
  667. id: "add_" + (this.getRoundId() + 1),
  668. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  669. sort: 0,
  670. name: "默认二级分组",
  671. type: "group",
  672. children: panoList,
  673. };
  674. list.push(defaultDir);
  675. list = list.concat(groupList);
  676. item.children = list;
  677. }
  678. if (item.children.length == 1 && item.type == "group" && !item.children[0].children.length && item.children[0].type != "pano") {
  679. //新增二级目录的时候,如果新增完只有一个二级目录,且二级目录为空,创建多一个目录,且第一个为默认二级目录
  680. let list = [];
  681. let defaultDir = {
  682. id: "add_" + (this.getRoundId() + 1),
  683. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  684. sort: 0,
  685. name: "默认二级分组",
  686. type: "group",
  687. children: [],
  688. };
  689. list.push(defaultDir);
  690. list = list.concat(groupList);
  691. item.children = list;
  692. }
  693. break;
  694. case "del":
  695. if (groupList.length == 1 && !panoList.length && groupList[0].children.length && groupList[0].name == "默认二级分组") {
  696. //当只有一个二级目录,二级目录有场景
  697. item.children = groupList[0].children;
  698. }
  699. if (groupList.length == 1 && !groupList[0].children.length) {
  700. //当只有一个二级目录,二级目录没有场景
  701. item.children = [];
  702. }
  703. break;
  704. case "drag":
  705. if (panoList.length && groupList.length) {
  706. //拖拽目录到二级目录。且二级目录只有场景的时候
  707. let list = [];
  708. let defaultDir = {
  709. id: "add_" + (this.getRoundId() + 1),
  710. sid: "sid_" + getRandomSid(), //用于修改导航之后的标识
  711. sort: 0,
  712. name: "默认二级分组",
  713. type: "group",
  714. children: panoList,
  715. };
  716. list.push(defaultDir);
  717. list = list.concat(groupList);
  718. item.children = list;
  719. }
  720. // if (groupList.length == 1 && !groupList[0].children.length) {
  721. // //当只有一个二级目录,二级目录没有场景
  722. // item.children = [];
  723. // }
  724. if (groupList.length == 1 && !panoList.length && groupList[0].children.length) {
  725. //当只有一个二级目录,二级目录有场景
  726. item.children = groupList[0].children;
  727. }
  728. break;
  729. }
  730. // if (item.id == this.currentRootId) {
  731. // console.error(groupList);
  732. // if (groupList.length) {
  733. // let index = groupList.findIndex((pano) => pano.children.length);
  734. // this.$store.commit("navigation/setData", { currentSecondId: groupList[index].id });
  735. // } else {
  736. // this.$store.commit("navigation/setData", { currentSecondId: null });
  737. // }
  738. // // let currentSecondId = item.children.find((group) => group.id == this.currentSecondId);
  739. // // console.error("currentSecondId", currentSecondId);
  740. // }
  741. });
  742. },
  743. },
  744. created() {},
  745. };
  746. </script>
  747. <style lang="less" rel="stylesheet/less" scoped>
  748. .vtl {
  749. // .vtl-drag-disabled {
  750. // background-color: #d0cfcf;
  751. // &:hover {
  752. // background-color: #d0cfcf;
  753. // }
  754. // }
  755. // .vtl-disabled {
  756. // background-color: #d0cfcf;
  757. // }
  758. }
  759. </style>
  760. <style lang="less" rel="stylesheet/less" scoped>
  761. .icon {
  762. &:hover {
  763. cursor: pointer;
  764. }
  765. }
  766. .el-tree {
  767. background: none !important;
  768. color: hsla(0, 0%, 100%, 0.6);
  769. // .folder_expanded {
  770. // display: none;
  771. // }
  772. // .is-expanded {
  773. // .folder_collapsed {
  774. // display: none;
  775. // }
  776. // .folder_expanded {
  777. // display: inline-block;
  778. // }
  779. // }
  780. .tree-msg {
  781. width: calc(100% - 24px);
  782. // min-height: 40px;
  783. color: hsla(0, 0%, 100%, 0.6);
  784. // display: flex;
  785. // align-items: center;
  786. // justify-content: space-between;
  787. padding-right: 10px;
  788. .tree-info {
  789. // display: flex;
  790. // align-items: center;
  791. // justify-content: flex-start;
  792. height: 100%;
  793. // height: 40px;
  794. // flex: 1;
  795. .group-info {
  796. display: flex;
  797. align-items: center;
  798. justify-content: flex-start;
  799. flex: 1;
  800. height: 100%;
  801. position: relative;
  802. .drag-icon {
  803. position: absolute;
  804. width: 40px;
  805. height: 40px;
  806. background: #313131;
  807. box-shadow: 0 0 4px 0 rgb(0 0 0 / 50%);
  808. border-radius: 4px;
  809. display: flex;
  810. justify-content: center;
  811. align-items: center;
  812. z-index: -1;
  813. }
  814. span {
  815. margin-left: 6px;
  816. display: inline-block;
  817. text-overflow: ellipsis;
  818. overflow: hidden;
  819. white-space: nowrap;
  820. flex: 1 1 auto;
  821. }
  822. }
  823. }
  824. .image-info {
  825. display: flex;
  826. align-items: center;
  827. // padding: 10px 0;
  828. height: 64px;
  829. // flex: 1;
  830. width: 100%;
  831. .cover-image {
  832. flex: 0 0 auto;
  833. width: 64px;
  834. height: 64px;
  835. background: #b0b0b0;
  836. border-radius: 2px;
  837. background-size: cover;
  838. img {
  839. width: 100%;
  840. height: 100%;
  841. pointer-events: none;
  842. object-fit: cover;
  843. }
  844. }
  845. .image-name {
  846. margin-left: 10px;
  847. width: calc(100% - 74px);
  848. flex: 1 1 auto;
  849. display: flex;
  850. flex-direction: column;
  851. justify-content: space-between;
  852. height: 100%;
  853. flex: 1;
  854. .name-top {
  855. width: 100%;
  856. span {
  857. width: 100%;
  858. word-break: break-all;
  859. display: -webkit-box;
  860. -webkit-box-orient: vertical;
  861. -webkit-line-clamp: 2;
  862. overflow: hidden;
  863. font-size: 14px;
  864. color: hsla(0, 0%, 100%, 0.6);
  865. white-space: normal;
  866. }
  867. }
  868. .name-bottom {
  869. color: #0076f6;
  870. }
  871. }
  872. .group-title-input {
  873. width: 100%;
  874. margin-left: 0;
  875. }
  876. }
  877. .group-title-input {
  878. margin-left: 6px;
  879. flex: 1 1 auto;
  880. width: 1px;
  881. height: 30px;
  882. background: #1a1b1d;
  883. border-radius: 2px;
  884. border: 1px solid #404040;
  885. color: #fff;
  886. font-size: 14px;
  887. padding: 0 10px 0 16px;
  888. &:focus {
  889. border-color: #0076f6;
  890. }
  891. }
  892. .deletion-confirm-wrap {
  893. position: absolute;
  894. top: 0;
  895. bottom: 0;
  896. right: 0;
  897. width: 44px;
  898. overflow: hidden;
  899. pointer-events: none;
  900. border-top-right-radius: 4px;
  901. border-bottom-right-radius: 4px;
  902. > .deletion-confirm {
  903. position: absolute;
  904. top: 0;
  905. bottom: 0;
  906. width: 100%;
  907. background: #fa5555;
  908. transition: right 0.3s;
  909. cursor: pointer;
  910. text-align: center;
  911. font-size: 12px;
  912. color: #fff;
  913. pointer-events: auto;
  914. &::after {
  915. content: "";
  916. height: 100%;
  917. vertical-align: middle;
  918. display: inline-block;
  919. }
  920. &.show {
  921. right: 0;
  922. }
  923. &.hide {
  924. right: -44px;
  925. }
  926. }
  927. }
  928. .controls-btn {
  929. display: none;
  930. > i {
  931. margin-left: 12px;
  932. cursor: pointer;
  933. &.iconfont {
  934. &:hover {
  935. color: #0076f6;
  936. }
  937. }
  938. }
  939. }
  940. &.image-item {
  941. .controls-btn {
  942. position: absolute;
  943. right: 10px;
  944. bottom: 8px;
  945. }
  946. .tree-info {
  947. display: flex;
  948. align-items: center;
  949. justify-content: flex-start;
  950. width: 100%;
  951. }
  952. }
  953. }
  954. }
  955. </style>
  956. <style lang="less">
  957. .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
  958. background: none !important;
  959. }
  960. .el-tree-node:focus > .el-tree-node__content {
  961. background: none !important;
  962. }
  963. .el-tree-node:focus > .el-tree-node__content:hover {
  964. background: #313131 !important;
  965. }
  966. .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content:hover {
  967. background: #313131 !important;
  968. }
  969. .el-tree-node__content:hover,
  970. .el-upload-list__item:hover {
  971. background: #313131;
  972. }
  973. .el-tree-node > .el-tree-node__children {
  974. overflow: inherit;
  975. }
  976. .el-tree-node__content {
  977. // height: 60px;
  978. height: auto;
  979. // padding: 10px 0;
  980. border-radius: 4px;
  981. cursor: default;
  982. }
  983. .el-tree-node__content {
  984. // padding-left: 30px !important;
  985. position: relative;
  986. &::before {
  987. content: "";
  988. width: 24px;
  989. height: 24px;
  990. display: inline-block;
  991. }
  992. &:hover {
  993. .controls-btn {
  994. display: block !important;
  995. }
  996. }
  997. }
  998. .custom-tree .el-tree__drop-indicator {
  999. // display: none
  1000. // margin-top: -25px; /* 修改间距为10px */
  1001. // margin-bottom: 10px; /* 修改间距为10px */
  1002. }
  1003. .el-tree-node__expand-icon {
  1004. // height: 44px;
  1005. display: flex;
  1006. align-items: center;
  1007. margin-right: 5px;
  1008. }
  1009. // .el-tree-node__expand-icon:hover {
  1010. // background: red;
  1011. // }
  1012. // .el-tree-node__content{
  1013. // background: red;
  1014. // }
  1015. .el-tree-node__content .el-tree-node__expand-icon {
  1016. position: absolute;
  1017. height: 100%;
  1018. // left: 6px;
  1019. }
  1020. .el-tree-node__content .el-tree-node__expand-icon:first-child + .group-item {
  1021. height: 44px;
  1022. }
  1023. .el-tree-node__content .el-tree-node__expand-icon:first-child + .image-item {
  1024. height: 80px;
  1025. }
  1026. </style>