index.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <template>
  2. <div
  3. class="go-chart-edit-tools"
  4. :class="[settingStore.getChartToolsStatus, isMiniComputed ? 'isMini' : 'unMini']"
  5. @click="isMini && (isMini = false)"
  6. @mouseenter="toolsMouseoverHandle"
  7. @mouseleave="toolsMouseoutHandle"
  8. >
  9. <!-- PawIcon -->
  10. <n-icon
  11. v-show="settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE && isMiniComputed"
  12. class="asideLogo"
  13. size="22"
  14. >
  15. <PawIcon></PawIcon>
  16. </n-icon>
  17. <n-tooltip
  18. v-for="(item, index) in btnListComputed"
  19. :key="item.key"
  20. :disabled="!isAside || (isHide && asideTootipDis)"
  21. trigger="hover"
  22. placement="left"
  23. >
  24. <template #trigger>
  25. <div class="btn-item">
  26. <n-button v-if="item.type === TypeEnum.BUTTON" :circle="isAside" secondary @click="item.handle">
  27. <template #icon>
  28. <n-icon size="22" v-if="isAside">
  29. <component :is="item.icon"></component>
  30. </n-icon>
  31. <component v-else :is="item.icon"></component>
  32. </template>
  33. <n-text depth="3" v-show="!isAside">{{ item.name }}</n-text>
  34. </n-button>
  35. <!-- 下载 -->
  36. <n-upload
  37. v-else-if="item.type === TypeEnum.IMPORTUPLOAD"
  38. v-model:file-list="importUploadFileListRef"
  39. :show-file-list="false"
  40. :customRequest="importCustomRequest"
  41. @before-upload="importBeforeUpload"
  42. >
  43. <n-button :circle="isAside" secondary>
  44. <template #icon>
  45. <n-icon size="22" v-if="isAside">
  46. <component :is="item.icon"></component>
  47. </n-icon>
  48. <component v-else :is="item.icon"></component>
  49. </template>
  50. <n-text depth="3" v-show="!isAside">{{ item.name }}</n-text>
  51. </n-button>
  52. </n-upload>
  53. </div>
  54. </template>
  55. <!-- 提示 -->
  56. <span>{{ item.name }}</span>
  57. </n-tooltip>
  58. </div>
  59. <!-- 系统设置 model -->
  60. <go-system-set v-model:modelShow="globalSettingModel"></go-system-set>
  61. </template>
  62. <script setup lang="ts">
  63. import { ref, computed } from 'vue'
  64. import { useSettingStore } from '@/store/modules/settingStore/settingStore'
  65. import { ToolsStatusEnum } from '@/store/modules/settingStore/settingStore.d'
  66. import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  67. import { fetchRouteParamsLocation, fetchPathByName, routerTurnByPath, setSessionStorage, getLocalStorage } from '@/utils'
  68. import { EditEnum } from '@/enums/pageEnum'
  69. import { StorageEnum } from '@/enums/storageEnum'
  70. import { useRoute } from 'vue-router'
  71. import { GoSystemSet } from '@/components/GoSystemSet/index'
  72. import { exportHandle } from './utils'
  73. import { useFile } from './hooks/useFile.hooks'
  74. import { useSyncUpdate } from './hooks/useSyncUpdate.hook'
  75. import { BtnListType, TypeEnum } from './index.d'
  76. import { icon } from '@/plugins'
  77. const { DownloadIcon, ShareIcon, PawIcon, SettingsSharpIcon, CreateIcon } = icon.ionicons5
  78. const settingStore = useSettingStore()
  79. const chartEditStore = useChartEditStore()
  80. const routerParamsInfo = useRoute()
  81. // 初始化编辑 JSON 模块
  82. useSyncUpdate()
  83. // 鼠标悬停定时器
  84. let mouseTime: any = null
  85. // 系统设置 model
  86. const globalSettingModel = ref(false)
  87. // 最小化
  88. const isMini = ref<boolean>(true)
  89. // 控制 tootip 提示时机
  90. const asideTootipDis = ref(true)
  91. // 文件上传
  92. const { importUploadFileListRef, importCustomRequest, importBeforeUpload } = useFile()
  93. // 是否是侧边栏
  94. const isAside = computed(() => settingStore.getChartToolsStatus === ToolsStatusEnum.ASIDE)
  95. // 是否隐藏(悬浮展示)
  96. const isHide = computed(() => settingStore.getChartToolsStatusHide)
  97. // 是否展示最小化(与全局配置相关)
  98. const isMiniComputed = computed(() => isMini.value && isHide.value)
  99. // 页面渲染配置
  100. const btnListComputed = computed(() => {
  101. if (!isAside.value) return btnList
  102. const reverseArr: BtnListType[] = []
  103. btnList.map(item => {
  104. reverseArr.unshift(item)
  105. })
  106. return reverseArr
  107. })
  108. // 鼠标移入
  109. const toolsMouseoverHandle = () => {
  110. mouseTime = setTimeout(() => {
  111. if (isMini.value) {
  112. isMini.value = false
  113. asideTootipDis.value = true
  114. }
  115. }, 200)
  116. setTimeout(() => {
  117. asideTootipDis.value = false
  118. }, 400)
  119. }
  120. // 鼠标移出
  121. const toolsMouseoutHandle = () => {
  122. clearTimeout(mouseTime)
  123. if (!isMini.value) {
  124. isMini.value = true
  125. }
  126. }
  127. // 编辑处理
  128. const editHandle = () => {
  129. window['$message'].warning('将开启失焦更新与 5 秒同步更新!')
  130. setTimeout(() => {
  131. // 获取id路径
  132. const path = fetchPathByName(EditEnum.CHART_EDIT_NAME, 'href')
  133. if (!path) return
  134. const id = fetchRouteParamsLocation()
  135. updateToSession(id)
  136. routerTurnByPath(path, [id], undefined, true)
  137. }, 1000)
  138. }
  139. // 把内存中的数据同步到SessionStorage 便于传递给新窗口初始化数据
  140. const updateToSession = (id: string) => {
  141. const storageInfo = chartEditStore.getStorageInfo
  142. const sessionStorageInfo = getLocalStorage(StorageEnum.GO_CHART_STORAGE_LIST) || []
  143. if (sessionStorageInfo?.length) {
  144. const repeateIndex = sessionStorageInfo.findIndex((e: { id: string }) => e.id === id)
  145. // 重复替换
  146. if (repeateIndex !== -1) {
  147. sessionStorageInfo.splice(repeateIndex, 1, { ...storageInfo, id })
  148. setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
  149. } else {
  150. sessionStorageInfo.push({ ...storageInfo, id })
  151. setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, sessionStorageInfo)
  152. }
  153. } else {
  154. setSessionStorage(StorageEnum.GO_CHART_STORAGE_LIST, [{ ...storageInfo, id }])
  155. }
  156. }
  157. // 配置列表
  158. const btnList: BtnListType[] = [
  159. {
  160. key: 'export',
  161. type: TypeEnum.BUTTON,
  162. name: '导出',
  163. icon: ShareIcon,
  164. handle: exportHandle
  165. },
  166. {
  167. key: 'import',
  168. type: TypeEnum.IMPORTUPLOAD,
  169. name: '导入',
  170. icon: DownloadIcon
  171. },
  172. {
  173. key: 'edit',
  174. type: TypeEnum.BUTTON,
  175. name: '编辑',
  176. icon: CreateIcon,
  177. handle: editHandle
  178. },
  179. {
  180. key: 'setting',
  181. type: TypeEnum.BUTTON,
  182. name: '设置',
  183. icon: SettingsSharpIcon,
  184. handle: () => {
  185. globalSettingModel.value = true
  186. }
  187. }
  188. ]
  189. </script>
  190. <style lang="scss" scoped>
  191. /* 底部区域的高度 */
  192. $dockHeight: 30px;
  193. $dockBottom: 60px;
  194. $dockMiniWidth: 200px;
  195. $dockMiniBottom: 53px;
  196. $asideHeight: 130px;
  197. $asideMiniHeight: 22px;
  198. $asideBottom: 70px;
  199. @include go('chart-edit-tools') {
  200. @extend .go-background-filter;
  201. position: absolute;
  202. display: flex;
  203. justify-content: space-around;
  204. align-items: center;
  205. border-radius: 25px;
  206. border: 1px solid;
  207. @include fetch-border-color('hover-border-color-shallow');
  208. &.aside {
  209. flex-direction: column-reverse;
  210. height: auto;
  211. right: 20px;
  212. padding: 30px 8px;
  213. bottom: $asideBottom;
  214. overflow: hidden;
  215. transition: height ease 0.4s;
  216. .btn-item {
  217. margin-bottom: 10px;
  218. &:first-of-type {
  219. margin-bottom: 0;
  220. }
  221. @include deep() {
  222. .n-button__icon {
  223. margin-right: 0;
  224. margin-left: 0;
  225. margin-bottom: 12px;
  226. }
  227. }
  228. }
  229. &.unMini {
  230. animation: aside-in 0.4s ease forwards;
  231. @keyframes aside-in {
  232. 0% {
  233. opacity: 0.5;
  234. height: $asideMiniHeight;
  235. }
  236. 100% {
  237. height: $asideHeight;
  238. opacity: 1;
  239. }
  240. }
  241. .btn-item {
  242. position: relative;
  243. display: block;
  244. }
  245. .asideLogo {
  246. opacity: 0.4;
  247. }
  248. }
  249. &.isMini {
  250. cursor: pointer;
  251. padding: 13px 13px;
  252. background-color: var(--n-toggle-bar-color);
  253. animation: aside-mini-in 0.4s ease forwards;
  254. @keyframes aside-mini-in {
  255. 0% {
  256. opacity: 0.5;
  257. height: $asideHeight;
  258. }
  259. 100% {
  260. opacity: 1;
  261. height: $asideMiniHeight;
  262. }
  263. }
  264. .btn-item {
  265. position: relative;
  266. display: none;
  267. }
  268. .asideLogo {
  269. opacity: 1;
  270. }
  271. }
  272. }
  273. &.dock {
  274. width: auto;
  275. left: 50%;
  276. transform: translateX(-50%);
  277. .btn-item {
  278. margin-right: 20px;
  279. &:last-child {
  280. margin-right: 0;
  281. }
  282. }
  283. &.unMini {
  284. animation: dock-in 0.4s ease forwards;
  285. @keyframes dock-in {
  286. 0% {
  287. opacity: 0;
  288. height: 0;
  289. padding: 5px;
  290. bottom: $dockMiniBottom;
  291. }
  292. 100% {
  293. height: $dockHeight;
  294. padding: 8px 30px;
  295. bottom: $dockBottom;
  296. border-radius: 25px;
  297. }
  298. }
  299. }
  300. /* 最小化 */
  301. &.isMini {
  302. height: 0;
  303. width: $dockMiniWidth;
  304. bottom: $dockMiniBottom;
  305. padding: 5px;
  306. border-radius: 8px;
  307. cursor: pointer;
  308. border: 0px;
  309. animation: dock-mini-in 1s ease forwards;
  310. @keyframes dock-mini-in {
  311. 0% {
  312. opacity: 1;
  313. height: $dockHeight;
  314. padding: 8px 30px;
  315. bottom: $dockBottom;
  316. border-radius: 25px;
  317. }
  318. 20% {
  319. height: 0;
  320. border-radius: 8px;
  321. }
  322. 50% {
  323. opacity: 0;
  324. bottom: calc(#{$dockMiniBottom} - 10px);
  325. }
  326. 100% {
  327. opacity: 1;
  328. height: 0;
  329. padding: 5px;
  330. bottom: $dockMiniBottom;
  331. }
  332. }
  333. .btn-item {
  334. position: relative;
  335. bottom: -50px;
  336. display: none;
  337. }
  338. }
  339. &::after {
  340. content: '';
  341. position: absolute;
  342. left: 0;
  343. width: 100%;
  344. height: 20px;
  345. bottom: -20px;
  346. cursor: pointer;
  347. }
  348. }
  349. }
  350. </style>