sceneGroupInEditor.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <template>
  2. <div class="scene-group">
  3. <div
  4. class="top-bar"
  5. :class="isConfirmingDeletion ? '' : 'show-icons-on-hover'"
  6. @click="onClickTopBar"
  7. :style="{
  8. paddingLeft: topBarPaddingLeft,
  9. }"
  10. >
  11. <i class="iconfont icon-edit_input_arrow icon-expand" :class="isExpanded ? '' : 'collapsed'"></i>
  12. <i v-show="isExpanded" class="iconfont icon-editor_folder_on folder_expalded"></i>
  13. <i v-show="!isExpanded" class="iconfont icon-editor_folder_off folder_collapsed"></i>
  14. <template v-if="!isRenaming">
  15. <span class="group-name" v-title="groupNode.name">{{groupNode.name}}</span>
  16. <i v-show="level === 1"
  17. class="iconfont icon-editor_list_add icon-add"
  18. v-tooltip="'新增二级分组'"
  19. @click="onRequestForAddGroup"
  20. >
  21. </i>
  22. <i
  23. class="iconfont icon-editor_list_image icon-image"
  24. v-tooltip="'新增全景图或三维场景'"
  25. >
  26. </i>
  27. <i
  28. class="iconfont icon-editor_list_edit icon-edit"
  29. v-tooltip="'重命名'"
  30. @click="onClickForRename"
  31. >
  32. </i>
  33. <i
  34. class="iconfont icon-editor_list_delete icon-delete"
  35. v-tooltip="'删除'"
  36. @click.stop="onRequestForDelete"
  37. >
  38. </i>
  39. <div class="deletion-confirm-wrap">
  40. <div class="deletion-confirm" :class="isConfirmingDeletion ? 'show' : 'hide'"
  41. v-clickoutside="onRequestForCancelDelete"
  42. @click.stop="onConfirmDelete"
  43. >
  44. 删除
  45. </div>
  46. </div>
  47. </template>
  48. <input v-if="isRenaming" class="group-title-input" v-model="newName"
  49. ref="input-for-rename"
  50. maxlength="50"
  51. placeholder="输入名字"
  52. @blur="onInputNewNameComplete"
  53. @keydown.enter="onInputEnter"
  54. />
  55. </div>
  56. <div class="group-content" v-if="isExpanded">
  57. <template v-if="!(groupNode.children.length === 1 && groupNode.children[0].name === '默认二级分组')">
  58. <div
  59. v-for="(item) of groupNode.children"
  60. :key=item.id
  61. >
  62. <component
  63. :is="'SceneGroup'"
  64. v-if="!item.type"
  65. :groupNode="item"
  66. :level="level + 1"
  67. @renameScene="onRenameScene"
  68. @deleteScene="onDeleteScene"
  69. @renameGroup="onInnerGroupRename"
  70. @deleteGroup="onInnerGroupConfirmDelete"
  71. />
  72. <SceneInGroupInEditor
  73. v-else
  74. :style="{
  75. paddingLeft: sceneItemPaddingLeft,
  76. }"
  77. :sceneInfo="item"
  78. @rename="onRenameScene"
  79. @delete="onDeleteScene"
  80. />
  81. </div>
  82. </template>
  83. <template v-else>
  84. <!-- 自动生成的默认二级分组不显示,里边的内容显示成直属于一级分组的效果。 -->
  85. <SceneInGroupInEditor
  86. v-for="(item) of groupNode.children[0].children"
  87. :key=item.id
  88. :style="{
  89. paddingLeft: sceneItemPaddingLeft,
  90. }"
  91. :sceneInfo="item"
  92. @rename="onRenameScene"
  93. @delete="onDeleteScene"
  94. />
  95. </template>
  96. </div>
  97. </div>
  98. </template>
  99. <script>
  100. import SceneInGroupInEditor from "@/components/sceneInGroupInEditor.vue";
  101. export default {
  102. name: 'SceneGroup',
  103. components: {
  104. SceneInGroupInEditor,
  105. },
  106. props: {
  107. groupNode: {
  108. type: Object,
  109. required: true,
  110. },
  111. level: {
  112. type: Number,
  113. default: 1,
  114. }
  115. },
  116. data() {
  117. return {
  118. isExpanded: false,
  119. isRenaming: false,
  120. newName: '',
  121. isConfirmingDeletion: false,
  122. }
  123. },
  124. computed: {
  125. topBarPaddingLeft() {
  126. return 12 + (this.level - 1) * 12 + 'px'
  127. },
  128. sceneItemPaddingLeft() {
  129. return 18 + this.level * 12 + 'px'
  130. },
  131. },
  132. methods: {
  133. onClickTopBar() {
  134. if (this.isConfirmingDeletion) {
  135. return
  136. }
  137. this.isExpanded = !this.isExpanded
  138. if (this.isExpanded) {
  139. this.$bus.emit('scene-group-expanded', this.groupNode.id, this.level)
  140. }
  141. },
  142. onOtherSceneGroupExpanded(id, level) {
  143. if (id !== this.groupNode.id && level === this.level) {
  144. this.isExpanded = false
  145. }
  146. },
  147. onRenameScene(...params) {
  148. this.$emit('renameScene', ...params)
  149. },
  150. onDeleteScene(...params) {
  151. this.$emit('deleteScene', ...params)
  152. },
  153. onRequestForAddGroup() {
  154. this.$emit('addGroup', this.groupNode.id)
  155. },
  156. onClickForRename() {
  157. this.isRenaming = true
  158. this.newName = this.groupNode.name
  159. this.$nextTick(() => {
  160. this.$refs['input-for-rename'].focus()
  161. })
  162. },
  163. onInputNewNameComplete() {
  164. this.isRenaming = false
  165. this.$emit('renameGroup', this.groupNode.id, this.level, this.newName)
  166. this.newName = ''
  167. },
  168. onInputEnter() {
  169. this.isRenaming = false // 会导致input blur,进而触发onInputNewNameComplete
  170. },
  171. onInnerGroupRename(...params) {
  172. this.$emit('renameGroup', ...params)
  173. },
  174. onRequestForDelete() {
  175. this.isConfirmingDeletion = true
  176. },
  177. onRequestForCancelDelete() {
  178. if (!this.isConfirmingDeletion) {
  179. return
  180. }
  181. // 先保持isConfirmingDeletion不变,因为onClickTopBar可能要用到
  182. setTimeout(() => {
  183. this.isConfirmingDeletion = false
  184. }, 0);
  185. },
  186. onConfirmDelete() {
  187. this.$emit('deleteGroup', this.groupNode.id, this.level)
  188. this.isConfirmingDeletion = false
  189. },
  190. onInnerGroupConfirmDelete(...params) {
  191. this.$emit('deleteGroup', ...params)
  192. }
  193. },
  194. mounted() {
  195. this.$bus.on('scene-group-expanded', this.onOtherSceneGroupExpanded)
  196. },
  197. destroyed() {
  198. this.$bus.removeListener('scene-group-expanded', this.onOtherSceneGroupExpanded)
  199. }
  200. }
  201. </script>
  202. <style lang="less" scoped>
  203. .scene-group {
  204. margin-top: 6px;
  205. .top-bar {
  206. position: relative;
  207. color: rgba(255, 255, 255, 0.6);
  208. height: 40px;
  209. border-radius: 4px;
  210. display: flex;
  211. align-items: center;
  212. margin-left: -12px;
  213. margin-right: -10px;
  214. padding-right: 10px;
  215. &:hover {
  216. background: #313131;
  217. > .group-name {
  218. width: 120px;
  219. }
  220. }
  221. &.show-icons-on-hover:hover {
  222. > .icon-add, .icon-image, .icon-edit, .icon-delete {
  223. display: block;
  224. }
  225. }
  226. > .icon-expand {
  227. display: inline-block;
  228. font-size: 12px;
  229. transform: scale(0.7);
  230. &.collapsed {
  231. display: inline-block;
  232. transform: scale(0.7) rotate(-90deg);
  233. }
  234. }
  235. > .folder_expalded {
  236. font-size: 16px;
  237. margin-left: 7px;
  238. }
  239. > .folder_collapsed {
  240. font-size: 16px;
  241. margin-left: 7px;
  242. }
  243. > .group-name {
  244. margin-left: 6px;
  245. display: inline-block;
  246. text-overflow: ellipsis;
  247. overflow: hidden;
  248. white-space: nowrap;
  249. flex: 1 1 auto;
  250. }
  251. > .icon-add {
  252. margin-left: 12px;
  253. display: none;
  254. cursor: pointer;
  255. &:hover {
  256. color: #0076f6;
  257. }
  258. }
  259. > .icon-image {
  260. margin-left: 12px;
  261. display: none;
  262. cursor: pointer;
  263. &:hover {
  264. color: #0076f6;
  265. }
  266. }
  267. > .icon-edit {
  268. margin-left: 12px;
  269. display: none;
  270. cursor: pointer;
  271. &:hover {
  272. color: #0076f6;
  273. }
  274. }
  275. > .icon-delete {
  276. margin-left: 12px;
  277. display: none;
  278. cursor: pointer;
  279. &:hover {
  280. color: #fa5555;
  281. }
  282. }
  283. > .deletion-confirm-wrap {
  284. position: absolute;
  285. top: 0;
  286. bottom: 0;
  287. right: 0;
  288. width: 44px;
  289. overflow: hidden;
  290. pointer-events: none;
  291. border-top-right-radius: 4px;
  292. border-bottom-right-radius: 4px;
  293. > .deletion-confirm {
  294. position: absolute;
  295. top: 0;
  296. bottom: 0;
  297. width: 100%;
  298. background: #FA5555;
  299. transition: right 0.3s;
  300. cursor: pointer;
  301. text-align: center;
  302. font-size: 12px;
  303. color: #fff;
  304. pointer-events: auto;
  305. &::after {
  306. content: '';
  307. height: 100%;
  308. vertical-align: middle;
  309. display: inline-block;
  310. }
  311. &.show {
  312. right: 0;
  313. }
  314. &.hide {
  315. right: -44px;
  316. }
  317. }
  318. }
  319. > .group-title-input {
  320. margin-left: 6px;
  321. flex: 1 1 auto;
  322. width: 1px;
  323. height: 30px;
  324. background: #1A1B1D;
  325. border-radius: 2px;
  326. border: 1px solid #404040;
  327. color: #fff;
  328. font-size: 14px;
  329. padding: 0 10px 0 16px;
  330. &:focus {
  331. border-color: #0076F6;
  332. }
  333. }
  334. }
  335. }
  336. </style>