AsideMenu.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <template>
  2. <div class="side-menu-wrapper">
  3. <!-- 768px 下,以抽屉形式展示 -->
  4. <a-drawer v-model="isDrawer" :width="210" :closable="false" placement="left" v-if="screenWidth <= 768">
  5. <!-- collapse 属性:控制菜单收缩展开 -->
  6. <a-menu class="side-menu" v-model:selectedKeys="activeIndex" :mode="'inline'" :inline-collapsed="isCollapse">
  7. <a-sub-menu key="myFile" class="my-file">
  8. <template #title>
  9. <!-- 使用 Ant Design Vue 的图标 -->
  10. <folder-outlined />
  11. <span>我的文件</span>
  12. </template>
  13. <a-menu-item key="0" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 0, filePath: '/' } })">
  14. <menu-outlined />
  15. <span>全部</span>
  16. </a-menu-item>
  17. <a-menu-item key="1" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 1 } })">
  18. <picture-outlined />
  19. <span>图片</span>
  20. </a-menu-item>
  21. <a-menu-item key="2" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 2 } })">
  22. <file-text-outlined />
  23. <span>文档</span>
  24. </a-menu-item>
  25. <a-menu-item key="3" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 3 } })">
  26. <video-camera-outlined />
  27. <span>视频</span>
  28. </a-menu-item>
  29. <a-menu-item key="4" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 4 } })">
  30. <sound-outlined />
  31. <span>音乐</span>
  32. </a-menu-item>
  33. <a-menu-item key="5" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 5 } })">
  34. <inbox-outlined />
  35. <span>其他</span>
  36. </a-menu-item>
  37. </a-sub-menu>
  38. <a-menu-item key="6" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 6 } })" class="recovery">
  39. <delete-outlined />
  40. <span>回收站</span>
  41. </a-menu-item>
  42. <a-menu-item
  43. key="8"
  44. @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 8, filePath: '/' } })"
  45. class="my-share"
  46. >
  47. <share-alt-outlined />
  48. <span>我的分享</span>
  49. </a-menu-item>
  50. </a-menu>
  51. <!-- 存储信息显示 -->
  52. <div class="storage-wrapper" :class="{ fold: isCollapse }">
  53. <a-progress
  54. :percent="storagePercentage"
  55. :stroke-color="storageColor"
  56. :show-info="false"
  57. :type="isCollapse ? 'circle' : 'line'"
  58. :width="32"
  59. :stroke-width="isCollapse ? 4 : 6"
  60. stroke-linecap="square"
  61. ></a-progress>
  62. <div class="text" v-show="!isCollapse">
  63. <span class="label">存储</span>
  64. <span>
  65. {{ $file.calculateFileSize(storageValue) }} /
  66. {{ $file.calculateFileSize(totalStorageValue) }}
  67. </span>
  68. </div>
  69. <div class="text" v-show="isCollapse">
  70. <span>{{ $file.calculateFileSize(storageValue) }}</span>
  71. </div>
  72. </div>
  73. </a-drawer>
  74. <!-- 768px 以上,平铺展示 -->
  75. <template v-else>
  76. <!-- collapse 属性:控制菜单收缩展开 -->
  77. <a-menu class="side-menu" v-model:selectedKeys="activeIndex" :mode="'inline'" :inline-collapsed="isCollapse">
  78. <a-sub-menu key="myFile" class="my-file">
  79. <template #title>
  80. <!-- 使用 Ant Design Vue 的图标 -->
  81. <folder-outlined />
  82. <span>我的文件</span>
  83. </template>
  84. <a-menu-item key="0" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 0, filePath: '/' } })">
  85. <menu-outlined />
  86. <span>全部</span>
  87. </a-menu-item>
  88. <a-menu-item key="1" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 1 } })">
  89. <picture-outlined />
  90. <span>图片</span>
  91. </a-menu-item>
  92. <a-menu-item key="2" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 2 } })">
  93. <file-text-outlined />
  94. <span>文档</span>
  95. </a-menu-item>
  96. <a-menu-item key="3" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 3 } })">
  97. <video-camera-outlined />
  98. <span>视频</span>
  99. </a-menu-item>
  100. <a-menu-item key="4" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 4 } })">
  101. <sound-outlined />
  102. <span>音乐</span>
  103. </a-menu-item>
  104. <a-menu-item key="5" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 5 } })">
  105. <inbox-outlined />
  106. <span>其他</span>
  107. </a-menu-item>
  108. </a-sub-menu>
  109. <a-menu-item key="6" @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 6 } })" class="recovery">
  110. <delete-outlined />
  111. <span>回收站</span>
  112. </a-menu-item>
  113. <a-menu-item
  114. key="8"
  115. @click="navigateTo({ name: 'resourceLibrary', query: { fileType: 8, filePath: '/' } })"
  116. class="my-share"
  117. >
  118. <share-alt-outlined />
  119. <span>我的分享</span>
  120. </a-menu-item>
  121. </a-menu>
  122. <!-- 存储信息显示 -->
  123. <div class="storage-wrapper" :class="{ fold: isCollapse }">
  124. <a-progress
  125. :percent="storagePercentage"
  126. :stroke-color="storageColor"
  127. :show-info="false"
  128. :type="isCollapse ? 'circle' : 'line'"
  129. :width="32"
  130. :stroke-width="isCollapse ? 4 : 6"
  131. stroke-linecap="square"
  132. ></a-progress>
  133. <div class="text" v-show="!isCollapse">
  134. <span class="label">存储</span>
  135. <span>
  136. {{ $file.calculateFileSize(storageValue) }} /
  137. {{ $file.calculateFileSize(totalStorageValue) }}
  138. </span>
  139. </div>
  140. <div class="text" v-show="isCollapse">
  141. <span>{{ $file.calculateFileSize(storageValue) }}</span>
  142. </div>
  143. </div>
  144. </template>
  145. <!-- 展开 & 收缩分类栏 -->
  146. <a-tooltip :title="isCollapse ? '展开' : '收起'" placement="right">
  147. <div class="aside-title" @click="isCollapse ? (isCollapse = false) : (isCollapse = true)">
  148. <right-outlined v-if="isCollapse" class="icon" />
  149. <left-outlined v-else class="icon" />
  150. </div>
  151. </a-tooltip>
  152. </div>
  153. </template>
  154. <script setup>
  155. import { ref, computed, watch, onMounted, getCurrentInstance } from 'vue'
  156. import { useRouter, useRoute } from 'vue-router'
  157. import { useMyResourceStore } from '@/store/myResource'
  158. import {
  159. FolderOutlined,
  160. MenuOutlined,
  161. PictureOutlined,
  162. FileTextOutlined,
  163. VideoCameraOutlined,
  164. SoundOutlined,
  165. InboxOutlined,
  166. DeleteOutlined,
  167. ShareAltOutlined,
  168. LeftOutlined,
  169. RightOutlined
  170. } from '@ant-design/icons-vue'
  171. // 获取当前实例,用于访问全局属性
  172. const { proxy } = getCurrentInstance()
  173. const router = useRouter()
  174. const route = useRoute()
  175. const myResourceStore = useMyResourceStore()
  176. const emit = defineEmits([''])
  177. // 数据
  178. const isDrawer = ref(false) // 控制移动端菜单抽屉是否显示
  179. const isCollapse = ref(false) // 控制菜单收缩展开
  180. // 将计算属性改为响应式变量
  181. const activeIndex = ref([String(myResourceStore.getQuery.fileType ? myResourceStore.getQuery.fileType : '' || '0')])
  182. // 菜单 index 和名称 Map
  183. const myFileMenuMap = {
  184. 0: '全部',
  185. 1: '图片',
  186. 2: '文档',
  187. 3: '视频',
  188. 4: '音乐',
  189. 5: '其他',
  190. 6: '回收站',
  191. 8: '我的分享'
  192. }
  193. // 自定义进度条颜色,不同占比,进度条颜色不同
  194. const storageColor = {
  195. '0%': '#67C23A',
  196. '50%': '#67C23A',
  197. '80%': '#E6A23C',
  198. '100%': '#F56C6C'
  199. }
  200. // 存储容量
  201. const storageValue = computed(() => {
  202. return myResourceStore.storageValue
  203. })
  204. const totalStorageValue = computed(() => {
  205. return myResourceStore.totalStorageValue
  206. })
  207. // 存储百分比
  208. const storagePercentage = computed(() => {
  209. return totalStorageValue.value ? (storageValue.value / totalStorageValue.value) * 100 : 0
  210. })
  211. // 屏幕宽度
  212. const screenWidth = computed(() => {
  213. return myResourceStore.screenWidth
  214. })
  215. // 监听路由变化,更新activeIndex
  216. // watch(
  217. // () => route.query.fileType,
  218. // (newValue) => {
  219. // activeIndex.value = [String(newValue || '0')]
  220. // console.log('activeIndex', activeIndex.value)
  221. // document.title = `${myFileMenuMap[Number(newValue || 0)]} - ${proxy.$RESOURCE_CONFIG.siteName}`
  222. // isDrawer.value = false
  223. // }
  224. // )
  225. // // 监听收缩状态变化,存储在 localStorage 中,保证页面刷新时仍然保存设置的状态
  226. // watch(isCollapse, (newValue) => {
  227. // localStorage.setItem('qiwen_is_collapse', newValue)
  228. // if (screenWidth.value <= 768 && newValue) {
  229. // isDrawer.value = true
  230. // isCollapse.value = false
  231. // }
  232. // })
  233. // 导航到指定路由
  234. const navigateTo = (route) => {
  235. console.log('route==', route)
  236. // router.push(route)
  237. emit('onNavigateTo', route)
  238. }
  239. // 生命周期钩子
  240. onMounted(() => {
  241. isCollapse.value = localStorage.getItem('qiwen_is_collapse') === 'true' // 读取保存的状态
  242. document.title = `${myFileMenuMap[Number(activeIndex.value[0] || 0)]} - ${proxy.$RESOURCE_CONFIG.siteName}`
  243. })
  244. </script>
  245. <style lang="less" scoped>
  246. @import '@/style/myResource/varibles.less';
  247. @import '@/style/myResource/mixins.less';
  248. .side-menu-wrapper {
  249. position: relative;
  250. height: calc(100vh - 61px);
  251. padding-right: 11px;
  252. .side-menu {
  253. // 高度设置为屏幕高度减去顶部导航栏的高度
  254. height: calc(100vh - 127px);
  255. overflow: auto;
  256. // 调整滚动条样式
  257. .setScrollbar(6px, transparent, #C0C4CC);
  258. :deep(.ant-menu-item-selected) {
  259. background: #ecf5ff;
  260. }
  261. .my-file,
  262. .recovery {
  263. box-shadow: 0 4px 12px 0 @BorderExtralight;
  264. }
  265. }
  266. :deep(.ant-menu) {
  267. background: transparent;
  268. color: #fff;
  269. }
  270. // 对展开状态下的菜单设置宽度
  271. .side-menu:not(.ant-menu-inline-collapsed) {
  272. width: 210px;
  273. }
  274. // 存储空间展示区
  275. .storage-wrapper {
  276. position: absolute;
  277. bottom: 0;
  278. left: 0;
  279. box-shadow: 0 -2px 12px 0 @BorderExtralight;
  280. border-right: solid 1px #e6e6e6;
  281. box-sizing: border-box;
  282. width: calc(100% - 11px);
  283. height: 66px;
  284. padding: 16px;
  285. z-index: 2;
  286. color: @PrimaryText;
  287. .text {
  288. margin-top: 8px;
  289. display: flex;
  290. justify-content: space-between;
  291. align-items: center;
  292. font-size: 12px;
  293. flex-wrap: wrap;
  294. }
  295. }
  296. .storage-wrapper.fold {
  297. padding: 0;
  298. :deep(.ant-progress-circle) {
  299. margin: 0 auto;
  300. width: 32px;
  301. display: block;
  302. }
  303. .text {
  304. font-size: 12px;
  305. justify-content: center;
  306. }
  307. }
  308. // 折叠图标调整样式
  309. .aside-title {
  310. position: absolute;
  311. top: calc(50% - 50px);
  312. right: 0;
  313. z-index: 2;
  314. background: @BorderBase;
  315. color: #fff;
  316. width: 12px;
  317. height: 100px;
  318. line-height: 100px;
  319. cursor: pointer;
  320. border-radius: 0 16px 16px 0;
  321. &:hover {
  322. opacity: 0.7;
  323. }
  324. .icon {
  325. font-size: 12px;
  326. }
  327. }
  328. }
  329. </style>