You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

440 lines
10 KiB

  1. <script setup lang="ts">
  2. import {
  3. reactive,
  4. ref,
  5. unref,
  6. watch,
  7. computed,
  8. nextTick,
  9. useCssModule,
  10. getCurrentInstance
  11. } from "vue";
  12. import panel from "../panel/index.vue";
  13. import { useRouter } from "vue-router";
  14. import { emitter } from "/@/utils/mitt";
  15. import { templateRef } from "@vueuse/core";
  16. import { debounce } from "/@/utils/debounce";
  17. import { themeColorsType } from "../../types";
  18. import { useAppStoreHook } from "/@/store/modules/app";
  19. import { storageLocal, storageSession } from "/@/utils/storage";
  20. import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
  21. import { toggleTheme } from "@zougt/vite-plugin-theme-preprocessor/dist/browser-utils";
  22. const router = useRouter();
  23. const { isSelect } = useCssModule();
  24. const instance =
  25. getCurrentInstance().appContext.app.config.globalProperties.$storage;
  26. const instanceConfig =
  27. getCurrentInstance().appContext.app.config.globalProperties.$config;
  28. let themeColors = ref<Array<themeColorsType>>([
  29. // 暗雅(默认)
  30. { rgb: "27, 42, 71", themeColor: "default" },
  31. // 明亮
  32. { rgb: "255, 255, 255", themeColor: "light" },
  33. // 薄暮
  34. { rgb: "245, 34, 45", themeColor: "dusk" },
  35. // 火山
  36. { rgb: "250, 84, 28", themeColor: "volcano" },
  37. // 黄色
  38. { rgb: "250, 219, 20", themeColor: "yellow" },
  39. // 明青
  40. { rgb: "19, 194, 194", themeColor: "mingQing" },
  41. // 极光绿
  42. { rgb: "82, 196, 26", themeColor: "auroraGreen" },
  43. // 粉红
  44. { rgb: "235, 47, 150", themeColor: "pink" },
  45. // 酱紫
  46. { rgb: "114, 46, 209", themeColor: "saucePurple" }
  47. ]);
  48. const verticalRef = templateRef<HTMLElement | null>("verticalRef", null);
  49. const horizontalRef = templateRef<HTMLElement | null>("horizontalRef", null);
  50. let layoutTheme =
  51. ref(storageLocal.getItem("responsive-layout")) ||
  52. ref({
  53. layout: instanceConfig?.Layout ?? "vertical",
  54. theme: instanceConfig?.Theme ?? "default"
  55. });
  56. // body添加layout属性,作用于src/style/sidebar.scss
  57. if (unref(layoutTheme)) {
  58. let layout = unref(layoutTheme).layout;
  59. let theme = unref(layoutTheme).theme;
  60. toggleTheme({
  61. scopeName: `layout-theme-${theme}`
  62. });
  63. setLayoutModel(layout);
  64. }
  65. // 默认灵动模式
  66. const markValue = ref(storageLocal.getItem("showModel") || "smart");
  67. const logoVal = ref(storageLocal.getItem("logoVal") || "1");
  68. const settings = reactive({
  69. greyVal: instance.sets.grey,
  70. weakVal: instance.sets.weak,
  71. tabsVal: instance.sets.hideTabs
  72. });
  73. function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) {
  74. const targetEl = target || document.body;
  75. let { className } = targetEl;
  76. className = className.replace(clsName, "");
  77. targetEl.className = flag ? `${className} ${clsName} ` : className;
  78. }
  79. // 灰色模式设置
  80. const greyChange = (value): void => {
  81. toggleClass(settings.greyVal, "html-grey", document.querySelector("html"));
  82. instance.sets = {
  83. grey: value,
  84. weak: instance.sets.weak,
  85. hideTabs: instance.sets.hideTabs
  86. };
  87. };
  88. // 色弱模式设置
  89. const weekChange = (value): void => {
  90. toggleClass(
  91. settings.weakVal,
  92. "html-weakness",
  93. document.querySelector("html")
  94. );
  95. instance.sets = {
  96. grey: instance.sets.grey,
  97. weak: value,
  98. hideTabs: instance.sets.hideTabs
  99. };
  100. };
  101. const tagsChange = () => {
  102. let showVal = settings.tabsVal;
  103. instance.sets = {
  104. grey: instance.sets.grey,
  105. weak: instance.sets.weak,
  106. hideTabs: showVal
  107. };
  108. emitter.emit("tagViewsChange", showVal);
  109. };
  110. //初始化项目配置
  111. nextTick(() => {
  112. settings.greyVal &&
  113. document.querySelector("html")?.setAttribute("class", "html-grey");
  114. settings.weakVal &&
  115. document.querySelector("html")?.setAttribute("class", "html-weakness");
  116. settings.tabsVal && tagsChange();
  117. });
  118. // 清空缓存并返回登录页
  119. function onReset() {
  120. storageLocal.clear();
  121. storageSession.clear();
  122. toggleClass(false, "html-grey", document.querySelector("html"));
  123. toggleClass(false, "html-weakness", document.querySelector("html"));
  124. useMultiTagsStoreHook().handleTags("equal", [
  125. {
  126. path: "/welcome",
  127. parentPath: "/",
  128. meta: {
  129. title: "message.hshome",
  130. icon: "el-icon-s-home",
  131. i18n: true,
  132. showLink: true
  133. }
  134. }
  135. ]);
  136. router.push("/login");
  137. }
  138. function onChange(label) {
  139. storageLocal.setItem("showModel", label);
  140. emitter.emit("tagViewsShowModel", label);
  141. }
  142. // 侧边栏Logo
  143. function logoChange() {
  144. unref(logoVal) === "1"
  145. ? storageLocal.setItem("logoVal", "1")
  146. : storageLocal.setItem("logoVal", "-1");
  147. emitter.emit("logoChange", unref(logoVal));
  148. }
  149. function setFalse(Doms): any {
  150. Doms.forEach(v => {
  151. toggleClass(false, isSelect, unref(v));
  152. });
  153. }
  154. watch(instance, ({ layout }) => {
  155. switch (layout["layout"]) {
  156. case "vertical":
  157. toggleClass(true, isSelect, unref(verticalRef));
  158. debounce(setFalse([horizontalRef]), 50);
  159. break;
  160. case "horizontal":
  161. toggleClass(true, isSelect, unref(horizontalRef));
  162. debounce(setFalse([verticalRef]), 50);
  163. break;
  164. }
  165. });
  166. // 主题色 激活选择项
  167. const getThemeColor = computed(() => {
  168. return current => {
  169. if (
  170. current === layoutTheme.value.theme &&
  171. layoutTheme.value.theme !== "light"
  172. ) {
  173. return "#fff";
  174. } else if (
  175. current === layoutTheme.value.theme &&
  176. layoutTheme.value.theme === "light"
  177. ) {
  178. return "#1d2b45";
  179. } else {
  180. return "transparent";
  181. }
  182. };
  183. });
  184. // 设置导航模式
  185. function setLayoutModel(layout: string) {
  186. layoutTheme.value.layout = layout;
  187. window.document.body.setAttribute("layout", layout);
  188. instance.layout = { layout, theme: layoutTheme.value.theme };
  189. useAppStoreHook().setLayout(layout);
  190. }
  191. // 设置导航主题色
  192. function setLayoutThemeColor(theme: string) {
  193. layoutTheme.value.theme = theme;
  194. toggleTheme({
  195. scopeName: `layout-theme-${theme}`
  196. });
  197. instance.layout = { layout: useAppStoreHook().layout, theme };
  198. }
  199. </script>
  200. <template>
  201. <panel>
  202. <el-divider>主题风格</el-divider>
  203. <ul class="pure-theme">
  204. <el-tooltip class="item" content="左侧菜单模式" placement="bottom">
  205. <li
  206. :class="layoutTheme.layout === 'vertical' ? $style.isSelect : ''"
  207. ref="verticalRef"
  208. @click="setLayoutModel('vertical')"
  209. >
  210. <div></div>
  211. <div></div>
  212. </li>
  213. </el-tooltip>
  214. <el-tooltip class="item" content="顶部菜单模式" placement="bottom">
  215. <li
  216. :class="layoutTheme.layout === 'horizontal' ? $style.isSelect : ''"
  217. ref="horizontalRef"
  218. @click="setLayoutModel('horizontal')"
  219. >
  220. <div></div>
  221. <div></div>
  222. </li>
  223. </el-tooltip>
  224. </ul>
  225. <el-divider>主题色</el-divider>
  226. <ul class="theme-color">
  227. <li
  228. v-for="(item, index) in themeColors"
  229. :key="index"
  230. :style="{ background: `rgb(${item.rgb})` }"
  231. @click="setLayoutThemeColor(item.themeColor)"
  232. >
  233. <el-icon
  234. style="margin: 0.1em 0.1em 0 0"
  235. :size="17"
  236. :color="getThemeColor(item.themeColor)"
  237. >
  238. <Check />
  239. </el-icon>
  240. </li>
  241. </ul>
  242. <el-divider>界面显示</el-divider>
  243. <ul class="setting">
  244. <li>
  245. <span>灰色模式</span>
  246. <el-switch
  247. v-model="settings.greyVal"
  248. inline-prompt
  249. inactive-color="#a6a6a6"
  250. active-text="开"
  251. inactive-text="关"
  252. @change="greyChange"
  253. >
  254. </el-switch>
  255. </li>
  256. <li>
  257. <span>色弱模式</span>
  258. <el-switch
  259. v-model="settings.weakVal"
  260. inline-prompt
  261. inactive-color="#a6a6a6"
  262. active-text="开"
  263. inactive-text="关"
  264. @change="weekChange"
  265. >
  266. </el-switch>
  267. </li>
  268. <li>
  269. <span>隐藏标签页</span>
  270. <el-switch
  271. v-model="settings.tabsVal"
  272. inline-prompt
  273. inactive-color="#a6a6a6"
  274. active-text="开"
  275. inactive-text="关"
  276. @change="tagsChange"
  277. >
  278. </el-switch>
  279. </li>
  280. <li>
  281. <span>侧边栏Logo</span>
  282. <el-switch
  283. v-model="logoVal"
  284. inline-prompt
  285. active-value="1"
  286. inactive-value="-1"
  287. inactive-color="#a6a6a6"
  288. active-text="开"
  289. inactive-text="关"
  290. @change="logoChange"
  291. >
  292. </el-switch>
  293. </li>
  294. <li>
  295. <span>标签风格</span>
  296. <el-radio-group v-model="markValue" size="small" @change="onChange">
  297. <el-radio label="card">卡片</el-radio>
  298. <el-radio label="smart">灵动</el-radio>
  299. </el-radio-group>
  300. </li>
  301. </ul>
  302. <el-divider />
  303. <el-button
  304. type="danger"
  305. style="width: 90%; margin: 24px 15px"
  306. @click="onReset"
  307. >
  308. <i class="fa fa-sign-out"></i>
  309. 清空缓存并返回登录页</el-button
  310. >
  311. </panel>
  312. </template>
  313. <style scoped module>
  314. .isSelect {
  315. border: 2px solid #0960bd;
  316. }
  317. </style>
  318. <style lang="scss" scoped>
  319. .setting {
  320. width: 100%;
  321. li {
  322. display: flex;
  323. justify-content: space-between;
  324. align-items: center;
  325. margin: 25px;
  326. }
  327. }
  328. :deep(.el-divider__text) {
  329. font-size: 16px;
  330. font-weight: 700;
  331. }
  332. .pure-theme {
  333. margin-top: 25px;
  334. width: 100%;
  335. height: 100px;
  336. display: flex;
  337. flex-wrap: wrap;
  338. justify-content: space-around;
  339. li {
  340. margin: 10px;
  341. width: 36%;
  342. height: 70px;
  343. background: #f0f2f5;
  344. position: relative;
  345. overflow: hidden;
  346. cursor: pointer;
  347. border-radius: 4px;
  348. box-shadow: 0 1px 2.5px 0 rgb(0 0 0 / 18%);
  349. &:nth-child(1) {
  350. div {
  351. &:nth-child(1) {
  352. width: 30%;
  353. height: 100%;
  354. background: #1b2a47;
  355. }
  356. &:nth-child(2) {
  357. width: 70%;
  358. height: 30%;
  359. top: 0;
  360. right: 0;
  361. background: #fff;
  362. box-shadow: 0 0 1px #888;
  363. position: absolute;
  364. }
  365. }
  366. }
  367. &:nth-child(2) {
  368. div {
  369. &:nth-child(1) {
  370. width: 100%;
  371. height: 30%;
  372. background: #1b2a47;
  373. box-shadow: 0 0 1px #888;
  374. }
  375. }
  376. }
  377. }
  378. }
  379. .theme-color {
  380. width: 100%;
  381. height: 40px;
  382. margin-top: 20px;
  383. display: flex;
  384. justify-content: center;
  385. li {
  386. float: left;
  387. width: 20px;
  388. height: 20px;
  389. margin-top: 8px;
  390. margin-right: 8px;
  391. font-weight: 700;
  392. text-align: center;
  393. border-radius: 2px;
  394. cursor: pointer;
  395. &:nth-child(2) {
  396. border: 1px solid #ddd;
  397. }
  398. }
  399. }
  400. </style>