Lin Qilong 1 周之前
父节点
当前提交
9e7cdcb232

+ 1 - 0
ruoyi-ui/.github/FUNDING.yml

@@ -0,0 +1 @@
+custom: http://doc.ruoyi.vip/ruoyi-cloud/other/donate.html

+ 20 - 0
ruoyi-ui/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 RuoYi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

文件差异内容过多而无法显示
+ 21 - 0
ruoyi-ui/html/ie.html


+ 215 - 0
ruoyi-ui/index.html

@@ -0,0 +1,215 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta charset="utf-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+  <meta name="renderer" content="webkit">
+  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+  <link rel="icon" href="/favicon.ico">
+  <title>若依管理系统</title>
+  <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
+  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0px;
+      padding: 0px;
+    }
+
+    .chromeframe {
+      margin: 0.2em 0;
+      background: #ccc;
+      color: #000;
+      padding: 0.2em 0;
+    }
+
+    #loader-wrapper {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 999999;
+    }
+
+    #loader {
+      display: block;
+      position: relative;
+      left: 50%;
+      top: 50%;
+      width: 150px;
+      height: 150px;
+      margin: -75px 0 0 -75px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 2s linear infinite;
+      -ms-animation: spin 2s linear infinite;
+      -moz-animation: spin 2s linear infinite;
+      -o-animation: spin 2s linear infinite;
+      animation: spin 2s linear infinite;
+      z-index: 1001;
+    }
+
+    #loader:before {
+      content: "";
+      position: absolute;
+      top: 5px;
+      left: 5px;
+      right: 5px;
+      bottom: 5px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 3s linear infinite;
+      -moz-animation: spin 3s linear infinite;
+      -o-animation: spin 3s linear infinite;
+      -ms-animation: spin 3s linear infinite;
+      animation: spin 3s linear infinite;
+    }
+
+    #loader:after {
+      content: "";
+      position: absolute;
+      top: 15px;
+      left: 15px;
+      right: 15px;
+      bottom: 15px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -moz-animation: spin 1.5s linear infinite;
+      -o-animation: spin 1.5s linear infinite;
+      -ms-animation: spin 1.5s linear infinite;
+      -webkit-animation: spin 1.5s linear infinite;
+      animation: spin 1.5s linear infinite;
+    }
+
+
+    @-webkit-keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+    @keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+
+    #loader-wrapper .loader-section {
+      position: fixed;
+      top: 0;
+      width: 51%;
+      height: 100%;
+      background: #7171C6;
+      z-index: 1000;
+      -webkit-transform: translateX(0);
+      -ms-transform: translateX(0);
+      transform: translateX(0);
+    }
+
+    #loader-wrapper .loader-section.section-left {
+      left: 0;
+    }
+
+    #loader-wrapper .loader-section.section-right {
+      right: 0;
+    }
+
+
+    .loaded #loader-wrapper .loader-section.section-left {
+      -webkit-transform: translateX(-100%);
+      -ms-transform: translateX(-100%);
+      transform: translateX(-100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader-wrapper .loader-section.section-right {
+      -webkit-transform: translateX(100%);
+      -ms-transform: translateX(100%);
+      transform: translateX(100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader {
+      opacity: 0;
+      -webkit-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+    }
+
+    .loaded #loader-wrapper {
+      visibility: hidden;
+      -webkit-transform: translateY(-100%);
+      -ms-transform: translateY(-100%);
+      transform: translateY(-100%);
+      -webkit-transition: all 0.3s 1s ease-out;
+      transition: all 0.3s 1s ease-out;
+    }
+
+    .no-js #loader-wrapper {
+      display: none;
+    }
+
+    .no-js h1 {
+      color: #222222;
+    }
+
+    #loader-wrapper .load_title {
+      font-family: 'Open Sans';
+      color: #FFF;
+      font-size: 19px;
+      width: 100%;
+      text-align: center;
+      z-index: 9999999999999;
+      position: absolute;
+      top: 60%;
+      opacity: 1;
+      line-height: 30px;
+    }
+
+    #loader-wrapper .load_title span {
+      font-weight: normal;
+      font-style: italic;
+      font-size: 13px;
+      color: #FFF;
+      opacity: 0.5;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="app">
+    <div id="loader-wrapper">
+      <div id="loader"></div>
+      <div class="loader-section section-left"></div>
+      <div class="loader-section section-right"></div>
+      <div class="load_title">正在加载系统资源,请耐心等待</div>
+    </div>
+  </div>
+  <script type="module" src="/src/main.js"></script>
+</body>
+
+</html>

+ 1 - 0
ruoyi-ui/src/assets/icons/svg/moon.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733303018722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1447" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M368.832 67.2c51.328-16.384 89.216 34.112 75.712 76.416a346.816 346.816 0 0 0 435.84 435.84c42.304-13.44 92.8 24.384 76.48 75.712A467.968 467.968 0 1 1 368.832 67.2z m-35.776 122.688a368.832 368.832 0 1 0 501.056 501.056 445.952 445.952 0 0 1-501.056-501.056z" p-id="1448"></path></svg>

文件差异内容过多而无法显示
+ 0 - 0
ruoyi-ui/src/assets/icons/svg/redis.svg


+ 1 - 0
ruoyi-ui/src/assets/icons/svg/sunny.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733303115132" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12397" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 890.432c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 0 1-66.816 0v-66.752c0-18.432 14.976-33.408 33.408-33.408z m-267.52-110.848a33.408 33.408 0 0 1 0 47.232l-47.296 47.232a33.408 33.408 0 0 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0z m582.336 0l47.232 47.232a33.408 33.408 0 0 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 1 1 47.232-47.232zM512 200.32a311.68 311.68 0 1 1 0 623.296 311.68 311.68 0 0 1 0-623.36z m0 66.752a244.864 244.864 0 1 0 0 489.728 244.864 244.864 0 0 0 0-489.728zM100.16 478.592a33.408 33.408 0 1 1 0 66.816H33.408a33.408 33.408 0 0 1 0-66.816h66.752z m890.432 0a33.408 33.408 0 0 1 0 66.816h-66.752a33.408 33.408 0 1 1 0-66.816h66.752zM197.184 149.952l47.232 47.232a33.408 33.408 0 1 1-47.232 47.232l-47.232-47.232a33.408 33.408 0 0 1 47.232-47.232z m676.864 0a33.408 33.408 0 0 1 0 47.232l-47.232 47.232a33.408 33.408 0 1 1-47.232-47.232l47.232-47.232a33.408 33.408 0 0 1 47.232 0zM512 0c18.432 0 33.408 14.976 33.408 33.408v66.752a33.408 33.408 0 1 1-66.816 0V33.408C478.592 14.976 493.568 0 512 0z" p-id="12398"></path></svg>

+ 221 - 0
ruoyi-ui/src/assets/styles/variables.module.scss

@@ -0,0 +1,221 @@
+// base color
+$blue: #324157;
+$light-blue: #333c46;
+$red: #C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow: #FEC171;
+$panGreen: #30B08F;
+
+// 默认主题变量
+$menuText: #bfcbd9;
+$menuActiveText: #409eff;
+$menuBg: #304156;
+$menuHover: #263445;
+
+// 浅色主题theme-light
+$menuLightBg: #ffffff;
+$menuLightHover: #f0f1f5;
+$menuLightText: #303133;
+$menuLightActiveText: #409EFF;
+
+// 基础变量
+$base-sidebar-width: 200px;
+$sideBarWidth: 200px;
+
+// 菜单暗色变量
+$base-menu-color: #bfcbd9;
+$base-menu-color-active: #f4f4f5;
+$base-menu-background: #304156;
+$base-sub-menu-background: #1f2d3d;
+$base-sub-menu-hover: #001528;
+
+// 组件变量
+$--color-primary: #409EFF;
+$--color-success: #67C23A;
+$--color-warning: #E6A23C;
+$--color-danger: #F56C6C;
+$--color-info: #909399;
+
+:export {
+  menuText: $menuText;
+  menuActiveText: $menuActiveText;
+  menuBg: $menuBg;
+  menuHover: $menuHover;
+  menuLightBg: $menuLightBg;
+  menuLightHover: $menuLightHover;
+  menuLightText: $menuLightText;
+  menuLightActiveText: $menuLightActiveText;
+  sideBarWidth: $sideBarWidth;
+  // 导出基础颜色
+  blue: $blue;
+  lightBlue: $light-blue;
+  red: $red;
+  pink: $pink;
+  green: $green;
+  tiffany: $tiffany;
+  yellow: $yellow;
+  panGreen: $panGreen;
+  // 导出组件颜色
+  colorPrimary: $--color-primary;
+  colorSuccess: $--color-success;
+  colorWarning: $--color-warning;
+  colorDanger: $--color-danger;
+  colorInfo: $--color-info;
+}
+
+// CSS变量定义
+:root {
+  /* 亮色模式变量 */
+  --sidebar-bg: #{$menuBg};
+  --sidebar-text: #{$menuText};
+  --menu-hover: #{$menuHover};
+  
+  --navbar-bg: #ffffff;
+  --navbar-text: #303133;
+  
+  /* splitpanes default-theme 变量 */
+  --splitpanes-default-bg: #ffffff;
+
+}
+
+// 暗黑模式变量
+html.dark {
+  /* 默认通用 */
+  --el-bg-color: #141414;
+  --el-bg-color-overlay: #1d1e1f;
+  --el-text-color-primary: #ffffff;
+  --el-text-color-regular: #d0d0d0;
+  --el-border-color: #434343;
+  --el-border-color-light: #434343;
+
+  /* 侧边栏 */
+  --sidebar-bg: #141414;
+  --sidebar-text: #ffffff;
+  --menu-hover: #2d2d2d;
+  --menu-active-text: #{$menuActiveText};
+
+  /* 顶部导航栏 */
+  --navbar-bg: #141414;
+  --navbar-text: #ffffff;
+  --navbar-hover: #141414;
+
+  /* 标签栏 */
+  --tags-bg: #141414;
+  --tags-item-bg: #1d1e1f;
+  --tags-item-border: #303030;
+  --tags-item-text: #d0d0d0;
+  --tags-item-hover: #2d2d2d;
+  --tags-close-hover: #64666a;
+
+  /* splitpanes 组件暗黑模式变量 */
+  --splitpanes-bg: #141414;
+  --splitpanes-border: #303030;
+  --splitpanes-splitter-bg: #1d1e1f;
+  --splitpanes-splitter-hover-bg: #2d2d2d;
+
+  /* blockquote 暗黑模式变量 */
+  --blockquote-bg: #1d1e1f;
+  --blockquote-border: #303030;
+  --blockquote-text: #d0d0d0;
+  
+  /* Cron 时间表达式 模式变量 */
+  --cron-border: #303030;
+
+  /* splitpanes default-theme 暗黑模式变量 */
+  --splitpanes-default-bg: #141414;
+
+  /* 侧边栏菜单覆盖 */
+   .sidebar-container {
+    .el-menu-item, .menu-title {
+      color: var(--el-text-color-regular);
+    }
+    & .theme-dark .nest-menu .el-sub-menu>.el-sub-menu__title,
+    & .theme-dark .el-sub-menu .el-menu-item {
+      background-color: var(--el-bg-color) !important;
+    }
+  }
+
+  /* 顶部栏栏菜单覆盖 */
+  .el-menu--horizontal {
+    .el-menu-item {
+      &:not(.is-disabled) {
+        &:hover,
+        &:focus {
+          background-color: var(--navbar-hover) !important;
+        }
+      }
+    }
+  }
+
+  /* 分割窗格覆盖 */
+  .splitpanes {
+    background-color: var(--splitpanes-bg);
+
+    .splitpanes__pane {
+      background-color: var(--splitpanes-bg);
+      border-color: var(--splitpanes-border);
+    }
+
+    .splitpanes__splitter {
+      background-color: var(--splitpanes-splitter-bg);
+      border-color: var(--splitpanes-border);
+
+      &:hover {
+        background-color: var(--splitpanes-splitter-hover-bg);
+      }
+
+      &:before,
+      &:after {
+        background-color: var(--splitpanes-border);
+      }
+    }
+  }
+
+  /* 表格样式覆盖 */
+  .el-table {
+    --el-table-header-bg-color: var(--el-bg-color-overlay) !important;
+    --el-table-header-text-color: var(--el-text-color-regular) !important;
+    --el-table-border-color: var(--el-border-color-light) !important;
+    --el-table-row-hover-bg-color: var(--el-bg-color-overlay) !important;
+
+    .el-table__header-wrapper, .el-table__fixed-header-wrapper {
+      th {
+        background-color: var(--el-bg-color-overlay, #f8f8f9) !important;
+        color: var(--el-text-color-regular, #515a6e);
+      }
+    }
+  }
+
+  /* 树组件高亮样式覆盖 */
+  .el-tree {
+    .el-tree-node.is-current > .el-tree-node__content {
+      background-color: var(--el-bg-color-overlay) !important;
+      color: var(--el-color-primary);
+    }
+
+    .el-tree-node__content:hover {
+      background-color: var(--el-bg-color-overlay);
+    }
+  }
+  
+  /* 下拉菜单样式覆盖 */
+  .el-dropdown-menu__item:not(.is-disabled):focus, .el-dropdown-menu__item:not(.is-disabled):hover{
+    background-color: var(--navbar-hover) !important;
+  }
+
+  /* blockquote样式覆盖 */
+  blockquote {
+    background-color: var(--blockquote-bg) !important;
+    border-left-color: var(--blockquote-border) !important;
+    color: var(--blockquote-text) !important;
+  }
+  
+  /* 时间表达式标题样式覆盖 */
+  .popup-result .title {
+    background: var(--cron-border);
+  }
+
+}
+

+ 10 - 0
ruoyi-ui/src/components/SvgIcon/svgicon.js

@@ -0,0 +1,10 @@
+import * as components from '@element-plus/icons-vue'
+
+export default {
+  install: (app) => {
+    for (const key in components) {
+      const componentConfig = components[key]
+      app.component(componentConfig.name, componentConfig)
+    }
+  }
+}

+ 65 - 0
ruoyi-ui/src/directive/common/copyText.js

@@ -0,0 +1,65 @@
+/**
+* v-copyText 复制文本内容
+* Copyright (c) 2022 ruoyi
+*/
+export default {
+  beforeMount(el, { value, arg }) {
+    if (arg === "callback") {
+      el.$copyCallback = value
+    } else {
+      el.$copyValue = value
+      const handler = () => {
+        copyTextToClipboard(el.$copyValue)
+        if (el.$copyCallback) {
+          el.$copyCallback(el.$copyValue)
+        }
+      }
+      el.addEventListener("click", handler)
+      el.$destroyCopy = () => el.removeEventListener("click", handler)
+    }
+  }
+}
+
+function copyTextToClipboard(input, { target = document.body } = {}) {
+  const element = document.createElement('textarea')
+  const previouslyFocusedElement = document.activeElement
+
+  element.value = input
+
+  // Prevent keyboard from showing on mobile
+  element.setAttribute('readonly', '')
+
+  element.style.contain = 'strict'
+  element.style.position = 'absolute'
+  element.style.left = '-9999px'
+  element.style.fontSize = '12pt' // Prevent zooming on iOS
+
+  const selection = document.getSelection()
+  const originalRange = selection.rangeCount > 0 && selection.getRangeAt(0)
+
+  target.append(element)
+  element.select()
+
+  // Explicit selection workaround for iOS
+  element.selectionStart = 0
+  element.selectionEnd = input.length
+
+  let isSuccess = false
+  try {
+    isSuccess = document.execCommand('copy')
+  } catch { }
+
+  element.remove()
+
+  if (originalRange) {
+    selection.removeAllRanges()
+    selection.addRange(originalRange)
+  }
+
+  // Get the focus back on the previously focused element, if any
+  if (previouslyFocusedElement) {
+    previouslyFocusedElement.focus()
+  }
+
+  return isSuccess
+}

+ 24 - 0
ruoyi-ui/src/utils/dict.js

@@ -0,0 +1,24 @@
+import useDictStore from '@/store/modules/dict'
+import { getDicts } from '@/api/system/dict/data'
+
+/**
+ * 获取字典数据
+ */
+export function useDict(...args) {
+  const res = ref({})
+  return (() => {
+    args.forEach((dictType, index) => {
+      res.value[dictType] = []
+      const dicts = useDictStore().getDict(dictType)
+      if (dicts) {
+        res.value[dictType] = dicts
+      } else {
+        getDicts(dictType).then(resp => {
+          res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
+          useDictStore().setDict(dictType, res.value[dictType])
+        })
+      }
+    })
+    return toRefs(res.value)
+  })()
+}

+ 29 - 0
ruoyi-ui/src/utils/generator/drawingDefalut.js

@@ -0,0 +1,29 @@
+export default [
+  {
+    layout: 'colFormItem',
+    tagIcon: 'input',
+    label: '手机号',
+    vModel: 'mobile',
+    formId: 6,
+    tag: 'el-input',
+    placeholder: '请输入手机号',
+    defaultValue: '',
+    span: 24,
+    style: { width: '100%' },
+    clearable: true,
+    prepend: '',
+    append: '',
+    'prefix-icon': 'Cellphone',
+    'suffix-icon': '',
+    maxlength: 11,
+    'show-word-limit': true,
+    readonly: false,
+    disabled: false,
+    required: true,
+    changeTag: true,
+    regList: [{
+      pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
+      message: '手机号格式错误'
+    }]
+  }
+]

+ 49 - 0
ruoyi-ui/src/utils/theme.js

@@ -0,0 +1,49 @@
+// 处理主题样式
+export function handleThemeStyle(theme) {
+	document.documentElement.style.setProperty('--el-color-primary', theme)
+	for (let i = 1; i <= 9; i++) {
+		document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, `${getLightColor(theme, i / 10)}`)
+	}
+	for (let i = 1; i <= 9; i++) {
+		document.documentElement.style.setProperty(`--el-color-primary-dark-${i}`, `${getDarkColor(theme, i / 10)}`)
+	}
+}
+
+// hex颜色转rgb颜色
+export function hexToRgb(str) {
+	str = str.replace('#', '')
+	let hexs = str.match(/../g)
+	for (let i = 0; i < 3; i++) {
+		hexs[i] = parseInt(hexs[i], 16)
+	}
+	return hexs
+}
+
+// rgb颜色转Hex颜色
+export function rgbToHex(r, g, b) {
+	let hexs = [r.toString(16), g.toString(16), b.toString(16)]
+	for (let i = 0; i < 3; i++) {
+		if (hexs[i].length == 1) {
+			hexs[i] = `0${hexs[i]}`
+		}
+	}
+	return `#${hexs.join('')}`
+}
+
+// 变浅颜色值
+export function getLightColor(color, level) {
+	let rgb = hexToRgb(color)
+	for (let i = 0; i < 3; i++) {
+		rgb[i] = Math.floor((255 - rgb[i]) * level + rgb[i])
+	}
+	return rgbToHex(rgb[0], rgb[1], rgb[2])
+}
+
+// 变深颜色值
+export function getDarkColor(color, level) {
+	let rgb = hexToRgb(color)
+	for (let i = 0; i < 3; i++) {
+		rgb[i] = Math.floor(rgb[i] * (1 - level))
+	}
+	return rgbToHex(rgb[0], rgb[1], rgb[2])
+}

+ 14 - 0
ruoyi-ui/src/views/redirect/index.vue

@@ -0,0 +1,14 @@
+<template>
+  <div></div>
+</template>
+
+<script setup>
+import { useRoute, useRouter } from 'vue-router'
+
+const route = useRoute()
+const router = useRouter()
+const { params, query } = route
+const { path } = params
+
+router.replace({ path: '/' + path, query })
+</script>

+ 73 - 0
ruoyi-ui/vite.config.js

@@ -0,0 +1,73 @@
+import { defineConfig, loadEnv } from 'vite'
+import path from 'path'
+import createVitePlugins from './vite/plugins'
+
+// https://vitejs.dev/config/
+export default defineConfig(({ mode, command }) => {
+  const env = loadEnv(mode, process.cwd())
+  const { VITE_APP_ENV } = env
+  return {
+    // 部署生产环境和开发环境下的URL。
+    // 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
+    // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
+    base: VITE_APP_ENV === 'production' ? '/' : '/',
+    plugins: createVitePlugins(env, command === 'build'),
+    resolve: {
+      // https://cn.vitejs.dev/config/#resolve-alias
+      alias: {
+        // 设置路径
+        '~': path.resolve(__dirname, './'),
+        // 设置别名
+        '@': path.resolve(__dirname, './src')
+      },
+      // https://cn.vitejs.dev/config/#resolve-extensions
+      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
+    },
+    // 打包配置
+    build: {
+      // https://vite.dev/config/build-options.html
+      sourcemap: command === 'build' ? false : 'inline',
+      outDir: 'dist',
+      assetsDir: 'assets',
+      chunkSizeWarningLimit: 2000,
+      rollupOptions: {
+        output: {
+          chunkFileNames: 'static/js/[name]-[hash].js',
+          entryFileNames: 'static/js/[name]-[hash].js',
+          assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
+        }
+      }
+    },
+    // vite 相关配置
+    server: {
+      port: 80,
+      host: true,
+      open: true,
+      proxy: {
+        // https://cn.vitejs.dev/config/#server-proxy
+        '/dev-api': {
+          target: 'http://localhost:8080',
+          changeOrigin: true,
+          rewrite: (p) => p.replace(/^\/dev-api/, '')
+        }
+      }
+    },
+    //fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
+    css: {
+      postcss: {
+        plugins: [
+          {
+            postcssPlugin: 'internal:charset-removal',
+            AtRule: {
+              charset: (atRule) => {
+                if (atRule.name === 'charset') {
+                  atRule.remove()
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+})

+ 12 - 0
ruoyi-ui/vite/plugins/auto-import.js

@@ -0,0 +1,12 @@
+import autoImport from 'unplugin-auto-import/vite'
+
+export default function createAutoImport() {
+    return autoImport({
+        imports: [
+            'vue',
+            'vue-router',
+            'pinia'
+        ],
+        dts: false
+    })
+}

+ 28 - 0
ruoyi-ui/vite/plugins/compression.js

@@ -0,0 +1,28 @@
+import compression from 'vite-plugin-compression'
+
+export default function createCompression(env) {
+    const { VITE_BUILD_COMPRESS } = env
+    const plugin = []
+    if (VITE_BUILD_COMPRESS) {
+        const compressList = VITE_BUILD_COMPRESS.split(',')
+        if (compressList.includes('gzip')) {
+            // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
+            plugin.push(
+                compression({
+                    ext: '.gz',
+                    deleteOriginFile: false
+                })
+            )
+        }
+        if (compressList.includes('brotli')) {
+            plugin.push(
+                compression({
+                    ext: '.br',
+                    algorithm: 'brotliCompress',
+                    deleteOriginFile: false
+                })
+            )
+        }
+    }
+    return plugin
+}

+ 15 - 0
ruoyi-ui/vite/plugins/index.js

@@ -0,0 +1,15 @@
+import vue from '@vitejs/plugin-vue'
+
+import createAutoImport from './auto-import'
+import createSvgIcon from './svg-icon'
+import createCompression from './compression'
+import createSetupExtend from './setup-extend'
+
+export default function createVitePlugins(viteEnv, isBuild = false) {
+    const vitePlugins = [vue()]
+    vitePlugins.push(createAutoImport())
+	vitePlugins.push(createSetupExtend())
+    vitePlugins.push(createSvgIcon(isBuild))
+	isBuild && vitePlugins.push(...createCompression(viteEnv))
+    return vitePlugins
+}

+ 5 - 0
ruoyi-ui/vite/plugins/setup-extend.js

@@ -0,0 +1,5 @@
+import setupExtend from 'unplugin-vue-setup-extend-plus/vite'
+
+export default function createSetupExtend() {
+    return setupExtend({})
+}

+ 10 - 0
ruoyi-ui/vite/plugins/svg-icon.js

@@ -0,0 +1,10 @@
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import path from 'path'
+
+export default function createSvgIcon(isBuild) {
+    return createSvgIconsPlugin({
+		iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],
+        symbolId: 'icon-[dir]-[name]',
+        svgoOptions: isBuild
+    })
+}

部分文件因为文件数量过多而无法显示