├── yxboot-admin ├── src │ ├── hooks │ │ ├── config │ │ │ ├── index.ts │ │ │ └── dark.ts │ │ ├── setting │ │ │ ├── index.ts │ │ │ ├── useGlobSetting.ts │ │ │ ├── useMultipleTabSetting.ts │ │ │ ├── useMenuSetting.ts │ │ │ ├── useSiderSetting.ts │ │ │ └── useThemeSetting.ts │ │ ├── core │ │ │ └── onMountedOrActivated.ts │ │ ├── web │ │ │ ├── usePermission.ts │ │ │ ├── useSortable.ts │ │ │ └── usePage.ts │ │ └── event │ │ │ └── useWindowSizeFn.ts │ ├── components │ │ ├── Tree │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ └── BasicTree.vue │ │ ├── CountTo │ │ │ └── index.ts │ │ ├── Form │ │ │ ├── src │ │ │ │ ├── types │ │ │ │ │ └── hooks.ts │ │ │ │ └── hooks │ │ │ │ │ ├── useDict.ts │ │ │ │ │ ├── useFormItem.ts │ │ │ │ │ └── useLabelWidth.ts │ │ │ └── index.ts │ │ ├── Modal │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ ├── components │ │ │ │ └── ModalFooter.vue │ │ │ │ └── hooks │ │ │ │ └── useModalFullScreen.ts │ │ ├── Drawer │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ └── props.ts │ │ ├── Icon │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ └── SvgIcon.vue │ │ ├── registerGlobComp.ts │ │ ├── Basic │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ └── BasicTitle.vue │ │ ├── Table │ │ │ ├── index.ts │ │ │ └── src │ │ │ │ ├── types │ │ │ │ ├── componentType.ts │ │ │ │ └── tableAction.ts │ │ │ │ ├── components │ │ │ │ ├── settings │ │ │ │ │ ├── RedoSetting.vue │ │ │ │ │ ├── FullScreenSetting.vue │ │ │ │ │ └── SizeSetting.vue │ │ │ │ ├── editable │ │ │ │ │ ├── helper.ts │ │ │ │ │ └── CellComponent.ts │ │ │ │ └── TableTitle.vue │ │ │ │ ├── hooks │ │ │ │ ├── useLoading.ts │ │ │ │ ├── useTableContext.ts │ │ │ │ ├── useTableStyle.ts │ │ │ │ └── useTableForm.ts │ │ │ │ ├── const.ts │ │ │ │ └── componentMap.ts │ │ └── Button │ │ │ ├── src │ │ │ ├── props.ts │ │ │ ├── BasicButton.vue │ │ │ └── PopConfirmButton.vue │ │ │ └── index.ts │ ├── styles │ │ ├── config.less │ │ ├── index.less │ │ └── var │ │ │ ├── index.less │ │ │ ├── easing.less │ │ │ └── breakpoint.less │ ├── assets │ │ ├── images │ │ │ └── captcha.png │ │ └── icons │ │ │ └── moon.svg │ ├── layout │ │ ├── content │ │ │ ├── other │ │ │ │ ├── 500.vue │ │ │ │ ├── 403.vue │ │ │ │ └── 404.vue │ │ │ └── index.vue │ │ ├── header │ │ │ └── components │ │ │ │ ├── index.ts │ │ │ │ ├── Setting.vue │ │ │ │ ├── HeaderTrigger.vue │ │ │ │ ├── FullScreen.vue │ │ │ │ └── UserDropDown.vue │ │ ├── menu │ │ │ ├── types.ts │ │ │ └── components │ │ │ │ ├── Menu.vue │ │ │ │ └── MenuGroup.vue │ │ ├── tabs │ │ │ ├── components │ │ │ │ ├── TabRedo.vue │ │ │ │ └── FoldButton.vue │ │ │ └── types.ts │ │ ├── mix-menu │ │ │ └── components │ │ │ │ └── SubMenu.vue │ │ ├── sider │ │ │ ├── AppLogo.vue │ │ │ └── index.vue │ │ ├── footer │ │ │ └── index.vue │ │ ├── index.vue │ │ └── setting │ │ │ └── components │ │ │ ├── SwitchItem.vue │ │ │ └── SelectItem.vue │ ├── api │ │ ├── model │ │ │ ├── basicModel.ts │ │ │ ├── userModel.ts │ │ │ └── sysModel.ts │ │ └── sys │ │ │ ├── home.ts │ │ │ ├── dict.ts │ │ │ ├── auth.ts │ │ │ ├── dictData.ts │ │ │ ├── menu.ts │ │ │ ├── dept.ts │ │ │ ├── role.ts │ │ │ ├── file.ts │ │ │ └── user.ts │ ├── enums │ │ ├── pageEnum.ts │ │ ├── index.ts │ │ ├── statusEnum.ts │ │ ├── breakpointEnum.ts │ │ ├── httpEnum.ts │ │ ├── cacheEnum.ts │ │ ├── menuEnum.ts │ │ ├── appEnum.ts │ │ └── designSetting.ts │ ├── store │ │ ├── index.ts │ │ └── modules │ │ │ └── permission.ts │ ├── directives │ │ ├── index.ts │ │ └── permission.ts │ ├── utils │ │ ├── log.ts │ │ ├── http │ │ │ └── axios │ │ │ │ ├── retryConfig.ts │ │ │ │ ├── axiosRetry.ts │ │ │ │ ├── helper.ts │ │ │ │ ├── checkStatus.ts │ │ │ │ └── axiosTransform.ts │ │ ├── theme.ts │ │ ├── dateUtil.ts │ │ ├── uuid.ts │ │ ├── helper │ │ │ └── tsxHelper.tsx │ │ ├── lib │ │ │ └── echarts.ts │ │ ├── cache │ │ │ └── index.ts │ │ ├── propTypes.ts │ │ ├── event │ │ │ └── index.ts │ │ ├── cipher.ts │ │ └── is.ts │ ├── views │ │ ├── dashboard │ │ │ ├── analysis │ │ │ │ ├── components │ │ │ │ │ ├── props.ts │ │ │ │ │ ├── SiteAnalysis.vue │ │ │ │ │ ├── VisitAnalysisBar.vue │ │ │ │ │ ├── GrowCard.vue │ │ │ │ │ └── SalesProductPie.vue │ │ │ │ ├── data.ts │ │ │ │ └── analysis.vue │ │ │ └── workplace │ │ │ │ ├── components │ │ │ │ ├── QuickNav.vue │ │ │ │ ├── DynamicInfo.vue │ │ │ │ ├── ProjectCard.vue │ │ │ │ └── WorkbenchHeader.vue │ │ │ │ └── workplace.vue │ │ ├── redirect.vue │ │ └── sys │ │ │ ├── personal │ │ │ └── personal.vue │ │ │ ├── dept │ │ │ └── dept.data.ts │ │ │ ├── role │ │ │ └── role.data.ts │ │ │ ├── user │ │ │ ├── ResetPasswordModal.vue │ │ │ └── UserDrawer.vue │ │ │ ├── menu │ │ │ └── MenuDrawer.vue │ │ │ └── dict │ │ │ └── DictDrawer.vue │ ├── settings │ │ ├── encryptionSetting.ts │ │ └── designSetting.ts │ ├── App.vue │ ├── router │ │ ├── routes │ │ │ ├── about.ts │ │ │ ├── personal.ts │ │ │ ├── index.ts │ │ │ └── basic.ts │ │ ├── constant.ts │ │ ├── index.ts │ │ ├── mitt │ │ │ └── routeChange.ts │ │ ├── guard │ │ │ └── stateGuard.ts │ │ └── types.ts │ └── main.ts ├── public │ ├── logo.png │ ├── favicon.ico │ └── images │ │ ├── avatar-1.png │ │ ├── avatar-2.png │ │ ├── avatar-3.png │ │ ├── avatar-4.png │ │ ├── avatar-5.png │ │ ├── avatar-6.png │ │ └── avatar-7.png ├── .husky │ └── pre-commit ├── .env ├── types │ ├── utils.d.ts │ ├── modules.d.ts │ ├── index.d.ts │ ├── store.d.ts │ └── axios.d.ts ├── uno.config.ts ├── build │ ├── constant.ts │ ├── getConfigFileName.ts │ ├── vite │ │ ├── plugin │ │ │ ├── html.ts │ │ │ ├── import.ts │ │ │ ├── components.ts │ │ │ ├── svgSprite.ts │ │ │ └── compress.ts │ │ ├── utils │ │ │ ├── hash.ts │ │ │ └── env.ts │ │ └── proxy.ts │ └── generate │ │ └── generateModifyVars.ts ├── .gitignore ├── .env.development ├── .env.production ├── LICENSE └── tsconfig.json ├── yxboot-api └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── yxboot │ │ │ ├── common │ │ │ ├── base │ │ │ │ └── BaseEnum.java │ │ │ ├── vo │ │ │ │ ├── AccountToken.java │ │ │ │ └── Dict.java │ │ │ ├── exception │ │ │ │ ├── Asserts.java │ │ │ │ └── ApiException.java │ │ │ ├── aspect │ │ │ │ └── SysLogOperation.java │ │ │ ├── api │ │ │ │ └── ResultCode.java │ │ │ ├── pagination │ │ │ │ └── PageRequest.java │ │ │ ├── enums │ │ │ │ ├── LogTypeEnum.java │ │ │ │ ├── SexEnum.java │ │ │ │ ├── TemplateTypeEnum.java │ │ │ │ ├── MenuEnum.java │ │ │ │ └── StatusEnum.java │ │ │ └── cache │ │ │ │ └── SysUserCacheUtil.java │ │ │ ├── modules │ │ │ └── sys │ │ │ │ ├── mapper │ │ │ │ ├── SysLogMapper.java │ │ │ │ ├── SysDeptMapper.java │ │ │ │ ├── SysDictMapper.java │ │ │ │ ├── SysFileMapper.java │ │ │ │ ├── SysMenuMapper.java │ │ │ │ ├── SysUserMapper.java │ │ │ │ ├── SysDictDataMapper.java │ │ │ │ ├── SysRoleMenuMapper.java │ │ │ │ ├── SysUserRoleMapper.java │ │ │ │ └── SysRoleMapper.java │ │ │ │ ├── service │ │ │ │ ├── SysFileService.java │ │ │ │ ├── SysRoleMenuService.java │ │ │ │ ├── SysLogService.java │ │ │ │ ├── SysUserRoleService.java │ │ │ │ ├── SysRoleService.java │ │ │ │ └── SysDictService.java │ │ │ │ └── entity │ │ │ │ ├── SysRoleMenu.java │ │ │ │ └── SysUserRole.java │ │ │ ├── config │ │ │ ├── cache │ │ │ │ ├── CacheConstants.java │ │ │ │ └── JetCacheConfig.java │ │ │ ├── web │ │ │ │ ├── FaviconController.java │ │ │ │ ├── DatetimeHandler.java │ │ │ │ ├── GlobalException.java │ │ │ │ └── jackson │ │ │ │ │ └── EnumJsonSerializer.java │ │ │ ├── upload │ │ │ │ ├── FileEntity.java │ │ │ │ ├── uploader │ │ │ │ │ └── Uploader.java │ │ │ │ └── UploadConfig.java │ │ │ ├── properties │ │ │ │ └── IgnoredUrlsProperties.java │ │ │ ├── security │ │ │ │ ├── SecurityUser.java │ │ │ │ ├── handler │ │ │ │ │ ├── CustomAccessDeniedHandler.java │ │ │ │ │ └── CustomAuthenticationEntryPoint.java │ │ │ │ └── SysUserDetailsService.java │ │ │ └── mybatisflex │ │ │ │ └── MyBatisFlexConfig.java │ │ │ ├── YXBootApplication.java │ │ │ └── utils │ │ │ ├── UserUtil.java │ │ │ └── CusAccessObjectUtil.java │ └── resources │ │ ├── generator.properties │ │ └── application-dev.template.yml │ └── test │ └── java │ └── com │ └── yxboot │ └── test │ └── MockTest.java ├── .vscode ├── extensions.json └── launch.json ├── .gitignore ├── LICENSE └── pom.xml /yxboot-admin/src/hooks/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dark' 2 | export * from './useAppConfig' 3 | -------------------------------------------------------------------------------- /yxboot-admin/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/logo.png -------------------------------------------------------------------------------- /yxboot-admin/src/components/Tree/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BasicTree } from './src/BasicTree.vue' 2 | -------------------------------------------------------------------------------- /yxboot-admin/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/favicon.ico -------------------------------------------------------------------------------- /yxboot-admin/src/styles/config.less: -------------------------------------------------------------------------------- 1 | @import (reference) 'color.less'; 2 | @import (reference) 'var/index.less'; 3 | -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-1.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-2.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-3.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-4.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-5.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-6.png -------------------------------------------------------------------------------- /yxboot-admin/public/images/avatar-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/public/images/avatar-7.png -------------------------------------------------------------------------------- /yxboot-admin/src/assets/images/captcha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyazuo/yxboot/HEAD/yxboot-admin/src/assets/images/captcha.png -------------------------------------------------------------------------------- /yxboot-admin/src/styles/index.less: -------------------------------------------------------------------------------- 1 | @import 'color.less'; 2 | 3 | body { 4 | a { 5 | color: var(--primary-color); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/content/other/500.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /yxboot-admin/.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | cd yxboot-admin 5 | npm run lint:lint-staged 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/model/basicModel.ts: -------------------------------------------------------------------------------- 1 | export interface BasicResultModel { 2 | code: number 3 | msg: string 4 | data: T 5 | } 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/content/other/403.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /yxboot-admin/.env: -------------------------------------------------------------------------------- 1 | # port 2 | VITE_PORT = 3000 3 | 4 | # spa-title 5 | VITE_GLOB_APP_TITLE = YXBoot Admin 6 | 7 | # spa shortname 8 | VITE_GLOB_APP_SHORT_NAME = yxboot_admin 9 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/CountTo/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from '@/utils' 2 | import countTo from './src/CountTo.vue' 3 | 4 | export const CountTo = withInstall(countTo) 5 | -------------------------------------------------------------------------------- /yxboot-admin/types/utils.d.ts: -------------------------------------------------------------------------------- 1 | import type { ComputedRef, Ref } from 'vue' 2 | 3 | export type DynamicProps = { 4 | [P in keyof T]: Ref | T[P] | ComputedRef 5 | } 6 | -------------------------------------------------------------------------------- /yxboot-admin/uno.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, presetTypography, presetUno } from 'unocss' 2 | 3 | export default defineConfig({ 4 | presets: [presetUno(), presetTypography()] 5 | }) 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Form/src/types/hooks.ts: -------------------------------------------------------------------------------- 1 | export interface AdvanceState { 2 | isAdvanced: boolean 3 | hideAdvanceBtn: boolean 4 | isLoad: boolean 5 | actionSpan: number 6 | } 7 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/base/BaseEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.base; 2 | 3 | public interface BaseEnum { 4 | String getValue(); 5 | 6 | String getDesc(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /yxboot-admin/src/styles/var/index.less: -------------------------------------------------------------------------------- 1 | @import (reference) '../color.less'; 2 | @import 'easing'; 3 | @import 'breakpoint'; 4 | 5 | // headers 6 | @header-height: 48px; 7 | 8 | @multiple-height: 30px; 9 | -------------------------------------------------------------------------------- /yxboot-admin/build/constant.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The name of the configuration file entered in the production environment 3 | */ 4 | export const GLOB_CONFIG_FILE_NAME = '_app.config.js' 5 | 6 | export const OUTPUT_DIR = 'dist' 7 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Modal/index.ts: -------------------------------------------------------------------------------- 1 | import BasicModal from './src/BasicModal.vue' 2 | export { BasicModal } 3 | 4 | export { useModal, useModalInner } from './src/hooks/useModal' 5 | export * from './src/types/typing' 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Drawer/index.ts: -------------------------------------------------------------------------------- 1 | import BasicDrawer from './src/BasicDrawer.vue' 2 | 3 | export { useDrawer, useDrawerInner } from './src/hooks/useDrawer' 4 | export * from './src/types/typing' 5 | export { BasicDrawer } 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Icon/index.ts: -------------------------------------------------------------------------------- 1 | import Icon from './src/Icon.vue' 2 | import IconPicker from './src/IconPicker.vue' 3 | import SvgIcon from './src/SvgIcon.vue' 4 | 5 | export { Icon, IconPicker, SvgIcon } 6 | 7 | export default Icon 8 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/pageEnum.ts: -------------------------------------------------------------------------------- 1 | export enum PageEnum { 2 | // basic login path 3 | BASE_LOGIN = '/login', 4 | // basic home path 5 | BASE_HOME = '/dashboard/workplace', 6 | // error page path 7 | ERROR_PAGE = '/exception', 8 | } 9 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/registerGlobComp.ts: -------------------------------------------------------------------------------- 1 | import Antd from 'ant-design-vue' 2 | import type { App } from 'vue' 3 | import { Button } from './Button' 4 | 5 | export function registerGlobComp(app: App) { 6 | app.use(Antd).use(Button) 7 | } 8 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/index.ts: -------------------------------------------------------------------------------- 1 | export * from './appEnum' 2 | export * from './cacheEnum' 3 | export * from './designSetting' 4 | export * from './httpEnum' 5 | export * from './menuEnum' 6 | export * from './pageEnum' 7 | export * from './statusEnum' 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "mikestead.dotenv", 6 | "mrmlnc.vscode-less", 7 | "stylelint.vscode-stylelint", 8 | "vue.volar" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /yxboot-admin/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createPinia } from 'pinia' 2 | import type { App } from 'vue' 3 | 4 | const store = createPinia() 5 | 6 | export function setupStore(app: App) { 7 | app.use(store) 8 | } 9 | 10 | export { store } 11 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Basic/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from '@/utils' 2 | import basicHelp from './src/BasicHelp.vue' 3 | import basicTitle from './src/BasicTitle.vue' 4 | 5 | export const BasicTitle = withInstall(basicTitle) 6 | export const BasicHelp = withInstall(basicHelp) 7 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/statusEnum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 状态枚举 3 | */ 4 | export enum StatusEnum { 5 | NORMAL = 'normal', 6 | INVALID = 'invalid', 7 | } 8 | 9 | export const statusOptions = [ 10 | { label: '正常', value: 'normal' }, 11 | { label: '无效', value: 'invalid' }, 12 | ] 13 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/header/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FullScreen } from './FullScreen.vue' 2 | export { default as HeaderTrigger } from './HeaderTrigger.vue' 3 | export { default as Setting } from './Setting.vue' 4 | export { default as UserDropDown } from './UserDropDown.vue' 5 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/home.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | list = '/sys/log/list', 6 | } 7 | 8 | export const listOptionLog = (params: any) => http.get({ url: Api.list, params }) 9 | -------------------------------------------------------------------------------- /yxboot-admin/src/directives/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Configure and register global directives 3 | */ 4 | import type { App } from 'vue' 5 | import { setupPermissionDirective } from './permission' 6 | 7 | export function setupGlobDirectives(app: App) { 8 | setupPermissionDirective(app) 9 | } 10 | -------------------------------------------------------------------------------- /yxboot-admin/build/getConfigFileName.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Get the configuration file variable name 3 | * @param env 4 | */ 5 | export const getConfigFileName = (env: Record) => { 6 | return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '') 7 | } 8 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useGlobSetting' 2 | export * from './useHeaderSetting' 3 | export * from './useMenuSetting' 4 | export * from './useMultipleTabSetting' 5 | export * from './useProjectSetting' 6 | export * from './useSiderSetting' 7 | export * from './useThemeSetting' 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Intellij project files 2 | *.iml 3 | .idea/ 4 | 5 | yxboot-logs/ 6 | 7 | # Others 8 | target/ 9 | logs/ 10 | .DS_Store 11 | 12 | *.class 13 | 14 | # Package Files # 15 | *.war 16 | *.ear 17 | 18 | # jrebel配置文件# 19 | rebel.xml 20 | rebel-remote.xml 21 | 22 | # 配置文件 23 | application-dev.yml -------------------------------------------------------------------------------- /yxboot-admin/src/api/model/userModel.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description: Login interface parameters 3 | */ 4 | export interface LoginParams { 5 | username: string 6 | password: string 7 | captchaCode: string 8 | } 9 | 10 | export interface RoleInfo { 11 | roleName: string 12 | value: string 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/index.ts: -------------------------------------------------------------------------------- 1 | export { default as BasicTable } from './src/BasicTable.vue' 2 | export { default as TableAction } from './src/components/TableAction.vue' 3 | export { useTable } from './src/hooks/useTable' 4 | export * from './src/types/table' 5 | export * from './src/types/tableAction' 6 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/types/componentType.ts: -------------------------------------------------------------------------------- 1 | export type ComponentType = 2 | | 'Input' 3 | | 'InputNumber' 4 | | 'Select' 5 | | 'ApiSelect' 6 | | 'ApiTreeSelect' 7 | | 'AutoComplete' 8 | | 'Checkbox' 9 | | 'Switch' 10 | | 'DatePicker' 11 | | 'TimePicker' 12 | | 'RadioGroup' 13 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/log.ts: -------------------------------------------------------------------------------- 1 | const projectName = import.meta.env.VITE_GLOB_APP_TITLE 2 | 3 | export function warn(message: string) { 4 | console.warn(`[${projectName} warn]:${message}`) 5 | } 6 | 7 | export function error(message: string) { 8 | throw new Error(`[${projectName} error]:${message}`) 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "chrome", 6 | "request": "launch", 7 | "name": "Launch Chrome", 8 | "url": "http://localhost:3000", 9 | "webRoot": "${workspaceFolder}/src", 10 | "sourceMaps": true 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/types/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | const Component: DefineComponent, Record, any> 4 | export default Component 5 | } 6 | 7 | declare module 'virtual:*' { 8 | const result: any 9 | export default result 10 | } 11 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Form/index.ts: -------------------------------------------------------------------------------- 1 | import BasicForm from './src/BasicForm.vue' 2 | 3 | export { default as ApiSelect } from './src/components/ApiSelect.vue' 4 | export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue' 5 | export { useForm } from './src/hooks/useForm' 6 | export * from './src/types/form' 7 | 8 | export { BasicForm } 9 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysLog; 5 | 6 | /** 7 | * 日志表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysLogMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysDeptMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysDept; 5 | 6 | /** 7 | * 部门表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysDeptMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysDictMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysDict; 5 | 6 | /** 7 | * 字典表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysDictMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysFileMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysFile; 5 | 6 | /** 7 | * 附件表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysFileMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysMenuMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysMenu; 5 | 6 | /** 7 | * 菜单表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysMenuMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysUser; 5 | 6 | /** 7 | * 用户表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysUserMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/menu/types.ts: -------------------------------------------------------------------------------- 1 | export type Key = string | number 2 | export interface MenuState { 3 | // 默认选中的列表 4 | defaultSelectedKeys: Key[] 5 | 6 | // 缩进 7 | inlineIndent?: number 8 | 9 | // 展开数组 10 | openKeys: Key[] 11 | 12 | // 当前选中的菜单项 key 数组 13 | selectedKeys: Key[] 14 | 15 | // 收缩状态下展开的数组 16 | collapsedOpenKeys: Key[] 17 | } 18 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/cache/CacheConstants.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.cache; 2 | 3 | public class CacheConstants { 4 | public static final int CACHE_EXPIRE_DAYS = 3; 5 | 6 | public static final String SYS_USER_VALUE_CACHE_KEY = "yxboot:sys:user:value::"; 7 | public static final String SYS_DICT_VALUE_CACHE_KEY = "yxboot:sys:dict:value::"; 8 | } 9 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysDictDataMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysDictData; 5 | 6 | /** 7 | * 字典数据表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysDictDataMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysRoleMenuMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysRoleMenu; 5 | 6 | /** 7 | * 角色菜单表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysRoleMenuMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysUserRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysUserRole; 5 | 6 | /** 7 | * 用户角色表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysUserRoleMapper extends BaseMapper { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/mapper/SysRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.mapper; 2 | 3 | import com.mybatisflex.core.BaseMapper; 4 | import com.yxboot.modules.sys.entity.SysRole; 5 | 6 | /** 7 | * 角色表 Mapper 8 | * 9 | * @author Boya 10 | */ 11 | public interface SysRoleMapper extends BaseMapper { 12 | SysRole selectByUserId(Long userId); 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Form/src/hooks/useDict.ts: -------------------------------------------------------------------------------- 1 | import type { BasicResultModel } from '@/api/model/basicModel' 2 | import { http } from '@/utils/http/axios' 3 | 4 | export function useDict() { 5 | enum Api { 6 | all = '/sys/dict/data/all', 7 | } 8 | 9 | const api = (params: any) => http.get({ url: Api.all, params }) 10 | 11 | return { 12 | api, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/core/onMountedOrActivated.ts: -------------------------------------------------------------------------------- 1 | import { nextTick, onActivated, onMounted } from 'vue' 2 | 3 | export function onMountedOrActivated(hook: Fn) { 4 | let mounted: boolean 5 | 6 | onMounted(() => { 7 | hook() 8 | nextTick(() => { 9 | mounted = true 10 | }) 11 | }) 12 | 13 | onActivated(() => { 14 | if (mounted) { 15 | hook() 16 | } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/components/props.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue' 2 | 3 | export interface BasicProps { 4 | width: string 5 | height: string 6 | } 7 | export const basicProps = { 8 | width: { 9 | type: String as PropType, 10 | default: '100%', 11 | }, 12 | height: { 13 | type: String as PropType, 14 | default: '280px', 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/YXBootApplication.java: -------------------------------------------------------------------------------- 1 | package com.yxboot; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class YXBootApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(YXBootApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/web/FaviconController.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.web; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class FaviconController { 8 | @GetMapping("/favicon.ico") 9 | public String favicon() { 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /yxboot-admin/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | auto-imports.d.ts 15 | components.d.ts 16 | 17 | # Editor directories and files 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | yarn.lock 26 | pnpm-lock.yaml 27 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/model/sysModel.ts: -------------------------------------------------------------------------------- 1 | import type { StatusEnum } from '@/enums/statusEnum' 2 | 3 | export interface SysMenu { 4 | menuId: number 5 | name: string 6 | descn: string 7 | code: string 8 | type: number 9 | icon: string 10 | path: string 11 | component: string 12 | parentId: number 13 | display: number 14 | sort: number 15 | status: StatusEnum 16 | children: Array 17 | } 18 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/vo/AccountToken.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.vo; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class AccountToken { 7 | 8 | private Long userId; 9 | 10 | private String username; 11 | 12 | private String name; 13 | 14 | private String avatar; 15 | 16 | private String phone; 17 | 18 | private String email; 19 | 20 | private String token; 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/settings/encryptionSetting.ts: -------------------------------------------------------------------------------- 1 | import { isDevMode } from '@/utils/env' 2 | 3 | // System default cache time, in seconds 4 | export const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7 5 | 6 | // aes encryption key 7 | export const cacheCipher = { 8 | key: '_11111000001111@', 9 | iv: '@11111000001111_', 10 | } 11 | 12 | // Whether the system cache is encrypted using aes 13 | export const enableStorageEncryption = !isDevMode() 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/web/usePermission.ts: -------------------------------------------------------------------------------- 1 | import { usePermissionStoreWithOut } from '@/store/modules/permission' 2 | 3 | export function usePermission() { 4 | const permissionStore = usePermissionStoreWithOut() 5 | 6 | function hasPermission(code) { 7 | if (!code) return true 8 | const menuCode = permissionStore.getMenusCode 9 | return menuCode.includes(code) 10 | } 11 | 12 | return { 13 | hasPermission, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/exception/Asserts.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.exception; 2 | 3 | 4 | import com.yxboot.common.api.ResultCode; 5 | 6 | /** 7 | * 断言处理类,用于抛出各种API异常 8 | */ 9 | public class Asserts { 10 | public static void fail(String message) { 11 | throw new ApiException(message); 12 | } 13 | 14 | public static void fail(ResultCode resultCode) { 15 | throw new ApiException(resultCode); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/upload/FileEntity.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.upload; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 文件上传实体类 7 | * 8 | * @author Boya 9 | */ 10 | @Data 11 | public class FileEntity { 12 | private String originName; 13 | private String fileName; 14 | private Long size; 15 | private String path; 16 | private String url; 17 | private String hash; 18 | private String contentType; 19 | } 20 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Button/src/props.ts: -------------------------------------------------------------------------------- 1 | export const buttonProps = { 2 | color: { type: String, validator: (v: string) => ['error', 'warning', 'success', ''].includes(v) }, 3 | loading: { type: Boolean }, 4 | disabled: { type: Boolean }, 5 | preIcon: { type: String }, 6 | postIcon: { type: String }, 7 | iconSize: { type: Number, default: 14 }, 8 | onClick: { type: [Function, Array] as PropType<(() => any) | (() => any)[]>, default: null }, 9 | } 10 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/plugin/html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin to minimize and use ejs template syntax in index.html. 3 | * https://github.com/anncwb/vite-plugin-html 4 | */ 5 | import type { PluginOption } from 'vite' 6 | import { createHtmlPlugin } from 'vite-plugin-html' 7 | 8 | export function configHtmlPlugin({ isBuild }: { isBuild: boolean }) { 9 | const htmlPlugin: PluginOption[] = createHtmlPlugin({ 10 | minify: isBuild, 11 | }) 12 | return htmlPlugin 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/plugin/import.ts: -------------------------------------------------------------------------------- 1 | import AutoImport from 'unplugin-auto-import/vite' 2 | import type { PluginOption } from 'vite' 3 | 4 | export function configImportPlugin() { 5 | const importPlugin: PluginOption = AutoImport({ 6 | imports: ['vue', 'vue-router', 'vue-i18n', 'vue/macros', '@vueuse/head', '@vueuse/core'], 7 | dts: 'src/auto-imports.d.ts', 8 | dirs: ['src/composables', 'src/stores'], 9 | vueTemplate: true, 10 | }) 11 | return importPlugin 12 | } 13 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | import type { ExtractPropTypes } from 'vue' 2 | import { withInstall } from '@/utils' 3 | import button from './src/BasicButton.vue' 4 | import popConfirmButton from './src/PopConfirmButton.vue' 5 | import type { buttonProps } from './src/props' 6 | 7 | export const Button = withInstall(button) 8 | export const PopConfirmButton = withInstall(popConfirmButton) 9 | export declare type ButtonProps = Partial> 10 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/http/axios/retryConfig.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios' 2 | 3 | export class RetryConfig implements AxiosRequestConfig { 4 | __retryCount: number 5 | requestOptions: { retryRequest: { waitTime: number; count: number } } 6 | constructor(config: InternalAxiosRequestConfig) { 7 | Object.keys(config).forEach((key: string) => { 8 | this[key] = config[key] 9 | console.log(key) 10 | }) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/content/other/404.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/vo/Dict.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | public class Dict implements Serializable { 11 | private String code; 12 | private String label; 13 | private String value; 14 | 15 | public Dict() { 16 | } 17 | 18 | public Dict(String value) { 19 | this.value = value; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/cache/JetCacheConfig.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.cache; 2 | 3 | import com.alicp.jetcache.anno.config.EnableMethodCache; 4 | import com.alicp.jetcache.anno.support.JetCacheBaseBeans; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | @Configuration 9 | @EnableMethodCache(basePackages = "com.yxboot") 10 | @Import(JetCacheBaseBeans.class) 11 | public class JetCacheConfig { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/header/components/Setting.vue: -------------------------------------------------------------------------------- 1 | 7 | 16 | -------------------------------------------------------------------------------- /yxboot-admin/.env.development: -------------------------------------------------------------------------------- 1 | # Whether to open mock 2 | VITE_USE_MOCK = true 3 | 4 | # public path 5 | VITE_PUBLIC_PATH = / 6 | 7 | # Cross-domain proxy, you can configure multiple 8 | # Please note that no line breaks 9 | VITE_PROXY = [["/api","http://localhost:9000/"]] 10 | 11 | # Delete console 12 | VITE_DROP_CONSOLE = false 13 | 14 | # Basic interface address SPA 15 | VITE_GLOB_API_URL=/api 16 | 17 | # File upload address, optional 18 | VITE_GLOB_UPLOAD_URL=/upload 19 | 20 | # Interface prefix 21 | VITE_GLOB_API_URL_PREFIX= 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 13 | 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/workplace/components/QuickNav.vue: -------------------------------------------------------------------------------- 1 | 11 | 15 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/plugin/components.ts: -------------------------------------------------------------------------------- 1 | import Components from 'unplugin-vue-components/vite' 2 | import type { PluginOption } from 'vite' 3 | 4 | export function configComponentsPlugin() { 5 | const componentsPlugin: PluginOption = Components({ 6 | // allow auto load markdown components under `./src/components/` 7 | extensions: ['vue', 'md'], 8 | // allow auto import and register components used in markdown 9 | include: [/\.vue$/, /\.vue\?vue/, /\.md$/], 10 | dts: 'src/components.d.ts', 11 | }) 12 | return componentsPlugin 13 | } 14 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/menu/components/Menu.vue: -------------------------------------------------------------------------------- 1 | 10 | 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/settings/RedoSetting.vue: -------------------------------------------------------------------------------- 1 | 9 | 21 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/utils/hash.ts: -------------------------------------------------------------------------------- 1 | import { createHash } from 'node:crypto' 2 | 3 | function createContentHash(content: string, hashLSize = 12) { 4 | const hash = createHash('sha256').update(content) 5 | return hash.digest('hex').slice(0, hashLSize) 6 | } 7 | function strToHex(str: string) { 8 | const result: string[] = [] 9 | for (let i = 0; i < str.length; ++i) { 10 | const hex = str.charCodeAt(i).toString(16) 11 | result.push(('000' + hex).slice(-4)) 12 | } 13 | return result.join('').toUpperCase() 14 | } 15 | 16 | export { createContentHash, strToHex } 17 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/aspect/SysLogOperation.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.aspect; 2 | 3 | import com.yxboot.common.enums.LogTypeEnum; 4 | 5 | import java.lang.annotation.*; 6 | 7 | import static java.lang.annotation.ElementType.METHOD; 8 | import static java.lang.annotation.ElementType.TYPE; 9 | 10 | 11 | @Target({METHOD, TYPE}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Inherited 14 | @Documented 15 | public @interface SysLogOperation { 16 | String value() default ""; 17 | 18 | LogTypeEnum type() default LogTypeEnum.OPERATE; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/plugin/svgSprite.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Vite Plugin for fast creating SVG sprites. 3 | * https://github.com/anncwb/vite-plugin-svg-icons 4 | */ 5 | import { resolve } from 'node:path' 6 | import type { PluginOption } from 'vite' 7 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' 8 | 9 | export function configSvgIconsPlugin({ isBuild }: { isBuild: boolean }) { 10 | const svgIconsPlugin = createSvgIconsPlugin({ 11 | iconDirs: [resolve(process.cwd(), 'src/assets/icons')], 12 | svgoOptions: isBuild, 13 | }) 14 | return svgIconsPlugin as PluginOption 15 | } 16 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/routes/about.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router' 2 | import { LAYOUT } from '@/router/constant' 3 | 4 | export const ABOUT_ROUTE: RouteRecordRaw = { 5 | path: '/about', 6 | name: 'About', 7 | component: LAYOUT, 8 | redirect: '/about/index', 9 | children: [ 10 | { 11 | path: 'index', 12 | name: 'AboutPage', 13 | component: () => import('@/views/sys/about/index.vue'), 14 | meta: { 15 | title: '关于', 16 | icon: 'simple-icons:about-dot-me', 17 | hideMenu: true, 18 | }, 19 | }, 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-api/src/test/java/com/yxboot/test/MockTest.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.test; 2 | 3 | 4 | import com.yxboot.YXBootApplication; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | import org.springframework.test.context.web.WebAppConfiguration; 10 | 11 | @RunWith(SpringRunner.class) 12 | @SpringBootTest(classes = YXBootApplication.class) 13 | @WebAppConfiguration 14 | public class MockTest { 15 | @Test 16 | public void testRun() { 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/constant.ts: -------------------------------------------------------------------------------- 1 | import { RouterView } from 'vue-router' 2 | 3 | export const REDIRECT_NAME = 'Redirect' 4 | 5 | export const PARENT_LAYOUT_NAME = 'ParentLayout' 6 | 7 | export const PAGE_NOT_FOUND_NAME = 'PageNotFound' 8 | 9 | export const EXCEPTION_COMPONENT = () => import('@/layout/content/other/404.vue') 10 | 11 | /** 12 | * @description: default layout 13 | */ 14 | export const LAYOUT = () => import('@/layout/index.vue') 15 | 16 | /** 17 | * @description: parent-layout 18 | */ 19 | export const PARENT_LAYOUT = { 20 | name: PARENT_LAYOUT_NAME, 21 | render: () => h(RouterView), 22 | } 23 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/theme.ts: -------------------------------------------------------------------------------- 1 | export function toggleClass(flag: boolean, clsName: string, target?: HTMLElement) { 2 | const targetEl = target || document.body 3 | let { className } = targetEl 4 | className = className.replace(clsName, '') 5 | targetEl.className = (flag ? `${className} ${clsName} ` : className).trim() 6 | } 7 | 8 | export function setCssVar(prop: string, val: any, dom = document.documentElement) { 9 | dom.style.setProperty(prop, val) 10 | } 11 | 12 | export function getCssVar(prop: string, dom: HTMLElement = document.documentElement) { 13 | return dom.style.getPropertyValue(prop) 14 | } 15 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/routes/personal.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router' 2 | import { LAYOUT } from '@/router/constant' 3 | 4 | export const PERSONAL_ROUTE: RouteRecordRaw = { 5 | path: '/personal', 6 | name: 'personal', 7 | component: LAYOUT, 8 | redirect: '/personal/index', 9 | children: [ 10 | { 11 | path: 'index', 12 | name: 'personalPage', 13 | component: () => import('@/views/sys/personal/personal.vue'), 14 | meta: { 15 | title: '个人中心', 16 | icon: 'ant-design:user-outlined', 17 | hideMenu: true, 18 | }, 19 | }, 20 | ], 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/upload/uploader/Uploader.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.upload.uploader; 2 | 3 | import com.yxboot.config.upload.FileEntity; 4 | import org.springframework.web.multipart.MultipartFile; 5 | 6 | /** 7 | * 文件上传接口 8 | */ 9 | public interface Uploader { 10 | 11 | /** 12 | * 上传文件 13 | 】 */ 14 | FileEntity upload(MultipartFile file); 15 | 16 | FileEntity upload(MultipartFile file, String dir); 17 | 18 | /** 19 | * 删除文件 20 | */ 21 | void delete(String path); 22 | 23 | /** 24 | * 重命名文件 25 | */ 26 | void rename(String path, String fileName); 27 | } 28 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/properties/IgnoredUrlsProperties.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.properties; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * @author Boya 12 | */ 13 | @Data 14 | @Configuration 15 | @ConfigurationProperties(prefix = "ignored") 16 | public class IgnoredUrlsProperties { 17 | 18 | private List urls = new ArrayList<>(); 19 | 20 | private List limitUrls = new ArrayList<>(); 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/hooks/useLoading.ts: -------------------------------------------------------------------------------- 1 | import { type ComputedRef, computed, ref, unref, watch } from 'vue' 2 | import type { BasicTableProps } from '../types/table' 3 | 4 | export function useLoading(props: ComputedRef) { 5 | const loadingRef = ref(unref(props).loading) 6 | 7 | watch( 8 | () => unref(props).loading, 9 | (loading) => { 10 | loadingRef.value = loading 11 | }, 12 | ) 13 | 14 | const getLoading = computed(() => unref(loadingRef)) 15 | 16 | function setLoading(loading: boolean) { 17 | loadingRef.value = loading 18 | } 19 | 20 | return { getLoading, setLoading } 21 | } 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/settings/designSetting.ts: -------------------------------------------------------------------------------- 1 | import { ThemeEnum } from '../enums/appEnum' 2 | 3 | export const prefixCls = 'yxboot' 4 | 5 | export const darkMode = ThemeEnum.LIGHT 6 | 7 | // app theme preset color 8 | export const APP_PRESET_COLOR_LIST: string[] = ['#1677ff', '#f5222d', '#fa541c', '#faad14', '#13c2c2', '#52c41a', '#2f54eb', '#722ed1'] 9 | 10 | // sider preset color 11 | export const SIDE_BAR_BG_COLOR_LIST: string[] = [ 12 | //'#001529', 13 | //'#212121', 14 | '#273352', 15 | '#ffffff', 16 | //'#191b24', 17 | //'#191a23', 18 | //'#304156', 19 | //'#001628', 20 | //'#28333E', 21 | //'#344058', 22 | //'#383f45' 23 | ] 24 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/header/components/HeaderTrigger.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/tabs/components/TabRedo.vue: -------------------------------------------------------------------------------- 1 | 6 | 24 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' 3 | import { setupRouterGuard } from '@/router/guard/index' 4 | import { basicRoutes } from './routes' 5 | 6 | const router = createRouter({ 7 | // 创建 WebHistory 8 | history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH), 9 | // 应该添加到路由的初始路由列表 10 | routes: basicRoutes as unknown as RouteRecordRaw[], 11 | // 是否应该禁止尾部斜杠。默认为假 12 | strict: true, 13 | }) 14 | export default router 15 | 16 | // config router 17 | export function setupRouter(app: App) { 18 | app.use(router) 19 | setupRouterGuard(router) 20 | } 21 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/mix-menu/components/SubMenu.vue: -------------------------------------------------------------------------------- 1 | 10 | 25 | 26 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/dict.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | list = '/sys/dict/list', 6 | get = '/sys/dict/get', 7 | save = '/sys/dict/save', 8 | remove = '/sys/dict/remove', 9 | } 10 | 11 | export const listDict = (params: any) => http.get({ url: Api.list, params }) 12 | export const getDict = (params: any) => http.get({ url: Api.get, params }) 13 | export const saveDict = (data: any) => http.post({ url: Api.save, data }) 14 | export const removeDict = (params: any) => http.delete({ url: Api.remove, params }) 15 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/breakpointEnum.ts: -------------------------------------------------------------------------------- 1 | export enum sizeEnum { 2 | XS = 'XS', 3 | SM = 'SM', 4 | MD = 'MD', 5 | LG = 'LG', 6 | XL = 'XL', 7 | XXL = 'XXL', 8 | } 9 | 10 | export enum screenEnum { 11 | XS = 320, 12 | SM = 640, 13 | MD = 768, 14 | LG = 960, 15 | XL = 1280, 16 | XXL = 1536, 17 | } 18 | 19 | const screenMap = new Map() 20 | 21 | screenMap.set(sizeEnum.XS, screenEnum.XS) 22 | screenMap.set(sizeEnum.SM, screenEnum.SM) 23 | screenMap.set(sizeEnum.MD, screenEnum.MD) 24 | screenMap.set(sizeEnum.LG, screenEnum.LG) 25 | screenMap.set(sizeEnum.XL, screenEnum.XL) 26 | screenMap.set(sizeEnum.XXL, screenEnum.XXL) 27 | 28 | export { screenMap } 29 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/auth.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | import type { LoginParams } from '../model/userModel' 4 | 5 | enum Api { 6 | login = '/auth/login', 7 | profile = '/auth/profile', 8 | permissions = '/auth/permissions', 9 | captcha = '/auth/captcha', 10 | } 11 | 12 | export const login = (params: LoginParams) => http.post({ url: Api.login, params }) 13 | export const profile = () => http.get({ url: Api.profile }) 14 | export const permissions = () => http.get({ url: Api.permissions }) 15 | export const captcha = () => http.get({ url: Api.captcha }) 16 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/tabs/types.ts: -------------------------------------------------------------------------------- 1 | import type { RouteLocationNormalized } from 'vue-router' 2 | 3 | export interface DropMenu { 4 | onClick?: Fn 5 | to?: string 6 | icon?: string 7 | event: string | number 8 | text: string 9 | disabled?: boolean 10 | divider?: boolean 11 | } 12 | 13 | export enum TabContentEnum { 14 | TAB_TYPE, 15 | EXTRA_TYPE, 16 | } 17 | 18 | export interface TabContentProps { 19 | tabItem: RouteLocationNormalized 20 | type?: TabContentEnum 21 | trigger?: ('click' | 'hover' | 'contextmenu')[] 22 | } 23 | 24 | export enum MenuEventEnum { 25 | REFRESH_PAGE, 26 | CLOSE_CURRENT, 27 | CLOSE_LEFT, 28 | CLOSE_RIGHT, 29 | CLOSE_OTHER, 30 | CLOSE_ALL, 31 | SCALE, 32 | } 33 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/httpEnum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description: Request result set 3 | */ 4 | export enum ResultEnum { 5 | SUCCESS = 0, 6 | ERROR = 1, 7 | TIMEOUT = 401, 8 | TYPE = 'success', 9 | } 10 | 11 | /** 12 | * @description: request method 13 | */ 14 | export enum RequestEnum { 15 | GET = 'GET', 16 | POST = 'POST', 17 | PUT = 'PUT', 18 | DELETE = 'DELETE', 19 | } 20 | 21 | /** 22 | * @description: contentType 23 | */ 24 | export enum ContentTypeEnum { 25 | // json 26 | JSON = 'application/json;charset=UTF-8', 27 | // form-data qs 28 | FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', 29 | // form-data upload 30 | FORM_DATA = 'multipart/form-data;charset=UTF-8', 31 | } 32 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/security/SecurityUser.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.security; 2 | 3 | import org.springframework.security.core.GrantedAuthority; 4 | import org.springframework.security.core.userdetails.User; 5 | 6 | import java.util.Collection; 7 | 8 | /** 9 | * 封装 SecurityUser 10 | * @author Boya 11 | */ 12 | public class SecurityUser extends User { 13 | 14 | private Long userId; 15 | 16 | public SecurityUser(Long userId, String username, String password, Collection authorities) { 17 | super(username, password, authorities); 18 | this.userId = userId; 19 | } 20 | 21 | public Long getUserId() { 22 | return userId; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/hooks/useTableContext.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | import { type ComputedRef, inject, provide } from 'vue' 3 | import type { BasicTableProps, TableActionType } from '../types/table' 4 | 5 | const key = Symbol('s-table') 6 | 7 | type Instance = Partial & { 8 | wrapRef: Ref> 9 | getBindValues: ComputedRef 10 | } 11 | 12 | type RetInstance = Omit & { 13 | getBindValues: ComputedRef 14 | } 15 | 16 | export function createTableContext(instance: Instance) { 17 | provide(key, instance) 18 | } 19 | 20 | export function useTableContext(): RetInstance { 21 | return inject(key) as RetInstance 22 | } 23 | -------------------------------------------------------------------------------- /yxboot-api/src/main/resources/generator.properties: -------------------------------------------------------------------------------- 1 | # 代码生成器,配置信息 2 | # 包名 3 | package=com.yxboot 4 | # 作者 5 | author=Boya 6 | # Email 7 | email=6989006@qq.com 8 | # 自动去除表前缀,默认是 true 9 | autoRemovePre=false 10 | # 类型转换,配置信息 11 | tinyint=TINYINT|Integer 12 | smallint=SMALLINT|Integer 13 | mediumint=INTEGER|Integer 14 | int=INTEGER|Integer 15 | integer=INTEGER|Integer 16 | bigint=BIGINT|Long 17 | float=FLOAT|Float 18 | double=DOUBLE|Double 19 | decimal=DECIMAL|BigDecimal 20 | bit=BIT|Boolean 21 | char=CHAR|String 22 | varchar=VARCHAR|String 23 | tinytext=LONGVARCHAR|String 24 | text=LONGVARCHAR|String 25 | mediumtext=LONGVARCHAR|String 26 | longtext=LONGVARCHAR|String 27 | date=DATE|Date 28 | datetime=TIMESTAMP|Date 29 | timestamp=TIMESTAMP|Date 30 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/settings/FullScreenSetting.vue: -------------------------------------------------------------------------------- 1 | 10 | 19 | -------------------------------------------------------------------------------- /yxboot-admin/types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare type Fn = (...arg: T[]) => R 2 | 3 | declare type PromiseFn = (...arg: T[]) => Promise 4 | 5 | declare type RefType = T | null 6 | 7 | declare type LabelValueOptions = { 8 | label: string 9 | value: any 10 | [key: string]: string | number | boolean 11 | }[] 12 | 13 | declare type EmitType = ReturnType 14 | 15 | declare type TargetContext = '_self' | '_blank' 16 | 17 | declare interface ComponentElRef { 18 | $el: T 19 | } 20 | 21 | declare type ComponentRef = ComponentElRef | null 22 | 23 | declare type ElRef = Nullable 24 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/editable/helper.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentType } from '../../types/componentType' 2 | 3 | /** 4 | * @description: 生成placeholder 5 | */ 6 | export function createPlaceholderMessage(component: ComponentType) { 7 | if (component.includes('Input') || component.includes('AutoComplete')) { 8 | return '请选择' 9 | } 10 | if (component.includes('Picker')) { 11 | return '请选择' 12 | } 13 | 14 | if ( 15 | component.includes('Select') || 16 | component.includes('Checkbox') || 17 | component.includes('Radio') || 18 | component.includes('Switch') || 19 | component.includes('DatePicker') || 20 | component.includes('TimePicker') 21 | ) { 22 | return '请选择' 23 | } 24 | return '' 25 | } 26 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/api/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.api; 2 | 3 | /** 4 | * 响应码枚举,参考HTTP状态码的语义 5 | */ 6 | public enum ResultCode { 7 | SUCCESS(0, "操作成功"), 8 | FAIL(1, "操作失败"), 9 | VALIDATE_FAILED(400, "参数检验失败"), 10 | UNAUTHORIZED(401, "暂未登录或token已经过期"), 11 | FORBIDDEN(403, "没有相关权限"), 12 | NOT_FOUND(404, "资源未找到"), 13 | INTERNAL_SERVER_ERROR(500, "服务内部错误"); 14 | 15 | private Integer code; 16 | private String msg; 17 | 18 | ResultCode(Integer code, String msg) { 19 | this.code = code; 20 | this.msg = msg; 21 | } 22 | 23 | public Integer getCode() { 24 | return code; 25 | } 26 | 27 | public String getMsg() { 28 | return msg; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/config/dark.ts: -------------------------------------------------------------------------------- 1 | import { addClass, hasClass, removeClass } from '@/utils/domUtils' 2 | 3 | export type CustomColorType = { 4 | name: string 5 | light: string 6 | dark: string 7 | } 8 | 9 | export async function updateDarkTheme(mode: string | null = 'light') { 10 | const htmlRoot = document.getElementById('htmlRoot') 11 | if (!htmlRoot) { 12 | return 13 | } 14 | const hasDarkClass = hasClass(htmlRoot, 'dark') 15 | if (mode === 'dark') { 16 | htmlRoot.setAttribute('data-theme', 'dark') 17 | if (!hasDarkClass) { 18 | addClass(htmlRoot, 'dark') 19 | } 20 | } else { 21 | htmlRoot.setAttribute('data-theme', 'light') 22 | if (hasDarkClass) { 23 | removeClass(htmlRoot, 'dark') 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/redirect.vue: -------------------------------------------------------------------------------- 1 | 4 | 31 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/personal/personal.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 26 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/header/components/FullScreen.vue: -------------------------------------------------------------------------------- 1 | 9 | 23 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/components/SiteAnalysis.vue: -------------------------------------------------------------------------------- 1 | 11 | 32 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/dateUtil.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Independent time operation tool to facilitate subsequent switch to dayjs 3 | */ 4 | import dayjs from 'dayjs' 5 | 6 | const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' 7 | const DATE_FORMAT = 'YYYY-MM-DD' 8 | const MONTH_FORMAT = 'YYYY-MM' 9 | 10 | export function formatDateTime(date: dayjs.ConfigType | undefined = undefined, format = DATE_TIME_FORMAT): string { 11 | return dayjs(date).format(format) 12 | } 13 | 14 | export function formatDate(date: dayjs.ConfigType | undefined = undefined, format = DATE_FORMAT): string { 15 | return dayjs(date).format(format) 16 | } 17 | 18 | export function formatMonth(date: dayjs.ConfigType | undefined = undefined, format = MONTH_FORMAT): string { 19 | return dayjs(date).format(format) 20 | } 21 | 22 | export const dateUtil = dayjs 23 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Modal/src/components/ModalFooter.vue: -------------------------------------------------------------------------------- 1 | 14 | 27 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/uuid.ts: -------------------------------------------------------------------------------- 1 | const hexList: string[] = [] 2 | for (let i = 0; i <= 15; i++) { 3 | hexList[i] = i.toString(16) 4 | } 5 | 6 | export function buildUUID(): string { 7 | let uuid = '' 8 | for (let i = 1; i <= 36; i++) { 9 | if (i === 9 || i === 14 || i === 19 || i === 24) { 10 | uuid += '-' 11 | } else if (i === 15) { 12 | uuid += 4 13 | } else if (i === 20) { 14 | uuid += hexList[(Math.random() * 4) | 8] 15 | } else { 16 | uuid += hexList[(Math.random() * 16) | 0] 17 | } 18 | } 19 | return uuid.replace(/-/g, '') 20 | } 21 | 22 | let unique = 0 23 | export function buildShortUUID(prefix = ''): string { 24 | const time = Date.now() 25 | const random = Math.floor(Math.random() * 1000000000) 26 | unique++ 27 | return prefix + '_' + random + unique + String(time) 28 | } 29 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/exception/ApiException.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.exception; 2 | 3 | 4 | import com.yxboot.common.api.ResultCode; 5 | 6 | /** 7 | * 自定义API异常 8 | */ 9 | public class ApiException extends RuntimeException { 10 | private ResultCode resultCode; 11 | 12 | public ApiException(ResultCode resultCode) { 13 | super(resultCode.getMsg()); 14 | this.resultCode = resultCode; 15 | } 16 | 17 | public ApiException(String message) { 18 | super(message); 19 | } 20 | 21 | public ApiException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public ApiException(String message, Throwable cause) { 26 | super(message, cause); 27 | } 28 | 29 | public ResultCode getResultCode() { 30 | return resultCode; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysFileService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysFileTableDef.SYS_FILE; 4 | import org.springframework.stereotype.Service; 5 | import com.mybatisflex.core.query.QueryWrapper; 6 | import com.mybatisflex.spring.service.impl.ServiceImpl; 7 | import com.yxboot.modules.sys.entity.SysFile; 8 | import com.yxboot.modules.sys.mapper.SysFileMapper; 9 | 10 | 11 | /** 12 | * 附件表业务实现类 13 | * 14 | * @author Boya 15 | */ 16 | @Service 17 | public class SysFileService extends ServiceImpl { 18 | 19 | public SysFile selectByFileName(String fileName) { 20 | QueryWrapper query = QueryWrapper.create(); 21 | query.where(SYS_FILE.FILE_NAME.eq(fileName)); 22 | return getOne(query); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/dictData.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | all = '/sys/dict/data/all', 6 | list = '/sys/dict/data/list', 7 | get = '/sys/dict/data/get', 8 | save = '/sys/dict/data/save', 9 | remove = '/sys/dict/data/remove', 10 | } 11 | 12 | export const allDictData = (params: any) => http.get({ url: Api.all, params }) 13 | export const listDictData = (params: any) => http.get({ url: Api.list, params }) 14 | export const getDictData = (params: any) => http.get({ url: Api.get, params }) 15 | export const saveDictData = (data: any) => http.post({ url: Api.save, data }) 16 | export const removeDictData = (params: any) => http.delete({ url: Api.remove, params }) 17 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/hooks/useTableStyle.ts: -------------------------------------------------------------------------------- 1 | import type { ComputedRef } from 'vue' 2 | import { unref } from 'vue' 3 | import { isFunction } from '@/utils/is' 4 | import type { BasicTableProps, TableCustomRecord } from '../types/table' 5 | 6 | export function useTableStyle(propsRef: ComputedRef, prefixCls: string) { 7 | function getRowClassName(record: TableCustomRecord, index: number) { 8 | const { striped, rowClassName } = unref(propsRef) 9 | const classNames: string[] = [] 10 | if (striped) { 11 | classNames.push((index || 0) % 2 === 1 ? `${prefixCls}-row__striped` : '') 12 | } 13 | if (rowClassName && isFunction(rowClassName)) { 14 | classNames.push(rowClassName(record, index)) 15 | } 16 | return classNames.filter((cls) => !!cls).join(' ') 17 | } 18 | 19 | return { getRowClassName } 20 | } 21 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/routes/index.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router' 2 | import { PageEnum } from '@/enums/pageEnum' 3 | import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from './basic' 4 | import { PERSONAL_ROUTE } from './personal' 5 | 6 | // 根路由 7 | export const ROOT_ROUTE: RouteRecordRaw = { 8 | path: '/', 9 | name: 'Root', 10 | redirect: PageEnum.BASE_HOME, 11 | meta: { 12 | title: 'Root', 13 | }, 14 | } 15 | 16 | export const LOGIN_ROUTE: RouteRecordRaw = { 17 | path: '/login', 18 | name: 'Login', 19 | component: () => import('@/views/login.vue'), 20 | meta: { 21 | title: '登录', 22 | keepAlive: true, 23 | requireAuth: false, 24 | }, 25 | } 26 | 27 | // Basic routing without permission 28 | // 未经许可的基本路由 29 | export const basicRoutes = [ROOT_ROUTE, LOGIN_ROUTE, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, PERSONAL_ROUTE] 30 | -------------------------------------------------------------------------------- /yxboot-admin/types/store.d.ts: -------------------------------------------------------------------------------- 1 | import type { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum' 2 | 3 | // Lock screen information 4 | export interface LockInfo { 5 | // Password required 6 | pwd?: string | undefined 7 | // Is it locked? 8 | isLock?: boolean 9 | } 10 | 11 | export interface UserInfo { 12 | userId: number 13 | username: string 14 | phone: string 15 | name: string 16 | avatar: string 17 | email: string 18 | } 19 | 20 | export interface BeforeMiniState { 21 | menuCollapsed?: boolean 22 | menuSplit?: boolean 23 | menuMode?: MenuModeEnum 24 | menuType?: MenuTypeEnum 25 | } 26 | 27 | export interface TableSetting { 28 | size: Recordable> 29 | showIndexColumn: Recordable> 30 | columns: Recordable>> 31 | showRowSelection: Recordable> 32 | } 33 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysRoleMenuService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysRoleMenuTableDef.SYS_ROLE_MENU; 4 | import org.springframework.stereotype.Service; 5 | import com.mybatisflex.core.query.QueryWrapper; 6 | import com.mybatisflex.spring.service.impl.ServiceImpl; 7 | import com.yxboot.modules.sys.entity.SysRoleMenu; 8 | import com.yxboot.modules.sys.mapper.SysRoleMenuMapper; 9 | 10 | 11 | /** 12 | * 角色菜单表业务实现类 13 | * 14 | * @author Boya 15 | */ 16 | @Service 17 | public class SysRoleMenuService extends ServiceImpl { 18 | public boolean removeByRoleId(Long roleId) { 19 | QueryWrapper wrapper = QueryWrapper.create(); 20 | wrapper.where(SYS_ROLE_MENU.ROLE_ID.eq(roleId)); 21 | return remove(wrapper); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/web/useSortable.ts: -------------------------------------------------------------------------------- 1 | import type Sortable from 'sortablejs' 2 | import type { Options } from 'sortablejs' 3 | import type { Ref } from 'vue' 4 | import { nextTick, unref } from 'vue' 5 | 6 | export function useSortable(el: HTMLElement | Ref, options?: Options) { 7 | const sortableRef = ref() 8 | 9 | function initSortable() { 10 | nextTick(async () => { 11 | const element = unref(el) 12 | if (!element) return 13 | const Sortable = (await import('sortablejs')).default 14 | sortableRef.value = Sortable.create(element, { 15 | animation: 100, 16 | delay: 400, 17 | delayOnTouchOnly: true, 18 | ...options, 19 | }) 20 | }) 21 | } 22 | 23 | function getSortable() { 24 | return sortableRef.value 25 | } 26 | 27 | initSortable() 28 | return { getSortable } 29 | } 30 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/event/useWindowSizeFn.ts: -------------------------------------------------------------------------------- 1 | import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core' 2 | 3 | interface WindowSizeOptions { 4 | once?: boolean 5 | immediate?: boolean 6 | listenerOptions?: AddEventListenerOptions | boolean 7 | } 8 | 9 | export function useWindowSizeFn(fn: Fn, wait = 150, options?: WindowSizeOptions) { 10 | let handler = () => { 11 | fn() 12 | } 13 | const handleSize = useDebounceFn(handler, wait) 14 | handler = handleSize 15 | 16 | const start = () => { 17 | if (options?.immediate) { 18 | handler() 19 | } 20 | window.addEventListener('resize', handler) 21 | } 22 | 23 | const stop = () => { 24 | window.removeEventListener('resize', handler) 25 | } 26 | 27 | tryOnMounted(() => { 28 | start() 29 | }) 30 | 31 | tryOnUnmounted(() => { 32 | stop() 33 | }) 34 | return [start, stop] 35 | } 36 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/web/DatetimeHandler.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.web; 2 | 3 | import com.fasterxml.jackson.databind.util.StdDateFormat; 4 | import org.springframework.beans.propertyeditors.CustomDateEditor; 5 | import org.springframework.web.bind.WebDataBinder; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.InitBinder; 8 | 9 | import java.text.DateFormat; 10 | import java.util.Date; 11 | import java.util.TimeZone; 12 | 13 | /** 14 | * @author Boya 15 | */ 16 | @ControllerAdvice 17 | public class DatetimeHandler { 18 | @InitBinder 19 | public void initBinder(WebDataBinder binder) { 20 | DateFormat dateFormat = new StdDateFormat().withTimeZone(TimeZone.getTimeZone("GMT+8")).withLenient(true); 21 | binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/menu.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | list = '/sys/menu/list', 6 | get = '/sys/menu/get', 7 | save = '/sys/menu/save', 8 | remove = '/sys/menu/remove', 9 | all = '/sys/menu/all', 10 | tree = '/sys/menu/tree', 11 | } 12 | 13 | export const listMenu = (params: any) => http.get({ url: Api.list, params }) 14 | export const getMenu = (params: any) => http.get({ url: Api.get, params }) 15 | export const saveMenu = (data: any) => http.post({ url: Api.save, data }) 16 | export const removeMenu = (params: any) => http.delete({ url: Api.remove, params }) 17 | export const allMenu = (params: any) => http.get({ url: Api.all, params }) 18 | export const treeMenu = () => http.get({ url: Api.tree }) 19 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/pagination/PageRequest.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.pagination; 2 | 3 | import com.mybatisflex.core.paginate.Page; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | * 封装分页请求参数 9 | * 10 | * @author Boya 11 | */ 12 | @Data 13 | @EqualsAndHashCode(callSuper = false) 14 | public class PageRequest { 15 | private static final String ORDER_ASC = "ascend"; 16 | private static final String ORDER_DESC = "descend"; 17 | 18 | /** 19 | * 当前页面 20 | */ 21 | private Long pageNumber = 1L; 22 | /** 23 | * 每页条数 24 | */ 25 | private Long pageSize = 20L; 26 | /** 27 | * 排序字段 28 | */ 29 | private String field; 30 | /** 31 | * 排序方式 32 | */ 33 | private String order; 34 | 35 | public Page convertToPage() { 36 | return Page.of(pageNumber, pageSize); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/mybatisflex/MyBatisFlexConfig.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.mybatisflex; 2 | 3 | import javax.annotation.PostConstruct; 4 | import org.mybatis.spring.annotation.MapperScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import com.mybatisflex.core.audit.AuditManager; 7 | 8 | /** 9 | * MyBatis-Flex配置类 10 | * 11 | * @author Boya 12 | */ 13 | @Configuration 14 | @MapperScan("com.yxboot.modules.**.mapper") 15 | public class MyBatisFlexConfig { 16 | 17 | @PostConstruct 18 | public void init() { 19 | // 配置审计管理器 20 | AuditManager.setAuditEnable(true); 21 | 22 | // 设置 SQL 审计收集器 23 | AuditManager.setMessageCollector(auditMessage -> { 24 | System.out.println("SQL: " + auditMessage.getFullSql()); 25 | System.out.println("执行时间: " + auditMessage.getElapsedTime() + " ms"); 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /yxboot-admin/src/styles/var/easing.less: -------------------------------------------------------------------------------- 1 | // ================================= 2 | // ==============动画函数-=========== 3 | // ================================= 4 | 5 | @ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); 6 | @ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); 7 | @ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); 8 | @ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); 9 | @ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); 10 | @ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); 11 | @ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); 12 | @ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); 13 | @ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); 14 | @ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); 15 | @ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); 16 | @ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); 17 | @ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); 18 | @ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/data.ts: -------------------------------------------------------------------------------- 1 | export interface GrowCardItem { 2 | icon: string 3 | title: string 4 | value: number 5 | total: number 6 | color: string 7 | action: string 8 | } 9 | 10 | export const growCardList: GrowCardItem[] = [ 11 | { 12 | title: '访问数', 13 | icon: 'visit-count|svg', 14 | value: 2000, 15 | total: 120000, 16 | color: 'green', 17 | action: '月', 18 | }, 19 | { 20 | title: '成交额', 21 | icon: 'total-sales|svg', 22 | value: 20000, 23 | total: 500000, 24 | color: 'blue', 25 | action: '月', 26 | }, 27 | { 28 | title: '下载数', 29 | icon: 'download-count|svg', 30 | value: 8000, 31 | total: 120000, 32 | color: 'orange', 33 | action: '周', 34 | }, 35 | { 36 | title: '成交数', 37 | icon: 'transaction|svg', 38 | value: 5000, 39 | total: 50000, 40 | color: 'purple', 41 | action: '年', 42 | }, 43 | ] 44 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/web/GlobalException.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.web; 2 | 3 | import com.yxboot.common.api.Result; 4 | import com.yxboot.common.api.ResultCode; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | import org.springframework.web.bind.annotation.ResponseStatus; 10 | 11 | /** 12 | * 全局异常捕获处理 13 | * 14 | * @author Boya 15 | */ 16 | @Slf4j 17 | @ControllerAdvice 18 | public class GlobalException { 19 | @ResponseBody 20 | @ResponseStatus 21 | @ExceptionHandler(value = Exception.class) 22 | public Result exceptionHandler(Exception e) { 23 | log.error("全局异常捕获:" + e.getMessage(), e); 24 | return Result.error(ResultCode.INTERNAL_SERVER_ERROR, "服务内部错误,请联系管理员!"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/dept.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | all = '/sys/dept/all', 6 | list = '/sys/dept/list', 7 | get = '/sys/dept/get', 8 | save = '/sys/dept/save', 9 | remove = '/sys/dept/remove', 10 | tree = '/sys/dept/tree', 11 | } 12 | 13 | export const allDept = (params: any) => http.get({ url: Api.all, params }) 14 | export const listDept = (params: any) => http.get({ url: Api.list, params }) 15 | export const getDept = (params: any) => http.get({ url: Api.get, params }) 16 | export const saveDept = (data: any) => http.post({ url: Api.save, data }) 17 | export const removeDept = (params: any) => http.delete({ url: Api.remove, params }) 18 | export const treeDept = (params: any) => http.get({ url: Api.tree, params }) 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/role.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | all = '/sys/role/all', 6 | list = '/sys/role/list', 7 | get = '/sys/role/get', 8 | save = '/sys/role/save', 9 | remove = '/sys/role/remove', 10 | saveMenus = '/sys/role/saveMenus', 11 | } 12 | 13 | export const allRole = () => http.get({ url: Api.all }) 14 | export const listRole = (params: any) => http.get({ url: Api.list, params }) 15 | export const getRole = (params: any) => http.get({ url: Api.get, params }) 16 | export const saveRole = (data: any) => http.post({ url: Api.save, data }) 17 | export const removeRole = (params: any) => http.delete({ url: Api.remove, params }) 18 | export const saveMenusRole = (data: any) => http.post({ url: Api.saveMenus, data }) 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/cacheEnum.ts: -------------------------------------------------------------------------------- 1 | export const ACCESS_TOKEN = 'ACCESS_TOKEN' 2 | export const CURRENT_USER = 'CURRENT_USER' 3 | // token key 4 | export const TOKEN_KEY = 'TOKEN__' 5 | 6 | export const LOCALE_KEY = 'LOCALE__' 7 | 8 | // user info key 9 | export const USER_INFO_KEY = 'USER__INFO__' 10 | 11 | // role info key 12 | export const ROLES_KEY = 'ROLES__KEY__' 13 | 14 | // project config key 15 | export const APP_CFG_KEY = 'APP__CFG__KEY__' 16 | 17 | // lock info 18 | export const LOCK_INFO_KEY = 'LOCK__INFO__KEY__' 19 | 20 | export const MULTIPLE_TABS_KEY = 'MULTIPLE_TABS__KEY__' 21 | 22 | export const APP_DARK_MODE_KEY_ = '__APP__DARK__MODE__' 23 | 24 | // base global local key 25 | export const APP_LOCAL_CACHE_KEY = 'COMMON__LOCAL__KEY__' 26 | 27 | // base global session key 28 | export const APP_SESSION_CACHE_KEY = 'COMMON__SESSION__KEY__' 29 | 30 | // table 列设置 31 | export const TABLE_SETTING_KEY = 'TABLE__SETTING__KEY__' 32 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/content/index.vue: -------------------------------------------------------------------------------- 1 | 9 | 16 | 36 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/http/axios/axiosRetry.ts: -------------------------------------------------------------------------------- 1 | import type { AxiosError, AxiosInstance } from 'axios' 2 | import { RetryConfig } from '@/utils/http/axios/retryConfig' 3 | /** 4 | * 请求重试机制 5 | */ 6 | 7 | export class AxiosRetry { 8 | /** 9 | * 重试 10 | */ 11 | retry(AxiosInstance: AxiosInstance, error: AxiosError) { 12 | const { config } = error.response 13 | const retryConfig = new RetryConfig(config) 14 | const { waitTime, count } = retryConfig?.requestOptions?.retryRequest 15 | retryConfig.__retryCount = retryConfig.__retryCount || 0 16 | if (retryConfig.__retryCount >= count) { 17 | return Promise.reject(error) 18 | } 19 | retryConfig.__retryCount += 1 20 | return this.delay(waitTime).then(() => AxiosInstance(retryConfig)) 21 | } 22 | 23 | /** 24 | * 延迟 25 | */ 26 | private delay(waitTime: number) { 27 | return new Promise((resolve) => setTimeout(resolve, waitTime)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/useGlobSetting.ts: -------------------------------------------------------------------------------- 1 | import type { GlobConfig } from '#/config' 2 | 3 | import { getAppEnvConfig } from '@/utils/env' 4 | import { warn } from '@/utils/log' 5 | 6 | export const useGlobSetting = (): Readonly => { 7 | const { VITE_GLOB_APP_TITLE, VITE_GLOB_API_URL, VITE_GLOB_APP_SHORT_NAME, VITE_GLOB_API_URL_PREFIX, VITE_GLOB_UPLOAD_URL } = getAppEnvConfig() 8 | 9 | if (!/[a-zA-Z_]*/.test(VITE_GLOB_APP_SHORT_NAME)) { 10 | warn(`VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`) 11 | } 12 | 13 | // Take global configuration 14 | const glob: Readonly = { 15 | title: VITE_GLOB_APP_TITLE, 16 | apiUrl: VITE_GLOB_API_URL, 17 | shortName: VITE_GLOB_APP_SHORT_NAME, 18 | urlPrefix: VITE_GLOB_API_URL_PREFIX, 19 | uploadUrl: VITE_GLOB_UPLOAD_URL, 20 | } 21 | return glob as Readonly 22 | } 23 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/proxy.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to parse the .env.development proxy configuration 3 | */ 4 | import type { ProxyOptions } from 'vite' 5 | 6 | type ProxyItem = [string, string] 7 | 8 | type ProxyList = ProxyItem[] 9 | 10 | type ProxyTargetList = Record 11 | 12 | const httpsRE = /^https:\/\// 13 | 14 | /** 15 | * Generate proxy 16 | * @param list 17 | */ 18 | export function createProxy(list: ProxyList = []) { 19 | const ret: ProxyTargetList = {} 20 | for (const [prefix, target] of list) { 21 | const isHttps = httpsRE.test(target) 22 | 23 | // https://github.com/http-party/node-http-proxy#options 24 | ret[prefix] = { 25 | target: target, 26 | changeOrigin: true, 27 | ws: true, 28 | rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''), 29 | // https is require secure=false 30 | ...(isHttps ? { secure: false } : {}) 31 | } 32 | } 33 | return ret 34 | } 35 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/file.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | list = '/sys/file/list', 6 | get = '/sys/file/get', 7 | save = '/sys/file/save', 8 | remove = '/sys/file/remove', 9 | getByPath = '/sys/file/getByPath', 10 | upload = '/sys/file/upload', 11 | } 12 | 13 | export const listFile = (params: any) => http.get({ url: Api.list, params }) 14 | export const getFile = (params: any) => http.get({ url: Api.get, params }) 15 | export const saveFile = (data: any) => http.post({ url: Api.save, data }) 16 | export const removeFile = (params: any) => http.delete({ url: Api.remove, params }) 17 | export const getByPathFile = (params: any) => http.get({ url: Api.getByPath, params }) 18 | export const uploadFile = (params: any) => http.uploadFile({ url: Api.upload }, params) 19 | -------------------------------------------------------------------------------- /yxboot-admin/.env.production: -------------------------------------------------------------------------------- 1 | # Whether to open mock 2 | VITE_USE_MOCK = true 3 | 4 | # public path 5 | VITE_PUBLIC_PATH = / 6 | 7 | # Delete console 8 | VITE_DROP_CONSOLE = true 9 | 10 | # Whether to enable gzip or brotli compression 11 | # Optional: gzip | brotli | none 12 | # If you need multiple forms, you can use `,` to separate 13 | VITE_BUILD_COMPRESS = 'none' 14 | 15 | # Whether to delete origin files when using compress, default false 16 | VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false 17 | 18 | # Basic interface address SPA 19 | VITE_GLOB_API_URL=/api 20 | 21 | # File upload address, optional 22 | # It can be forwarded by nginx or write the actual address directly 23 | VITE_GLOB_UPLOAD_URL=/upload 24 | 25 | # Interface prefix 26 | VITE_GLOB_API_URL_PREFIX= 27 | 28 | # Whether to enable image compression 29 | VITE_USE_IMAGEMIN= true 30 | 31 | # use pwa 32 | VITE_USE_PWA = false 33 | 34 | # Is it compatible with older browsers 35 | VITE_LEGACY = false 36 | -------------------------------------------------------------------------------- /yxboot-admin/src/styles/var/breakpoint.less: -------------------------------------------------------------------------------- 1 | // ================================= 2 | // ==============屏幕断点============ 3 | // ================================= 4 | 5 | // Extra small screen / phone 6 | @screen-xs: 480px; 7 | @screen-xs-min: @screen-xs; 8 | 9 | // Small screen / tablet 10 | @screen-sm: 576px; 11 | @screen-sm-min: @screen-sm; 12 | 13 | // Medium screen / desktop 14 | @screen-md: 768px; 15 | @screen-md-min: @screen-md; 16 | 17 | // Large screen / wide desktop 18 | @screen-lg: 992px; 19 | @screen-lg-min: @screen-lg; 20 | 21 | // Extra large screen / full hd 22 | @screen-xl: 1200px; 23 | @screen-xl-min: @screen-xl; 24 | 25 | // Extra extra large screen / large desktop 26 | @screen-2xl: 1600px; 27 | @screen-2xl-min: @screen-2xl; 28 | 29 | @screen-xs-max: (@screen-sm-min - 1px); 30 | @screen-sm-max: (@screen-md-min - 1px); 31 | @screen-md-max: (@screen-lg-min - 1px); 32 | @screen-lg-max: (@screen-xl-min - 1px); 33 | @screen-xl-max: (@screen-2xl-min - 1px); 34 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/helper/tsxHelper.tsx: -------------------------------------------------------------------------------- 1 | import type { Slots } from 'vue' 2 | import { isFunction } from '@/utils/is' 3 | 4 | /** 5 | * @description: Get slot to prevent empty error 6 | */ 7 | export function getSlot(slots: Slots, slot = 'default', data?: any) { 8 | if (!slots || !Reflect.has(slots, slot)) { 9 | return null 10 | } 11 | if (!isFunction(slots[slot])) { 12 | console.error(`${slot} is not a function!`) 13 | return null 14 | } 15 | const slotFn = slots[slot] 16 | if (!slotFn) return null 17 | return slotFn(data) 18 | } 19 | 20 | /** 21 | * extends slots 22 | * @param slots 23 | * @param excludeKeys 24 | */ 25 | export function extendSlots(slots: Slots, excludeKeys: string[] = []) { 26 | const slotKeys = Object.keys(slots) 27 | const ret: any = {} 28 | slotKeys.forEach((key) => { 29 | if (!excludeKeys.includes(key)) { 30 | ret[key] = (data?: any) => getSlot(slots, key, data) 31 | } 32 | }) 33 | return ret 34 | } 35 | -------------------------------------------------------------------------------- /yxboot-admin/src/api/sys/user.ts: -------------------------------------------------------------------------------- 1 | import { http } from '@/utils/http/axios' 2 | import type { BasicResultModel } from '../model/basicModel' 3 | 4 | enum Api { 5 | list = '/sys/user/list', 6 | get = '/sys/user/get', 7 | save = '/sys/user/save', 8 | remove = '/sys/user/remove', 9 | reset = '/sys/user/resetPassword', 10 | change = '/sys/user/changePassword', 11 | } 12 | 13 | export const listUser = (params: any) => http.get({ url: Api.list, params }) 14 | export const getUser = (params: any) => http.get({ url: Api.get, params }) 15 | export const saveUser = (data: any) => http.post({ url: Api.save, data }) 16 | export const removeUser = (params: any) => http.delete({ url: Api.remove, params }) 17 | export const resetPassword = (params: any) => http.post({ url: Api.reset, params }) 18 | export const changePassword = (params: any) => http.post({ url: Api.change, params }) 19 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/sider/AppLogo.vue: -------------------------------------------------------------------------------- 1 | 7 | 14 | 39 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/menuEnum.ts: -------------------------------------------------------------------------------- 1 | // 折叠触发器位置 2 | export enum TriggerEnum { 3 | // 不显示 4 | NONE = 'NONE', 5 | // 菜单底部 6 | FOOTER = 'FOOTER', 7 | // 菜单中间 8 | CENTER = 'CENTER', 9 | // 头部 10 | HEADER = 'HEADER', 11 | } 12 | 13 | /** 14 | * @description: menu type 15 | */ 16 | export enum MenuTypeEnum { 17 | // left menu 18 | SIDER = 'sider', 19 | // top menu 20 | TOP_MENU = 'top-menu', 21 | // mixin menu 22 | MIX_TOP = 'mix-top', 23 | // mix-sidebar 24 | MIX_SIDER = 'mix-sider', 25 | } 26 | 27 | export type Mode = 'vertical' | 'vertical-right' | 'horizontal' | 'inline' 28 | 29 | // menu mode 30 | export enum MenuModeEnum { 31 | VERTICAL = 'vertical', 32 | HORIZONTAL = 'horizontal', 33 | VERTICAL_RIGHT = 'vertical-right', 34 | INLINE = 'inline', 35 | MIX = 'mix', 36 | } 37 | 38 | export enum MenuSplitTyeEnum { 39 | NONE, 40 | TOP, 41 | LEFT, 42 | } 43 | 44 | export enum MixSidebarTriggerEnum { 45 | HOVER = 'hover', 46 | CLICK = 'click', 47 | } 48 | -------------------------------------------------------------------------------- /yxboot-api/src/main/resources/application-dev.template.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | # 数据源 3 | datasource: 4 | url: jdbc:mysql://localhost:3306/yxboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 5 | username: root 6 | # Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果) 以下解密结果为123456 7 | password: 123456 8 | type: com.alibaba.druid.pool.DruidDataSource 9 | driver-class-name: com.mysql.jdbc.Driver 10 | 11 | # Redis 若设有密码自行添加配置password 12 | data: 13 | redis: 14 | host: localhost 15 | port: 6379 16 | password: 123456 17 | 18 | yxboot: 19 | upload: 20 | model: local 21 | local: 22 | enable: true 23 | path-prefix: /srv/yxboot/images/ 24 | url-prefix: http://admin.yxboot.com/images/ 25 | rewrite-file-name: false 26 | oss: 27 | enable: true 28 | endpoint: xxx 29 | accessKey: xxx 30 | secretKey: xxx 31 | bucketName: xxx 32 | rewrite-file-name: true 33 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/const.ts: -------------------------------------------------------------------------------- 1 | import componentSetting from '@/settings/componentSetting' 2 | 3 | const { table } = componentSetting 4 | 5 | const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSize, defaultSortFn, defaultFilterFn } = table 6 | 7 | export const ROW_KEY = 'key' 8 | 9 | // Optional display number per page; 10 | export const PAGE_SIZE_OPTIONS = pageSizeOptions 11 | 12 | // Number of items displayed per page 13 | export const PAGE_SIZE = defaultPageSize 14 | 15 | // Common interface field settings 16 | export const FETCH_SETTING = fetchSetting 17 | 18 | // Default Size 19 | export const DEFAULT_SIZE = defaultSize 20 | 21 | // Configure general sort function 22 | export const DEFAULT_SORT_FN = defaultSortFn 23 | 24 | export const DEFAULT_FILTER_FN = defaultFilterFn 25 | 26 | // Default layout of table cells 27 | export const DEFAULT_ALIGN = 'center' 28 | 29 | export const INDEX_COLUMN_FLAG = 'INDEX' 30 | 31 | export const ACTION_COLUMN_FLAG = 'ACTION' 32 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/tabs/components/FoldButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 28 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/analysis.vue: -------------------------------------------------------------------------------- 1 | 12 | 26 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/mitt/routeChange.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to monitor routing changes to change the status of menus and tabs. There is no need to monitor the route, because the route status change is affected by the page rendering time, which will be slow 3 | */ 4 | 5 | import type { RouteLocationNormalized } from 'vue-router' 6 | import { getRawRoute } from '@/utils' 7 | import mitt from '@/utils/mitt' 8 | 9 | const emitter = mitt() 10 | 11 | const key = Symbol() 12 | 13 | let lastChangeTab: RouteLocationNormalized 14 | 15 | export function setRouteChange(lastChangeRoute: RouteLocationNormalized) { 16 | const r = getRawRoute(lastChangeRoute) 17 | emitter.emit(key, r) 18 | lastChangeTab = r 19 | } 20 | 21 | export function listenerRouteChange(callback: (route: RouteLocationNormalized) => void, immediate = true) { 22 | emitter.on(key, callback) 23 | immediate && lastChangeTab && callback(lastChangeTab) 24 | } 25 | 26 | export function removeTabChangeListener() { 27 | emitter.clear() 28 | } 29 | -------------------------------------------------------------------------------- /yxboot-admin/src/main.ts: -------------------------------------------------------------------------------- 1 | import 'iconify-icon' 2 | import '@/styles/index.less' 3 | import 'ant-design-vue/dist/reset.css' 4 | import 'virtual:uno.css' 5 | // Register icon sprite 6 | import 'virtual:svg-icons-register' 7 | 8 | import { createApp } from 'vue' 9 | import { registerGlobComp } from '@/components/registerGlobComp' 10 | import { setupGlobDirectives } from '@/directives' 11 | import { initAppConfig } from '@/hooks/config' 12 | import { setupRouter } from '@/router' 13 | import { setupStore } from '@/store' 14 | import App from './App.vue' 15 | 16 | async function bootstrap() { 17 | const app = createApp(App) 18 | 19 | // 注册全局 Antd UI组件 20 | registerGlobComp(app) 21 | 22 | // 挂载状态管理 23 | setupStore(app) 24 | 25 | // Initialize internal system configuration 26 | // 初始化内部系统配置 27 | initAppConfig() 28 | 29 | // 挂载路由 30 | setupRouter(app) 31 | 32 | // Register global directive 33 | // 注册全局指令 34 | setupGlobDirectives(app) 35 | 36 | app.mount('#app') 37 | } 38 | 39 | bootstrap() 40 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/routes/basic.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from 'vue-router' 2 | import { EXCEPTION_COMPONENT, LAYOUT, PAGE_NOT_FOUND_NAME, REDIRECT_NAME } from '@/router/constant' 3 | 4 | // 404 on a page 5 | export const PAGE_NOT_FOUND_ROUTE: RouteRecordRaw = { 6 | path: '/:path(.*)*', 7 | name: PAGE_NOT_FOUND_NAME, 8 | component: EXCEPTION_COMPONENT, 9 | meta: { 10 | title: 'ErrorPage', 11 | hideBreadcrumb: true, 12 | hideMenu: true, 13 | }, 14 | } 15 | 16 | export const REDIRECT_ROUTE: RouteRecordRaw = { 17 | path: '/redirect', 18 | component: LAYOUT, 19 | name: 'RedirectTo', 20 | meta: { 21 | title: REDIRECT_NAME, 22 | hideBreadcrumb: true, 23 | hideMenu: true, 24 | }, 25 | children: [ 26 | { 27 | path: '/redirect/:path(.*)', 28 | name: REDIRECT_NAME, 29 | component: () => import('@/views/redirect.vue'), 30 | meta: { 31 | title: REDIRECT_NAME, 32 | hideBreadcrumb: true, 33 | }, 34 | }, 35 | ], 36 | } 37 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/utils/UserUtil.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.utils; 2 | 3 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.stereotype.Component; 7 | import com.yxboot.config.security.SecurityUser; 8 | import lombok.RequiredArgsConstructor; 9 | 10 | @Component 11 | @RequiredArgsConstructor 12 | public class UserUtil { 13 | 14 | public static Long getCurrentUserId() { 15 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 16 | if (authentication != null && authentication.isAuthenticated() && authentication.getName() != null 17 | && !(authentication instanceof AnonymousAuthenticationToken)) { 18 | return ((SecurityUser) authentication.getPrincipal()).getUserId(); 19 | } 20 | return null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/workplace/components/DynamicInfo.vue: -------------------------------------------------------------------------------- 1 | 24 | 27 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/plugin/compress.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Used to package and output gzip. Note that this does not work properly in Vite, the specific reason is still being investigated 3 | * https://github.com/anncwb/vite-plugin-compression 4 | */ 5 | import type { PluginOption } from 'vite' 6 | import compressPlugin from 'vite-plugin-compression' 7 | 8 | export function configCompressPlugin({ compress, deleteOriginFile = false }: { compress: string; deleteOriginFile?: boolean }): PluginOption[] { 9 | const compressList = compress.split(',') 10 | 11 | const plugins: PluginOption[] = [] 12 | 13 | if (compressList.includes('gzip')) { 14 | plugins.push( 15 | compressPlugin({ 16 | ext: '.gz', 17 | deleteOriginFile, 18 | }), 19 | ) 20 | } 21 | 22 | if (compressList.includes('brotli')) { 23 | plugins.push( 24 | compressPlugin({ 25 | ext: '.br', 26 | algorithm: 'brotliCompress', 27 | deleteOriginFile, 28 | }), 29 | ) 30 | } 31 | return plugins 32 | } 33 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/useMultipleTabSetting.ts: -------------------------------------------------------------------------------- 1 | import { storeToRefs } from 'pinia' 2 | import { useAppConfigStore } from '@/store/modules/appConfig' 3 | 4 | export function useMultipleTabSetting() { 5 | const appConfigStore = useAppConfigStore() 6 | const { setMultiTabsSetting } = appConfigStore 7 | const { getMultiTabsSetting } = storeToRefs(appConfigStore) 8 | 9 | const getCache = computed(() => unref(getMultiTabsSetting).cache) 10 | const getCanDrag = computed(() => unref(getMultiTabsSetting).canDrag) 11 | const getShowMultipleTab = computed(() => unref(getMultiTabsSetting).show) 12 | const getShowQuick = computed(() => unref(getMultiTabsSetting).showQuick) 13 | const getShowRedo = computed(() => unref(getMultiTabsSetting).showRedo) 14 | const getShowFold = computed(() => unref(getMultiTabsSetting).showFold) 15 | 16 | return { 17 | setMultiTabsSetting, 18 | 19 | getCache, 20 | getCanDrag, 21 | getShowMultipleTab, 22 | getShowQuick, 23 | getShowRedo, 24 | getShowFold, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/workplace/components/ProjectCard.vue: -------------------------------------------------------------------------------- 1 | 19 | 23 | 28 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/types/tableAction.ts: -------------------------------------------------------------------------------- 1 | import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes' 2 | import type { TooltipProps } from 'ant-design-vue/es/tooltip/Tooltip' 3 | 4 | export interface ActionItem extends ButtonProps { 5 | onClick?: Fn 6 | label?: string 7 | color?: 'success' | 'error' | 'warning' 8 | icon?: string 9 | popConfirm?: PopConfirm 10 | disabled?: boolean 11 | divider?: boolean 12 | // 权限编码控制是否显示 13 | auth?: string | string[] 14 | // 业务控制是否显示 15 | ifShow?: boolean | ((action: ActionItem) => boolean) 16 | tooltip?: string | TooltipProps 17 | } 18 | 19 | export interface PopConfirm { 20 | title: string 21 | okText?: string 22 | cancelText?: string 23 | confirm: Fn 24 | cancel?: Fn 25 | icon?: string 26 | placement?: 27 | | 'top' 28 | | 'left' 29 | | 'right' 30 | | 'bottom' 31 | | 'topLeft' 32 | | 'topRight' 33 | | 'leftTop' 34 | | 'leftBottom' 35 | | 'rightTop' 36 | | 'rightBottom' 37 | | 'bottomLeft' 38 | | 'bottomRight' 39 | } 40 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/guard/stateGuard.ts: -------------------------------------------------------------------------------- 1 | import type { Router } from 'vue-router' 2 | import { PageEnum } from '@/enums/pageEnum' 3 | import { removeTabChangeListener } from '@/router/mitt/routeChange' 4 | import { useAppConfigStore } from '@/store/modules/appConfig' 5 | import { useMultipleTabStore } from '@/store/modules/multipleTab' 6 | import { usePermissionStore } from '@/store/modules/permission' 7 | import { useUserStore } from '@/store/modules/user' 8 | 9 | export function createStateGuard(router: Router) { 10 | router.afterEach((to) => { 11 | // Just enter the login page and clear the authentication information 12 | if (to.path === PageEnum.BASE_LOGIN) { 13 | const tabStore = useMultipleTabStore() 14 | const userStore = useUserStore() 15 | const appConfigStore = useAppConfigStore() 16 | const permissionStore = usePermissionStore() 17 | appConfigStore.resetAllState() 18 | permissionStore.resetState() 19 | tabStore.resetState() 20 | userStore.resetState() 21 | removeTabChangeListener() 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/dept/dept.data.ts: -------------------------------------------------------------------------------- 1 | import { FormSchema } from '@/components/Form' 2 | import { BasicColumn } from '@/components/Table' 3 | import { statusOptions } from '@/enums' 4 | 5 | export const tableColumns: BasicColumn[] = [ 6 | { title: '部门名称', dataIndex: 'name', align: 'left' }, 7 | { title: '部门说明', dataIndex: 'remark' }, 8 | { title: '状态', dataIndex: 'statusDesc' }, 9 | ] 10 | 11 | export const editFormSchema: FormSchema[] = [ 12 | { field: 'deptId', label: '编号', component: 'InputNumber', show: false }, 13 | { 14 | field: 'parentId', 15 | label: '上级部门', 16 | component: 'TreeSelect', 17 | slot: 'parentId', 18 | }, 19 | { 20 | field: 'name', 21 | label: '部门名称', 22 | component: 'Input', 23 | required: true, 24 | }, 25 | { field: 'remark', label: '部门说明', component: 'InputTextArea' }, 26 | { 27 | field: 'status', 28 | label: '状态', 29 | component: 'Select', 30 | rules: [{ required: true, message: '请选择状态' }], 31 | defaultValue: 1, 32 | componentProps: { options: statusOptions }, 33 | }, 34 | ] 35 | -------------------------------------------------------------------------------- /yxboot-admin/src/directives/permission.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Global authority directive 3 | * Used for fine-grained control of component permissions 4 | * @Example v-auth="RoleEnum.TEST" 5 | */ 6 | 7 | import type { App, Directive, DirectiveBinding } from 'vue' 8 | import { usePermission } from '@/hooks/web/usePermission' 9 | 10 | function isAuth(el: Element, binding: any) { 11 | const { hasPermission } = usePermission() 12 | // console.log('value123====》', binding.value) 13 | // console.log('!menuss(value)====》', menuCode.code) 14 | // console.log('判断==>', menuCode.code.indexOf(binding.value[0]) !== -1) 15 | const value: null = binding.value 16 | if (!value) return 17 | if (!hasPermission(value)) { 18 | el.parentNode?.removeChild(el) 19 | } 20 | } 21 | 22 | const mounted = (el: Element, binding: DirectiveBinding) => { 23 | isAuth(el, binding) 24 | } 25 | 26 | const authDirective: Directive = { 27 | mounted, 28 | } 29 | 30 | export function setupPermissionDirective(app: App) { 31 | app.directive('auth', authDirective) 32 | } 33 | 34 | export default authDirective 35 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/entity/SysRoleMenu.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.entity; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | import com.mybatisflex.annotation.Id; 6 | import com.mybatisflex.annotation.KeyType; 7 | import com.mybatisflex.annotation.Table; 8 | import io.swagger.v3.oas.annotations.media.Schema; 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | 12 | /** 13 | * 系统角色菜单表 14 | * 15 | * @author Boya 16 | */ 17 | @Data 18 | @EqualsAndHashCode(callSuper = false) 19 | @Table(value = "sys_role_menu") 20 | @Schema(name = "SysRoleMenu", description = "系统角色菜单表") 21 | public class SysRoleMenu implements Serializable { 22 | @Serial 23 | private static final long serialVersionUID = 1L; 24 | 25 | /** 26 | * 编号 27 | */ 28 | @Id(keyType = KeyType.Auto) 29 | @Schema(description = "编号") 30 | private Long id; 31 | 32 | /** 33 | * 角色编号 34 | */ 35 | @Schema(description = "角色编号") 36 | private Long roleId; 37 | 38 | /** 39 | * 菜单编号 40 | */ 41 | @Schema(description = "菜单编号") 42 | private Long menuId; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/entity/SysUserRole.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.entity; 2 | 3 | import java.io.Serial; 4 | import java.io.Serializable; 5 | import com.mybatisflex.annotation.Id; 6 | import com.mybatisflex.annotation.KeyType; 7 | import com.mybatisflex.annotation.Table; 8 | import io.swagger.v3.oas.annotations.media.Schema; 9 | import lombok.Data; 10 | import lombok.EqualsAndHashCode; 11 | 12 | /** 13 | * 系统用户角色表 14 | * 15 | * @author Boya 16 | */ 17 | @Data 18 | @EqualsAndHashCode(callSuper = false) 19 | @Table(value = "sys_user_role") 20 | @Schema(name = "SysUserRole", description = "系统用户角色表") 21 | public class SysUserRole implements Serializable { 22 | @Serial 23 | private static final long serialVersionUID = 1L; 24 | 25 | /** 26 | * 编号 27 | */ 28 | @Id(keyType = KeyType.Auto) 29 | @Schema(description = "编号") 30 | private Long id; 31 | 32 | /** 33 | * 用户编号 34 | */ 35 | @Schema(description = "用户编号") 36 | private Long userId; 37 | 38 | /** 39 | * 角色编号 40 | */ 41 | @Schema(description = "角色编号") 42 | private Long roleId; 43 | 44 | } 45 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/enums/LogTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.enums; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.mybatisflex.annotation.EnumValue; 5 | import com.yxboot.common.base.BaseEnum; 6 | import com.yxboot.common.exception.ApiException; 7 | import cn.hutool.core.util.EnumUtil; 8 | import lombok.Getter; 9 | 10 | @Getter 11 | public enum LogTypeEnum implements BaseEnum { 12 | // 1登录 2操作 13 | LOGIN("login", "登录"), 14 | OPERATE("operate", "操作"); 15 | 16 | @EnumValue 17 | private String value; 18 | private String desc; 19 | 20 | LogTypeEnum(String value, String desc) { 21 | this.value = value; 22 | this.desc = desc; 23 | } 24 | 25 | @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 26 | public static LogTypeEnum create(Object value) { 27 | LogTypeEnum logTypeEnum = EnumUtil.likeValueOf(LogTypeEnum.class, value); 28 | if (logTypeEnum == null) { 29 | throw new ApiException("未找到匹配的枚举值:" + value); 30 | } 31 | return logTypeEnum; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/workplace/workplace.vue: -------------------------------------------------------------------------------- 1 | 18 | 31 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/enums/SexEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.enums; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.mybatisflex.annotation.EnumValue; 5 | import com.yxboot.common.base.BaseEnum; 6 | import com.yxboot.common.exception.ApiException; 7 | import cn.hutool.core.util.EnumUtil; 8 | import lombok.Getter; 9 | 10 | /** 11 | * 性别枚举 12 | * 13 | * @author Boya 14 | */ 15 | @Getter 16 | public enum SexEnum implements BaseEnum { 17 | // 1男 2女 18 | MALE("male", "男"), 19 | FEMALE("female", "女"); 20 | 21 | @EnumValue 22 | private String value; 23 | private String desc; 24 | 25 | SexEnum(String value, String desc) { 26 | this.value = value; 27 | this.desc = desc; 28 | } 29 | 30 | @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 31 | public static SexEnum create(Object value) { 32 | SexEnum sexEnum = EnumUtil.likeValueOf(SexEnum.class, value); 33 | if (sexEnum == null) { 34 | throw new ApiException("未找到匹配的枚举值:" + value); 35 | } 36 | return sexEnum; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/enums/TemplateTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.enums; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.mybatisflex.annotation.EnumValue; 5 | import com.yxboot.common.base.BaseEnum; 6 | import com.yxboot.common.exception.ApiException; 7 | import cn.hutool.core.util.EnumUtil; 8 | import lombok.Getter; 9 | 10 | @Getter 11 | public enum TemplateTypeEnum implements BaseEnum { 12 | // 1前端 2后端 13 | WEB("web", "前端"), 14 | SERVICE("service", "后端"); 15 | 16 | @EnumValue 17 | private String value; 18 | private String desc; 19 | 20 | TemplateTypeEnum(String value, String desc) { 21 | this.value = value; 22 | this.desc = desc; 23 | } 24 | 25 | @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 26 | public static TemplateTypeEnum create(Object value) { 27 | TemplateTypeEnum statusEnum = EnumUtil.likeValueOf(TemplateTypeEnum.class, value); 28 | if (statusEnum == null) { 29 | throw new ApiException("未找到匹配的枚举值:" + value); 30 | } 31 | return statusEnum; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/enums/MenuEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.enums; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.mybatisflex.annotation.EnumValue; 5 | import com.yxboot.common.base.BaseEnum; 6 | import com.yxboot.common.exception.ApiException; 7 | import cn.hutool.core.util.EnumUtil; 8 | import lombok.Getter; 9 | 10 | @Getter 11 | public enum MenuEnum implements BaseEnum { 12 | // module:模块 menu:菜单 button:按钮/链接 13 | MODULE("module", "模块"), 14 | MENU("menu", "菜单"), 15 | BUTTON("button", "按钮"); 16 | 17 | 18 | @EnumValue 19 | private String value; 20 | private String desc; 21 | 22 | MenuEnum(String value, String desc) { 23 | this.value = value; 24 | this.desc = desc; 25 | } 26 | 27 | @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 28 | public static MenuEnum create(Object value) { 29 | MenuEnum menuEnum = EnumUtil.likeValueOf(MenuEnum.class, value); 30 | if (menuEnum == null) { 31 | throw new ApiException("未找到匹配的枚举值:" + value); 32 | } 33 | return menuEnum; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/appEnum.ts: -------------------------------------------------------------------------------- 1 | export const SIDE_BAR_MINI_WIDTH = 48 2 | 3 | export enum ContentLayoutEnum { 4 | // auto width 5 | FULL = 'full', 6 | // fixed width 7 | FIXED = 'fixed', 8 | } 9 | 10 | // menu theme enum 11 | export enum ThemeEnum { 12 | DARK = 'dark', 13 | LIGHT = 'light', 14 | } 15 | 16 | export enum ThemeTypeEnum { 17 | LIGHT = 'light', 18 | DARK = 'dark', 19 | REAL_DARK = 'real-dark', 20 | } 21 | 22 | /** 23 | * @description: Navigation bar mode 24 | */ 25 | export enum NavBarModeEnum { 26 | // left menu 27 | SIDEBAR = 'sidebar', 28 | // mix-sidebar 29 | MIX_SIDEBAR = 'mix-sidebar', 30 | // mixin menu 31 | MIX = 'mix', 32 | // top menu 33 | TOP_MENU = 'top-menu', 34 | } 35 | 36 | export enum SettingButtonPositionEnum { 37 | AUTO = 'auto', 38 | HEADER = 'header', 39 | FIXED = 'fixed', 40 | } 41 | 42 | // Route switching animation 43 | // 路由切换动画 44 | export enum RouterTransitionEnum { 45 | ZOOM_FADE = 'zoom-fade', 46 | ZOOM_OUT = 'zoom-out', 47 | FADE_SIDE = 'fade-slide', 48 | FADE = 'fade', 49 | FADE_BOTTOM = 'fade-bottom', 50 | FADE_SCALE = 'fade-scale', 51 | } 52 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysLogService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysLogTableDef.SYS_LOG; 4 | import org.springframework.stereotype.Service; 5 | import com.mybatisflex.core.paginate.Page; 6 | import com.mybatisflex.core.query.QueryWrapper; 7 | import com.mybatisflex.spring.service.impl.ServiceImpl; 8 | import com.yxboot.common.pagination.PageRequest; 9 | import com.yxboot.modules.sys.entity.SysLog; 10 | import com.yxboot.modules.sys.mapper.SysLogMapper; 11 | 12 | /** 13 | * 日志表 业务实现类 14 | * 15 | * @author ceshi 16 | * @date 2023-01-13 17 | * @Email 1111@qq.com 18 | */ 19 | @Service 20 | public class SysLogService extends ServiceImpl { 21 | public Page pageQuery(Integer type, PageRequest pageRequest) { 22 | QueryWrapper wrapper = QueryWrapper.create(); 23 | if (type != null) { 24 | wrapper.where(SYS_LOG.TYPE.eq(type)); 25 | } 26 | wrapper.orderBy(SYS_LOG.CREATE_TIME, false); 27 | return page(pageRequest.convertToPage(), wrapper); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysUserRoleService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysUserRoleTableDef.SYS_USER_ROLE; 4 | import java.util.List; 5 | import org.springframework.stereotype.Service; 6 | import com.mybatisflex.core.query.QueryWrapper; 7 | import com.mybatisflex.spring.service.impl.ServiceImpl; 8 | import com.yxboot.modules.sys.entity.SysUserRole; 9 | import com.yxboot.modules.sys.mapper.SysUserRoleMapper; 10 | 11 | 12 | /** 13 | * 用户角色表业务实现类 14 | * 15 | * @author Boya 16 | */ 17 | @Service 18 | public class SysUserRoleService extends ServiceImpl { 19 | public List selectByUserId(Long userId) { 20 | QueryWrapper wrapper = QueryWrapper.create(); 21 | wrapper.where(SYS_USER_ROLE.USER_ID.eq(userId)); 22 | return list(wrapper); 23 | } 24 | 25 | public boolean removeByUserId(Long userId) { 26 | QueryWrapper wrapper = QueryWrapper.create(); 27 | wrapper.where(SYS_USER_ROLE.USER_ID.eq(userId)); 28 | return remove(wrapper); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present, YXBoot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/utils/CusAccessObjectUtil.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.utils; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | 5 | public class CusAccessObjectUtil { 6 | 7 | public static String getIpAddress(HttpServletRequest request) { 8 | String ip = request.getHeader("x-forwarded-for"); 9 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 10 | ip = request.getHeader("Proxy-Client-IP"); 11 | } 12 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 13 | ip = request.getHeader("WL-Proxy-Client-IP"); 14 | } 15 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 16 | ip = request.getHeader("HTTP_CLIENT_IP"); 17 | } 18 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 19 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 20 | } 21 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 22 | ip = request.getRemoteAddr(); 23 | } 24 | return ip; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /yxboot-admin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-present, YXBoot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/componentMap.ts: -------------------------------------------------------------------------------- 1 | import { AutoComplete, Checkbox, DatePicker, Input, InputNumber, Radio, Select, Switch, TimePicker } from 'ant-design-vue' 2 | import type { Component } from 'vue' 3 | import { ApiSelect, ApiTreeSelect } from '@/components/Form' 4 | import type { ComponentType } from './types/componentType' 5 | 6 | const componentMap = new Map() 7 | 8 | componentMap.set('Input', Input) 9 | componentMap.set('InputNumber', InputNumber) 10 | componentMap.set('Select', Select) 11 | componentMap.set('ApiSelect', ApiSelect) 12 | componentMap.set('AutoComplete', AutoComplete) 13 | componentMap.set('ApiTreeSelect', ApiTreeSelect) 14 | componentMap.set('Switch', Switch) 15 | componentMap.set('Checkbox', Checkbox) 16 | componentMap.set('DatePicker', DatePicker) 17 | componentMap.set('TimePicker', TimePicker) 18 | componentMap.set('RadioGroup', Radio.Group) 19 | 20 | export function add(compName: ComponentType, component: Component) { 21 | componentMap.set(compName, component) 22 | } 23 | 24 | export function del(compName: ComponentType) { 25 | componentMap.delete(compName) 26 | } 27 | 28 | export { componentMap } 29 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/enums/StatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.enums; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.mybatisflex.annotation.EnumValue; 5 | import com.yxboot.common.base.BaseEnum; 6 | import com.yxboot.common.exception.ApiException; 7 | import cn.hutool.core.util.EnumUtil; 8 | import lombok.Getter; 9 | 10 | /** 11 | * 通用状态枚举 12 | * 13 | * @author Boya 14 | */ 15 | @Getter 16 | public enum StatusEnum implements BaseEnum { 17 | // normal:正常 invalid:无效 18 | NORMAL("normal", "正常"), 19 | INVALID("invalid", "无效"); 20 | 21 | @EnumValue 22 | private String value; 23 | private String desc; 24 | 25 | StatusEnum(String value, String desc) { 26 | this.value = value; 27 | this.desc = desc; 28 | } 29 | 30 | @JsonCreator(mode = JsonCreator.Mode.DELEGATING) 31 | public static StatusEnum create(Object value) { 32 | StatusEnum statusEnum = EnumUtil.likeValueOf(StatusEnum.class, value); 33 | if (statusEnum == null) { 34 | throw new ApiException("未找到匹配的枚举值:" + value); 35 | } 36 | return statusEnum; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/useMenuSetting.ts: -------------------------------------------------------------------------------- 1 | import { storeToRefs } from 'pinia' 2 | import { MenuTypeEnum } from '@/enums' 3 | import { useAppConfigStore } from '@/store/modules/appConfig' 4 | 5 | export function useMenuSetting() { 6 | const appConfigStore = useAppConfigStore() 7 | const { setMenuSetting } = appConfigStore 8 | const { getMenuSetting } = storeToRefs(appConfigStore) 9 | 10 | const getMenuMode = computed(() => unref(getMenuSetting).mode) 11 | const getMenuType = computed(() => unref(getMenuSetting).type) 12 | const getSplit = computed(() => unref(getMenuSetting).split) 13 | 14 | const isSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDER) 15 | const isTopMenuType = computed(() => unref(getMenuType) === MenuTypeEnum.TOP_MENU) 16 | const isMixTopType = computed(() => unref(getMenuType) === MenuTypeEnum.MIX_TOP) 17 | const isMixSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.MIX_SIDER) 18 | 19 | return { 20 | setMenuSetting, 21 | 22 | getMenuMode, 23 | getMenuType, 24 | getSplit, 25 | isSidebarType, 26 | isTopMenuType, 27 | isMixTopType, 28 | isMixSidebarType, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/lib/echarts.ts: -------------------------------------------------------------------------------- 1 | import { BarChart, LineChart, MapChart, PictorialBarChart, PieChart, RadarChart, ScatterChart } from 'echarts/charts' 2 | import { 3 | AriaComponent, 4 | CalendarComponent, 5 | DataZoomComponent, 6 | GraphicComponent, 7 | GridComponent, 8 | LegendComponent, 9 | ParallelComponent, 10 | PolarComponent, 11 | RadarComponent, 12 | TimelineComponent, 13 | TitleComponent, 14 | ToolboxComponent, 15 | TooltipComponent, 16 | VisualMapComponent, 17 | } from 'echarts/components' 18 | import * as echarts from 'echarts/core' 19 | 20 | import { SVGRenderer } from 'echarts/renderers' 21 | 22 | echarts.use([ 23 | LegendComponent, 24 | TitleComponent, 25 | TooltipComponent, 26 | GridComponent, 27 | PolarComponent, 28 | AriaComponent, 29 | ParallelComponent, 30 | BarChart, 31 | LineChart, 32 | PieChart, 33 | MapChart, 34 | RadarChart, 35 | SVGRenderer, 36 | PictorialBarChart, 37 | RadarComponent, 38 | ToolboxComponent, 39 | DataZoomComponent, 40 | VisualMapComponent, 41 | TimelineComponent, 42 | CalendarComponent, 43 | GraphicComponent, 44 | ScatterChart, 45 | ]) 46 | 47 | export default echarts 48 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Form/src/hooks/useFormItem.ts: -------------------------------------------------------------------------------- 1 | import type { SelectValue } from 'ant-design-vue/es/select' 2 | import { isEqual } from 'lodash-es' 3 | import type { UnwrapRef } from 'vue' 4 | import { computed, getCurrentInstance, reactive, readonly, watchEffect } from 'vue' 5 | 6 | export function useRuleFormItem(props: T, key: keyof T = 'value', changeEvent = 'change') { 7 | const instance = getCurrentInstance() 8 | const emit = instance?.emit 9 | 10 | const innerState = reactive({ 11 | value: props[key], 12 | }) 13 | 14 | const defaultState = readonly(innerState) 15 | 16 | const setState = (val: UnwrapRef): void => { 17 | innerState.value = val as T[keyof T] 18 | } 19 | 20 | watchEffect(() => { 21 | innerState.value = props[key] 22 | }) 23 | 24 | const state: WritableComputedRef = computed({ 25 | get() { 26 | return innerState.value 27 | }, 28 | set(value) { 29 | if (isEqual(value, defaultState.value)) return 30 | innerState.value = value as T[keyof T] 31 | emit?.(changeEvent, value) 32 | }, 33 | }) 34 | 35 | return [state, setState, defaultState] 36 | } 37 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/cache/index.ts: -------------------------------------------------------------------------------- 1 | import { DEFAULT_CACHE_TIME, enableStorageEncryption } from '@/settings/encryptionSetting' 2 | import { getStorageShortName } from '@/utils/env' 3 | import { type CreateStorageParams, createStorage as create } from './storageCache' 4 | 5 | export type Options = Partial 6 | 7 | const createOptions = (storage: Storage, options: Options = {}): Options => { 8 | return { 9 | // No encryption in debug mode 10 | hasEncrypt: enableStorageEncryption, 11 | storage, 12 | prefixKey: getStorageShortName(), 13 | ...options, 14 | } 15 | } 16 | 17 | export const WebStorage = create(createOptions(sessionStorage)) 18 | 19 | export const createStorage = (storage: Storage = sessionStorage, options: Options = {}) => { 20 | return create(createOptions(storage, options)) 21 | } 22 | 23 | export const createSessionStorage = (options: Options = {}) => { 24 | return createStorage(sessionStorage, { ...options, timeout: DEFAULT_CACHE_TIME }) 25 | } 26 | 27 | export const createLocalStorage = (options: Options = {}) => { 28 | return createStorage(localStorage, { ...options, timeout: DEFAULT_CACHE_TIME }) 29 | } 30 | 31 | export default WebStorage 32 | -------------------------------------------------------------------------------- /yxboot-admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "strict": true, 7 | "noLib": false, 8 | "forceConsistentCasingInFileNames": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strictFunctionTypes": false, 11 | "jsx": "preserve", 12 | "baseUrl": ".", 13 | "allowJs": true, 14 | "sourceMap": true, 15 | "esModuleInterop": true, 16 | "resolveJsonModule": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "experimentalDecorators": true, 20 | "lib": ["ESNext", "DOM"], 21 | "noImplicitAny": false, 22 | "skipLibCheck": true, 23 | "types": ["vite/client"], 24 | "removeComments": true, 25 | "paths": { 26 | "@/*": ["src/*"], 27 | "#/*": ["types/*"] 28 | } 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.d.ts", 33 | "src/**/*.tsx", 34 | "src/**/*.vue", 35 | "types/**/*.d.ts", 36 | "types/**/*.ts", 37 | "build/**/*.ts", 38 | "build/**/*.d.ts", 39 | "vite.config.ts" 40 | ], 41 | "exclude": ["node_modules", "tests/server/**/*.ts", "dist", "**/*.js"] 42 | } 43 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/web/jackson/EnumJsonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.web.jackson; 2 | 3 | import java.io.IOException; 4 | import com.fasterxml.jackson.core.JsonGenerator; 5 | import com.fasterxml.jackson.databind.JsonSerializer; 6 | import com.fasterxml.jackson.databind.SerializerProvider; 7 | import com.yxboot.common.base.BaseEnum; 8 | import cn.hutool.core.util.StrUtil; 9 | 10 | public class EnumJsonSerializer extends JsonSerializer { 11 | public final static EnumJsonSerializer instance = new EnumJsonSerializer(); 12 | 13 | @Override 14 | public void serialize(BaseEnum baseEnum, JsonGenerator gen, SerializerProvider serializers) throws IOException { 15 | String name = gen.getOutputContext().getCurrentName(); 16 | gen.writeString(baseEnum.getValue()); 17 | gen.writeStringField(StrUtil.format("{}Desc", name), baseEnum.getDesc()); 18 | gen.writeFieldName(StrUtil.format("{}Enum", name)); 19 | gen.writeStartObject(); 20 | gen.writeStringField("value", baseEnum.getValue()); 21 | gen.writeStringField(StrUtil.format("desc", name), baseEnum.getDesc()); 22 | gen.writeEndObject(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/editable/CellComponent.ts: -------------------------------------------------------------------------------- 1 | import { Popover } from 'ant-design-vue' 2 | import type { defineComponent, FunctionalComponent } from 'vue' 3 | import { h } from 'vue' 4 | import { componentMap } from '@/components/Table/src/componentMap' 5 | import type { ComponentType } from '../../types/componentType' 6 | 7 | export interface ComponentProps { 8 | component: ComponentType 9 | rule: boolean 10 | popoverVisible: boolean 11 | ruleMessage: string 12 | getPopupContainer?: Fn 13 | } 14 | 15 | export const CellComponent: FunctionalComponent = ( 16 | { component = 'Input', rule = true, ruleMessage, popoverVisible, getPopupContainer }: ComponentProps, 17 | { attrs }, 18 | ) => { 19 | const Comp = componentMap.get(component) as typeof defineComponent 20 | 21 | const DefaultComp = h(Comp, attrs) 22 | if (!rule) { 23 | return DefaultComp 24 | } 25 | return h( 26 | Popover, 27 | { 28 | overlayClassName: 'edit-cell-rule-popover', 29 | visible: !!popoverVisible, 30 | ...(getPopupContainer ? { getPopupContainer } : {}), 31 | }, 32 | { 33 | default: () => DefaultComp, 34 | content: () => ruleMessage, 35 | }, 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/footer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 51 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/role/role.data.ts: -------------------------------------------------------------------------------- 1 | import { FormSchema } from '@/components/Form' 2 | import { BasicColumn } from '@/components/Table' 3 | import { statusOptions } from '@/enums' 4 | 5 | export const tableColumns: BasicColumn[] = [ 6 | { title: '角色名称', dataIndex: 'name' }, 7 | { title: '描述', dataIndex: 'descn' }, 8 | { title: '状态', dataIndex: 'statusDesc' }, 9 | ] 10 | 11 | export const searchFormSchema: FormSchema[] = [ 12 | { field: 'name', label: '角色名称', component: 'Input', componentProps: { allowClear: true } }, 13 | { 14 | field: 'status', 15 | label: '状态', 16 | component: 'Select', 17 | componentProps: { allowClear: true, options: statusOptions }, 18 | }, 19 | ] 20 | 21 | export const editFormSchema: FormSchema[] = [ 22 | { field: 'roleId', label: '编号', component: 'InputNumber', show: false }, 23 | { 24 | field: 'name', 25 | label: '角色名称', 26 | component: 'Input', 27 | required: true, 28 | }, 29 | { field: 'descn', label: '描述', component: 'Input' }, 30 | { 31 | field: 'status', 32 | label: '状态', 33 | component: 'Select', 34 | rules: [{ required: true, message: '请选择状态' }], 35 | defaultValue: 1, 36 | componentProps: { options: statusOptions }, 37 | }, 38 | ] 39 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/propTypes.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, VNodeChild } from 'vue' 2 | import { createTypes, toValidableType, type VueTypesInterface, type VueTypeValidableDef } from 'vue-types' 3 | 4 | export type VueNode = VNodeChild | JSX.Element 5 | 6 | type PropTypes = VueTypesInterface & { 7 | readonly style: VueTypeValidableDef 8 | readonly VNodeChild: VueTypeValidableDef 9 | // readonly trueBool: VueTypeValidableDef; 10 | } 11 | const newPropTypes = createTypes({ 12 | func: undefined, 13 | bool: undefined, 14 | string: undefined, 15 | number: undefined, 16 | object: undefined, 17 | integer: undefined, 18 | }) as PropTypes 19 | 20 | // 从 vue-types v5.0 开始,extend()方法已经废弃,当前已改为官方推荐的ES6+方法 https://dwightjack.github.io/vue-types/advanced/extending-vue-types.html#the-extend-method 21 | class propTypes extends newPropTypes { 22 | // a native-like validator that supports the `.validable` method 23 | static override get style() { 24 | return toValidableType('style', { 25 | type: [String, Object], 26 | }) 27 | } 28 | 29 | static override get VNodeChild() { 30 | return toValidableType('VNodeChild', { 31 | type: undefined, 32 | }) 33 | } 34 | } 35 | export { propTypes } 36 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 45 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/security/handler/CustomAccessDeniedHandler.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.security.handler; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.yxboot.common.api.Result; 5 | import com.yxboot.common.api.ResultCode; 6 | import jakarta.servlet.http.HttpServletRequest; 7 | import jakarta.servlet.http.HttpServletResponse; 8 | import org.springframework.security.access.AccessDeniedException; 9 | import org.springframework.security.web.access.AccessDeniedHandler; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * 自定义返回结果:没有权限访问时 15 | * 16 | * @author Boya 17 | */ 18 | public class CustomAccessDeniedHandler implements AccessDeniedHandler { 19 | @Override 20 | public void handle(HttpServletRequest request, 21 | HttpServletResponse response, 22 | AccessDeniedException e) throws IOException { 23 | response.setHeader("Access-Control-Allow-Origin", "*"); 24 | response.setHeader("Cache-Control", "no-cache"); 25 | response.setCharacterEncoding("UTF-8"); 26 | response.setContentType("application/json"); 27 | response.getWriter().println(JSONUtil.parse(Result.error(ResultCode.FORBIDDEN, e.getMessage()))); 28 | response.getWriter().flush(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Button/src/BasicButton.vue: -------------------------------------------------------------------------------- 1 | 10 | 37 | 44 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Icon/src/SvgIcon.vue: -------------------------------------------------------------------------------- 1 | 6 | 40 | 54 | -------------------------------------------------------------------------------- /yxboot-admin/src/router/types.ts: -------------------------------------------------------------------------------- 1 | import type { defineComponent } from 'vue' 2 | import type { RouteMeta, RouteRecordRaw } from 'vue-router' 3 | 4 | export type Component = ReturnType | (() => Promise) | (() => Promise) 5 | 6 | // @ts-expect-error 7 | export interface AppRouteRecordRaw extends Omit { 8 | name: string 9 | meta: RouteMeta 10 | component?: Component | string 11 | components?: Component 12 | children?: AppRouteRecordRaw[] 13 | props?: Recordable 14 | fullPath?: string 15 | } 16 | 17 | export interface MenuTag { 18 | type?: 'primary' | 'error' | 'warn' | 'success' 19 | content?: string 20 | dot?: boolean 21 | } 22 | 23 | export interface Menu { 24 | name: string 25 | 26 | icon?: string 27 | 28 | path: string 29 | 30 | // path contains param, auto assignment. 31 | paramPath?: string 32 | 33 | disabled?: boolean 34 | 35 | children?: Menu[] 36 | 37 | orderNo?: number 38 | 39 | meta?: Partial 40 | 41 | tag?: MenuTag 42 | 43 | hideMenu?: boolean 44 | } 45 | 46 | export interface MenuModule { 47 | orderNo?: number 48 | menu: Menu 49 | } 50 | 51 | // export type AppRouteModule = RouteModule | AppRouteRecordRaw; 52 | export type AppRouteModule = RouteRecordRaw 53 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/components/VisitAnalysisBar.vue: -------------------------------------------------------------------------------- 1 | 4 | 46 | -------------------------------------------------------------------------------- /yxboot-admin/src/store/modules/permission.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import type { SysMenu } from '@/api/model/sysModel' 3 | import { store } from '@/store' 4 | 5 | export interface PermissionState { 6 | origin: Array 7 | menus: Array 8 | menusCode: Array 9 | loaded: boolean 10 | } 11 | export const usePermissionStore = defineStore('permissionStore', { 12 | state: (): PermissionState => ({ 13 | origin: [], 14 | menus: [], 15 | menusCode: [], 16 | loaded: false, 17 | }), 18 | getters: { 19 | getMenus(): Array { 20 | return this.menus 21 | }, 22 | getMenusCode(): Array { 23 | return this.menusCode 24 | }, 25 | isLoaded(): boolean { 26 | return this.loaded 27 | }, 28 | }, 29 | actions: { 30 | setMenus(menus: Array) { 31 | this.menus = menus 32 | }, 33 | setMenusCode(menusCode: Array) { 34 | this.menusCode = menusCode 35 | }, 36 | setLoaded(loaded: boolean) { 37 | this.loaded = loaded 38 | }, 39 | resetState(): void { 40 | this.origin = [] 41 | this.menus = [] 42 | this.loaded = false 43 | }, 44 | }, 45 | }) 46 | 47 | export function usePermissionStoreWithOut() { 48 | return usePermissionStore(store) 49 | } 50 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yxboot 8 | yxboot 9 | pom 10 | 1.0.0 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 3.4.3 16 | 17 | 18 | 19 | 1.0.0 20 | 1.18.36 21 | 5.8.36 22 | 1.10.9 23 | 8.3.0 24 | 1.2.24 25 | 26 | UTF-8 27 | UTF-8 28 | 29 | 30 | 31 | yxboot-api 32 | 33 | 34 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/TableTitle.vue: -------------------------------------------------------------------------------- 1 | 6 | 36 | 48 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/components/GrowCard.vue: -------------------------------------------------------------------------------- 1 | 28 | 40 | -------------------------------------------------------------------------------- /yxboot-admin/src/assets/icons/moon.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 10 | 11 | 13 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/security/handler/CustomAuthenticationEntryPoint.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.security.handler; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.yxboot.common.api.Result; 5 | import com.yxboot.common.api.ResultCode; 6 | import jakarta.servlet.ServletException; 7 | import jakarta.servlet.http.HttpServletRequest; 8 | import jakarta.servlet.http.HttpServletResponse; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.web.AuthenticationEntryPoint; 11 | 12 | import java.io.IOException; 13 | 14 | /** 15 | * 自定义返回结果:未登录或登录过期 16 | * 17 | * @author Boya 18 | */ 19 | public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { 20 | @Override 21 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { 22 | response.setHeader("Access-Control-Allow-Origin", "*"); 23 | response.setHeader("Cache-Control","no-cache"); 24 | response.setCharacterEncoding("UTF-8"); 25 | response.setContentType("application/json"); 26 | response.getWriter().println(JSONUtil.parse(Result.error(ResultCode.UNAUTHORIZED, "未登录或登录过期,请重新登录!"))); 27 | response.getWriter().flush(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Tree/src/BasicTree.vue: -------------------------------------------------------------------------------- 1 | 6 | 42 | ./tree./tree 43 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/header/components/UserDropDown.vue: -------------------------------------------------------------------------------- 1 | 15 | 30 | 40 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Drawer/src/props.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from 'vue' 2 | 3 | export const footerProps = { 4 | confirmLoading: { type: Boolean }, 5 | showCancelBtn: { type: Boolean, default: true }, 6 | cancelButtonProps: Object as PropType, 7 | cancelText: { type: String, default: '取消' }, 8 | showOkBtn: { type: Boolean, default: true }, 9 | okButtonProps: Object as PropType, 10 | okText: { type: String, default: '确认' }, 11 | okType: { type: String, default: 'primary' }, 12 | showFooter: { type: Boolean, default: true }, 13 | footerHeight: { 14 | type: [String, Number] as PropType, 15 | default: 60, 16 | }, 17 | } 18 | 19 | export const basicProps = { 20 | isDetail: { type: Boolean }, 21 | title: { type: String, default: '' }, 22 | loadingText: { type: String }, 23 | showDetailBack: { type: Boolean, default: true }, 24 | visible: { type: Boolean }, 25 | loading: { type: Boolean }, 26 | maskClosable: { type: Boolean, default: true }, 27 | getContainer: { 28 | type: [Object, String] as PropType, 29 | }, 30 | closeFunc: { 31 | type: [Function, Object] as PropType, 32 | default: null, 33 | }, 34 | destroyOnClose: { type: Boolean }, 35 | bodyStyle: { 36 | type: Object, 37 | default: {}, 38 | }, 39 | ...footerProps, 40 | } 41 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/setting/components/SwitchItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 46 | 55 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/http/axios/helper.ts: -------------------------------------------------------------------------------- 1 | import { isObject, isString } from '@/utils/is' 2 | 3 | const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' 4 | 5 | export function joinTimestamp(join: boolean, restful: T): T extends true ? string : object 6 | 7 | export function joinTimestamp(join: boolean, restful = false): string | object { 8 | if (!join) { 9 | return restful ? '' : {} 10 | } 11 | const now = new Date().getTime() 12 | if (restful) { 13 | return `?_t=${now}` 14 | } 15 | return { _t: now } 16 | } 17 | 18 | /** 19 | * @description: Format request parameter time 20 | */ 21 | export function formatRequestDate(params: Recordable) { 22 | if (Object.prototype.toString.call(params) !== '[object Object]') { 23 | return 24 | } 25 | 26 | for (const key in params) { 27 | const format = params[key]?.format ?? null 28 | if (format && typeof format === 'function') { 29 | params[key] = params[key].format(DATE_TIME_FORMAT) 30 | } 31 | if (isString(key)) { 32 | const value = params[key] 33 | if (value) { 34 | try { 35 | params[key] = isString(value) ? value.trim() : value 36 | } catch (error: any) { 37 | throw new Error(error) 38 | } 39 | } 40 | } 41 | if (isObject(params[key])) { 42 | formatRequestDate(params[key]) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /yxboot-admin/build/vite/utils/env.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'node:path' 2 | 3 | import dotenv from 'dotenv' 4 | import { readFile } from 'fs-extra' 5 | 6 | /** 7 | * 获取当前环境下生效的配置文件名 8 | */ 9 | function getConfFiles() { 10 | const script = process.env.npm_lifecycle_script as string 11 | const reg = /--mode ([a-z_\d]+)/ 12 | const result = reg.exec(script) 13 | if (result) { 14 | const mode = result[1] 15 | return ['.env', `.env.${mode}`] 16 | } 17 | return ['.env', '.env.production'] 18 | } 19 | 20 | /** 21 | * Get the environment variables starting with the specified prefix 22 | * @param match prefix 23 | * @param confFiles ext 24 | */ 25 | export async function getEnvConfig( 26 | match = 'VITE_GLOB_', 27 | confFiles = getConfFiles(), 28 | ): Promise<{ 29 | [key: string]: string 30 | }> { 31 | let envConfig = {} 32 | 33 | for (const confFile of confFiles) { 34 | try { 35 | const envPath = await readFile(join(process.cwd(), confFile), { encoding: 'utf8' }) 36 | const env = dotenv.parse(envPath) 37 | envConfig = { ...envConfig, ...env } 38 | } catch (e) { 39 | console.error(`Error in parsing ${confFile}`, e) 40 | } 41 | } 42 | const reg = new RegExp(`^(${match})`) 43 | Object.keys(envConfig).forEach((key) => { 44 | if (!reg.test(key)) { 45 | Reflect.deleteProperty(envConfig, key) 46 | } 47 | }) 48 | return envConfig 49 | } 50 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/event/index.ts: -------------------------------------------------------------------------------- 1 | import ResizeObserver from 'resize-observer-polyfill' 2 | 3 | const isServer = typeof window === 'undefined' 4 | 5 | /* istanbul ignore next */ 6 | function resizeHandler(entries: any[]) { 7 | for (const entry of entries) { 8 | const listeners = entry.target.__resizeListeners__ || [] 9 | if (listeners.length) { 10 | listeners.forEach((fn: () => any) => { 11 | fn() 12 | }) 13 | } 14 | } 15 | } 16 | 17 | /* istanbul ignore next */ 18 | export function addResizeListener(element: any, fn: () => any) { 19 | if (isServer) return 20 | if (!element.__resizeListeners__) { 21 | element.__resizeListeners__ = [] 22 | element.__ro__ = new ResizeObserver(resizeHandler) 23 | element.__ro__.observe(element) 24 | } 25 | element.__resizeListeners__.push(fn) 26 | } 27 | 28 | /* istanbul ignore next */ 29 | export function removeResizeListener(element: any, fn: () => any) { 30 | if (!element || !element.__resizeListeners__) return 31 | element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1) 32 | if (!element.__resizeListeners__.length) { 33 | element.__ro__.disconnect() 34 | } 35 | } 36 | 37 | export function triggerWindowResize() { 38 | const event = document.createEvent('HTMLEvents') 39 | event.initEvent('resize', true, true) 40 | ;(event as any).eventType = 'message' 41 | window.dispatchEvent(event) 42 | } 43 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/user/ResetPasswordModal.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 50 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/components/settings/SizeSetting.vue: -------------------------------------------------------------------------------- 1 | 25 | 43 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/cipher.ts: -------------------------------------------------------------------------------- 1 | import { decrypt, encrypt } from 'crypto-js/aes' 2 | import Base64 from 'crypto-js/enc-base64' 3 | import UTF8, { parse } from 'crypto-js/enc-utf8' 4 | import md5 from 'crypto-js/md5' 5 | import ECB from 'crypto-js/mode-ecb' 6 | import pkcs7 from 'crypto-js/pad-pkcs7' 7 | 8 | export interface EncryptionParams { 9 | key: string 10 | iv: string 11 | } 12 | 13 | export class AesEncryption { 14 | private key 15 | private iv 16 | 17 | constructor(opt: Partial = {}) { 18 | const { key, iv } = opt 19 | if (key) { 20 | this.key = parse(key) 21 | } 22 | if (iv) { 23 | this.iv = parse(iv) 24 | } 25 | } 26 | 27 | get getOptions() { 28 | return { 29 | mode: ECB, 30 | padding: pkcs7, 31 | iv: this.iv, 32 | } 33 | } 34 | 35 | encryptByAES(cipherText: string) { 36 | return encrypt(cipherText, this.key, this.getOptions).toString() 37 | } 38 | 39 | decryptByAES(cipherText: string) { 40 | return decrypt(cipherText, this.key, this.getOptions).toString(UTF8) 41 | } 42 | } 43 | 44 | export function encryptByBase64(cipherText: string) { 45 | return UTF8.parse(cipherText).toString(Base64) 46 | } 47 | 48 | export function decodeByBase64(cipherText: string) { 49 | return Base64.parse(cipherText).toString(UTF8) 50 | } 51 | 52 | export function encryptByMd5(password: string) { 53 | return md5(password).toString() 54 | } 55 | -------------------------------------------------------------------------------- /yxboot-admin/build/generate/generateModifyVars.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'node:path' 2 | import { theme } from 'ant-design-vue/lib' 3 | import convertLegacyToken from 'ant-design-vue/lib/theme/convertLegacyToken' 4 | 5 | const { defaultAlgorithm, defaultSeed } = theme 6 | 7 | /** 8 | * less global variable 9 | */ 10 | export function generateModifyVars() { 11 | // const palettes = generateAntColors(primaryColor) 12 | // const primary = palettes[5] 13 | // const primaryColorObj: Record = {} 14 | 15 | // for (let index = 0; index < 10; index++) { 16 | // primaryColorObj[`primary-${index + 1}`] = palettes[index] 17 | // } 18 | // const modifyVars = getThemeVariables(); 19 | const mapToken = defaultAlgorithm(defaultSeed) 20 | const v3Token = convertLegacyToken(mapToken) 21 | return { 22 | ...v3Token, 23 | // reference: Avoid repeated references 24 | hack: `true; @import (reference) "${resolve('src/styles/config.less')}";`, 25 | // 'primary-color': primary, 26 | // ...primaryColorObj, 27 | // 'info-color': primary, 28 | // 'processing-color': primary, 29 | // 'success-color': '#55D187', // Success color 30 | // 'error-color': '#ED6F6F', // False color 31 | // 'warning-color': '#EFBD47', // Warning color 32 | // 'font-size-base': '14px', // Main font size 33 | // 'border-radius-base': '2px', // Component/float fillet 34 | // 'link-color': primary // Link color 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Button/src/PopConfirmButton.vue: -------------------------------------------------------------------------------- 1 | 49 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Form/src/hooks/useLabelWidth.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | import { computed, unref } from 'vue' 3 | import { isNumber } from '@/utils/is' 4 | import type { FormProps, FormSchema } from '../types/form' 5 | 6 | export function useItemLabelWidth(schemaItemRef: Ref, propsRef: Ref) { 7 | return computed(() => { 8 | const schemaItem = unref(schemaItemRef) 9 | const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {} 10 | const { labelWidth, disabledLabelWidth } = schemaItem 11 | 12 | const { labelWidth: globalLabelWidth, labelCol: globalLabelCol, wrapperCol: globWrapperCol, layout } = unref(propsRef) 13 | 14 | // If labelWidth is set globally, all items setting 15 | if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) { 16 | labelCol.style = { 17 | textAlign: 'left', 18 | } 19 | return { labelCol, wrapperCol } 20 | } 21 | let width = labelWidth || globalLabelWidth 22 | const col = { ...globalLabelCol, ...labelCol } 23 | const wrapCol = { ...globWrapperCol, ...wrapperCol } 24 | 25 | if (width) { 26 | width = isNumber(width) ? `${width}px` : width 27 | } 28 | 29 | return { 30 | labelCol: { style: { width }, ...col }, 31 | wrapperCol: { 32 | style: { width: layout === 'vertical' ? '100%' : `calc(100% - ${width})` }, 33 | ...wrapCol, 34 | }, 35 | } 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/sider/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 29 | 54 | -------------------------------------------------------------------------------- /yxboot-admin/src/enums/designSetting.ts: -------------------------------------------------------------------------------- 1 | // primary preset color 2 | export const APP_PRESET_COLOR_LIST: string[] = ['#0960bd', '#0084f4', '#009688', '#536dfe', '#ff5c93', '#ee4f12', '#0096c7', '#9c27b0', '#ff9800'] 3 | 4 | export enum HandlerSettingEnum { 5 | CHANGE_LAYOUT, 6 | CHANGE_THEME_COLOR, 7 | CHANGE_THEME, 8 | // menu 9 | MENU_HAS_DRAG, 10 | MENU_ACCORDION, 11 | MENU_TRIGGER, 12 | MENU_TOP_ALIGN, 13 | MENU_COLLAPSED, 14 | MENU_COLLAPSED_SHOW_TITLE, 15 | MENU_WIDTH, 16 | MENU_SHOW_SIDEBAR, 17 | MENU_THEME, 18 | MENU_SPLIT, 19 | MENU_FIXED, 20 | MENU_CLOSE_MIX_SIDEBAR_ON_CHANGE, 21 | MENU_TRIGGER_MIX_SIDEBAR, 22 | MENU_FIXED_MIX_SIDEBAR, 23 | 24 | // header 25 | HEADER_SHOW, 26 | HEADER_THEME, 27 | HEADER_FIXED, 28 | 29 | HEADER_SEARCH, 30 | 31 | TABS_SHOW_QUICK, 32 | TABS_SHOW_REDO, 33 | TABS_SHOW, 34 | TABS_SHOW_FOLD, 35 | 36 | LOCK_TIME, 37 | FULL_CONTENT, 38 | CONTENT_MODE, 39 | SHOW_BREADCRUMB, 40 | SHOW_BREADCRUMB_ICON, 41 | GRAY_MODE, 42 | COLOR_WEAK, 43 | SHOW_LOGO, 44 | SHOW_FOOTER, 45 | 46 | ROUTER_TRANSITION, 47 | OPEN_PROGRESS, 48 | OPEN_PAGE_LOADING, 49 | OPEN_ROUTE_TRANSITION, 50 | } 51 | 52 | export enum ThemeChangeEnum { 53 | THEME_CHANGE, 54 | 55 | THEME_PRIMARY_COLOR_CHANGE, 56 | THEME_INFO_COLOR_CHANGE, 57 | THEME_SUCCESS_COLOR_CHANGE, 58 | THEME_WARNING_COLOR_CHANGE, 59 | THEME_ERROR_COLOR_CHANGE, 60 | 61 | THEME_HEADER_BG_COLOR_CHANGE, 62 | THEME_SIDEBAR_BG_COLOR_CHANGE, 63 | } 64 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/useSiderSetting.ts: -------------------------------------------------------------------------------- 1 | import { storeToRefs } from 'pinia' 2 | import { ThemeEnum } from '@/enums' 3 | import { useAppConfigStore } from '@/store/modules/appConfig' 4 | 5 | export function useSiderSetting() { 6 | const appConfigStore = useAppConfigStore() 7 | const { setSiderSetting } = appConfigStore 8 | const { getSiderSetting } = storeToRefs(appConfigStore) 9 | 10 | const getSiderTheme = computed(() => unref(getSiderSetting).theme) 11 | const getFixed = computed(() => unref(getSiderSetting).fixed) 12 | const getShowSider = computed(() => unref(getSiderSetting).show) 13 | const getWidth = computed(() => unref(getSiderSetting).width) 14 | const getMixSidebarWidth = computed(() => unref(getSiderSetting).mixSidebarWidth) 15 | const getCollapsedWidth = computed(() => unref(getSiderSetting).collapsedWidth) 16 | const getCollapsed = computed(() => unref(getSiderSetting).collapsed) 17 | 18 | function toggleTheme() { 19 | setSiderSetting({ 20 | theme: unref(getSiderTheme) === ThemeEnum.DARK ? ThemeEnum.LIGHT : ThemeEnum.DARK, 21 | }) 22 | } 23 | 24 | function toggleCollapsed() { 25 | setSiderSetting({ 26 | collapsed: !unref(getCollapsed), 27 | }) 28 | } 29 | 30 | return { 31 | setSiderSetting, 32 | 33 | getSiderTheme, 34 | getFixed, 35 | getShowSider, 36 | getWidth, 37 | getMixSidebarWidth, 38 | getCollapsedWidth, 39 | getCollapsed, 40 | 41 | toggleTheme, 42 | toggleCollapsed, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/workplace/components/WorkbenchHeader.vue: -------------------------------------------------------------------------------- 1 | 26 | 33 | 38 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/menu/MenuDrawer.vue: -------------------------------------------------------------------------------- 1 | 6 | 48 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/dict/DictDrawer.vue: -------------------------------------------------------------------------------- 1 | 6 | 48 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/is.ts: -------------------------------------------------------------------------------- 1 | export { 2 | isArguments, 3 | isArrayBuffer, 4 | isArrayLike, 5 | isArrayLikeObject, 6 | isBoolean, 7 | isBuffer, 8 | isDate, 9 | isElement, 10 | isEmpty, 11 | isEqual, 12 | isEqualWith, 13 | isError, 14 | isFinite, 15 | isFunction, 16 | isLength, 17 | isMap, 18 | isMatch, 19 | isMatchWith, 20 | isNative, 21 | isNil, 22 | isNull, 23 | isNumber, 24 | isObjectLike, 25 | isPlainObject, 26 | isRegExp, 27 | isSafeInteger, 28 | isSet, 29 | isString, 30 | isSymbol, 31 | isTypedArray, 32 | isUndefined, 33 | isWeakMap, 34 | isWeakSet, 35 | } from 'lodash-es' 36 | 37 | export function is(val: unknown, type: string) { 38 | return toString.call(val) === `[object ${type}]` 39 | } 40 | 41 | export function isDef(val?: T): val is T { 42 | return typeof val !== 'undefined' 43 | } 44 | 45 | // TODO 此处 isObject 存在歧义 46 | export function isObject(val: any): val is Record { 47 | return val !== null && is(val, 'Object') 48 | } 49 | 50 | // TODO 此处 isArray 存在歧义 51 | export function isArray(val: any): val is Array { 52 | return val && Array.isArray(val) 53 | } 54 | 55 | export function isWindow(val: any): val is Window { 56 | return typeof window !== 'undefined' && is(val, 'Window') 57 | } 58 | 59 | export const isServer = typeof window === 'undefined' 60 | 61 | export const isClient = !isServer 62 | 63 | export function isHttpUrl(path: string): boolean { 64 | const reg = /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?/ 65 | return reg.test(path) 66 | } 67 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/sys/user/UserDrawer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 50 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/security/SysUserDetailsService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.security; 2 | 3 | import com.yxboot.modules.sys.entity.SysUser; 4 | import com.yxboot.modules.sys.service.SysUserService; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * 实现UserDetailsService接口,用于加载用户信息 18 | * 19 | * @author Boya 20 | */ 21 | @Slf4j 22 | @Component(value = "tenantUserDetailsService") 23 | public class SysUserDetailsService implements UserDetailsService { 24 | 25 | @Autowired 26 | private SysUserService sysUserService; 27 | 28 | @Override 29 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 30 | // 查询数据库操作 31 | SysUser user = sysUserService.selectByUsername(username); 32 | if (user != null) { 33 | List authorities = new ArrayList<>(); 34 | return new SecurityUser(user.getUserId(), username, user.getPassword(), authorities); 35 | } else { 36 | throw new UsernameNotFoundException("the user is not found"); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /yxboot-admin/types/axios.d.ts: -------------------------------------------------------------------------------- 1 | export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined 2 | 3 | export interface RequestOptions { 4 | // Splicing request parameters to url 5 | joinParamsToUrl?: boolean 6 | // Format request parameter time 7 | formatDate?: boolean 8 | // Whether to process the request result 9 | isTransformResponse?: boolean 10 | // Whether to return native response headers 11 | // For example: use this attribute when you need to get the response headers 12 | isReturnNativeResponse?: boolean 13 | // Whether to join url 14 | joinPrefix?: boolean 15 | // Interface address, use the default apiUrl if you leave it blank 16 | apiUrl?: string 17 | // 请求拼接路径 18 | urlPrefix?: string 19 | // Error message prompt type 20 | errorMessageMode?: ErrorMessageMode 21 | // Whether to add a timestamp 22 | joinTime?: boolean 23 | ignoreCancelToken?: boolean 24 | // Whether to send token in header 25 | withToken?: boolean 26 | // 请求重试机制 27 | retryRequest?: RetryRequest 28 | } 29 | 30 | export interface RetryRequest { 31 | isOpenRetry: boolean 32 | count: number 33 | waitTime: number 34 | } 35 | export interface Result { 36 | code: number 37 | type: 'success' | 'error' | 'warning' 38 | msg: string 39 | data: T 40 | } 41 | 42 | // multipart/form-data: upload file 43 | export interface UploadFileParams { 44 | // Other parameters 45 | data?: Recordable 46 | // File parameter interface field name 47 | name?: string 48 | // file name 49 | file: File | Blob 50 | // file name 51 | filename?: string 52 | [key: string]: any 53 | } 54 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Modal/src/hooks/useModalFullScreen.ts: -------------------------------------------------------------------------------- 1 | import { computed, type Ref, ref, unref } from 'vue' 2 | 3 | export interface UseFullScreenContext { 4 | wrapClassName: Ref 5 | modalWrapperRef: Ref 6 | extHeightRef: Ref 7 | } 8 | 9 | export function useFullScreen(context: UseFullScreenContext) { 10 | // const formerHeightRef = ref(0); 11 | const fullScreenRef = ref(false) 12 | 13 | const getWrapClassName = computed(() => { 14 | const clsName = unref(context.wrapClassName) || '' 15 | return unref(fullScreenRef) ? `fullscreen-modal ${clsName} ` : unref(clsName) 16 | }) 17 | 18 | function handleFullScreen(e: Event) { 19 | e?.stopPropagation() 20 | fullScreenRef.value = !unref(fullScreenRef) 21 | 22 | // const modalWrapper = unref(context.modalWrapperRef); 23 | 24 | // if (!modalWrapper) return; 25 | 26 | // const wrapperEl = modalWrapper.$el as HTMLElement; 27 | // if (!wrapperEl) return; 28 | // const modalWrapSpinEl = wrapperEl.querySelector('.ant-spin-nested-loading') as HTMLElement; 29 | 30 | // if (!modalWrapSpinEl) return; 31 | 32 | // if (!unref(formerHeightRef) && unref(fullScreenRef)) { 33 | // formerHeightRef.value = modalWrapSpinEl.offsetHeight; 34 | // } 35 | 36 | // if (unref(fullScreenRef)) { 37 | // modalWrapSpinEl.style.height = `${window.innerHeight - unref(context.extHeightRef)}px`; 38 | // } else { 39 | // modalWrapSpinEl.style.height = `${unref(formerHeightRef)}px`; 40 | // } 41 | } 42 | return { getWrapClassName, handleFullScreen, fullScreenRef } 43 | } 44 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Basic/src/BasicTitle.vue: -------------------------------------------------------------------------------- 1 | 7 | 26 | 61 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/http/axios/checkStatus.ts: -------------------------------------------------------------------------------- 1 | import { message as Message, Modal } from 'ant-design-vue' 2 | import type { ErrorMessageMode } from '#/axios' 3 | 4 | export function checkStatus(status: number, msg: string, errorMessageMode: ErrorMessageMode = 'message'): void { 5 | let errMessage = '' 6 | switch (status) { 7 | case 400: 8 | errMessage = msg 9 | break 10 | // 401: 未登录 11 | // 未登录则跳转登录页面,并携带当前页面的路径 12 | // 在登录成功后返回当前页面,这一步需要在登录页操作。 13 | case 401: 14 | errMessage = '用户没有权限(令牌、用户名、密码错误)!' 15 | break 16 | case 403: 17 | errMessage = '用户得到授权,但是访问是被禁止的。!' 18 | break 19 | // 404请求不存在 20 | case 404: 21 | errMessage = '网络请求错误,未找到该资源!' 22 | break 23 | case 405: 24 | errMessage = '网络请求错误,请求方法未允许!' 25 | break 26 | case 408: 27 | errMessage = '网络请求超时' 28 | break 29 | case 500: 30 | errMessage = '服务器错误,请联系管理员!' 31 | break 32 | case 501: 33 | errMessage = '网络未实现' 34 | break 35 | case 502: 36 | errMessage = '网络错误' 37 | break 38 | case 503: 39 | errMessage = '服务不可用,服务器暂时过载或维护!' 40 | break 41 | case 504: 42 | errMessage = '网络超时' 43 | break 44 | case 505: 45 | errMessage = 'http版本不支持该请求!' 46 | break 47 | default: 48 | errMessage = msg 49 | } 50 | 51 | if (errMessage) { 52 | if (errorMessageMode === 'modal') { 53 | Modal.error({ title: '错误提示', content: errMessage }) 54 | } else if (errorMessageMode === 'message') { 55 | Message.error({ content: errMessage, key: `global_error_message_status_${status}` }) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysRoleService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysRoleTableDef.SYS_ROLE; 4 | import java.util.List; 5 | import org.springframework.stereotype.Service; 6 | import com.mybatisflex.core.paginate.Page; 7 | import com.mybatisflex.core.query.QueryWrapper; 8 | import com.mybatisflex.spring.service.impl.ServiceImpl; 9 | import com.yxboot.common.pagination.PageRequest; 10 | import com.yxboot.modules.sys.entity.SysRole; 11 | import com.yxboot.modules.sys.mapper.SysRoleMapper; 12 | import cn.hutool.core.util.StrUtil; 13 | 14 | 15 | /** 16 | * 角色表业务实现类 17 | * 18 | * @author Boya 19 | */ 20 | @Service 21 | public class SysRoleService extends ServiceImpl { 22 | public Page pageQuery(String name, String status, PageRequest pageRequest) { 23 | QueryWrapper wrapper = QueryWrapper.create(); 24 | if (StrUtil.isNotEmpty(name)) { 25 | wrapper.where(SYS_ROLE.NAME.like(name)); 26 | } 27 | if (StrUtil.isNotEmpty(status)) { 28 | wrapper.where(SYS_ROLE.STATUS.eq(status)); 29 | } 30 | return page(pageRequest.convertToPage(), wrapper); 31 | } 32 | 33 | public List query(String name, String status) { 34 | QueryWrapper wrapper = QueryWrapper.create(); 35 | if (StrUtil.isNotEmpty(name)) { 36 | wrapper.where(SYS_ROLE.NAME.like(name)); 37 | } 38 | if (StrUtil.isNotEmpty(status)) { 39 | wrapper.where(SYS_ROLE.STATUS.eq(status)); 40 | } 41 | return list(wrapper); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/menu/components/MenuGroup.vue: -------------------------------------------------------------------------------- 1 | 23 | 59 | 60 | -------------------------------------------------------------------------------- /yxboot-admin/src/utils/http/axios/axiosTransform.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Data processing class, can be configured according to the project 3 | */ 4 | 5 | import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults } from 'axios' 6 | import type { RequestOptions, Result } from '#/axios' 7 | 8 | export interface CreateAxiosOptions extends AxiosRequestConfig, CreateAxiosDefaults { 9 | authenticationScheme?: string 10 | transform?: AxiosTransform 11 | requestOptions?: RequestOptions 12 | } 13 | 14 | export abstract class AxiosTransform { 15 | /** 16 | * @description: Process configuration before request 17 | * @description: Process configuration before request 18 | */ 19 | beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig 20 | 21 | /** 22 | * @description: Request successfully processed 23 | */ 24 | transformRequestHook?: (res: AxiosResponse, options: RequestOptions) => any 25 | 26 | /** 27 | * @description: 请求失败处理 28 | */ 29 | requestCatchHook?: (e: Error, options: RequestOptions) => Promise 30 | 31 | /** 32 | * @description: 请求之前的拦截器 33 | */ 34 | requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => AxiosRequestConfig 35 | 36 | /** 37 | * @description: 请求之后的拦截器 38 | */ 39 | responseInterceptors?: (res: AxiosResponse) => AxiosResponse 40 | 41 | /** 42 | * @description: 请求之前的拦截器错误处理 43 | */ 44 | requestInterceptorsCatch?: (error: Error) => void 45 | 46 | /** 47 | * @description: 请求之后的拦截器错误处理 48 | */ 49 | responseInterceptorsCatch?: (axiosInstance: AxiosInstance, error: Error) => void 50 | } 51 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/modules/sys/service/SysDictService.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.modules.sys.service; 2 | 3 | import static com.yxboot.modules.sys.entity.table.SysDictTableDef.SYS_DICT; 4 | import org.springframework.stereotype.Service; 5 | import com.mybatisflex.core.paginate.Page; 6 | import com.mybatisflex.core.query.QueryWrapper; 7 | import com.mybatisflex.spring.service.impl.ServiceImpl; 8 | import com.yxboot.common.pagination.PageRequest; 9 | import com.yxboot.modules.sys.entity.SysDict; 10 | import com.yxboot.modules.sys.mapper.SysDictMapper; 11 | import cn.hutool.core.util.StrUtil; 12 | 13 | 14 | /** 15 | * 字典表业务实现类 16 | * 17 | * @author Boya 18 | */ 19 | @Service 20 | public class SysDictService extends ServiceImpl { 21 | public Page pageQuery(String dictName, String dictCode, String status, PageRequest pageRequest) { 22 | QueryWrapper wrapper = QueryWrapper.create(); 23 | if (StrUtil.isNotEmpty(dictName)) { 24 | wrapper.where(SYS_DICT.DICT_NAME.like(dictName)); 25 | } 26 | if (StrUtil.isNotEmpty(dictCode)) { 27 | wrapper.where(SYS_DICT.DICT_CODE.like(dictCode)); 28 | } 29 | if (StrUtil.isNotEmpty(status)) { 30 | wrapper.where(SYS_DICT.STATUS.eq(status)); 31 | } 32 | return page(pageRequest.convertToPage(), wrapper); 33 | } 34 | 35 | public SysDict selectByDictCode(String dictCode) { 36 | QueryWrapper wrapper = QueryWrapper.create(); 37 | if (StrUtil.isNotEmpty(dictCode)) { 38 | wrapper.where(SYS_DICT.DICT_CODE.eq(dictCode)); 39 | } 40 | return getOne(wrapper); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/web/usePage.ts: -------------------------------------------------------------------------------- 1 | import { unref } from 'vue' 2 | import type { RouteLocationRaw, Router } from 'vue-router' 3 | import { useRouter } from 'vue-router' 4 | import { PageEnum } from '@/enums/pageEnum' 5 | import { REDIRECT_NAME } from '@/router/constant' 6 | 7 | export type PathAsPageEnum = T extends { path: string } ? T & { path: PageEnum } : T 8 | export type RouteLocationRawEx = PathAsPageEnum 9 | 10 | function handleError(e: Error) { 11 | console.error(e) 12 | } 13 | 14 | /** 15 | * page switch 16 | */ 17 | export function useGo(_router?: Router) { 18 | const { push, replace } = _router || useRouter() 19 | function go(opt: RouteLocationRawEx = PageEnum.BASE_HOME, isReplace = false) { 20 | if (!opt) { 21 | return 22 | } 23 | isReplace ? replace(opt).catch(handleError) : push(opt).catch(handleError) 24 | } 25 | return go 26 | } 27 | 28 | /** 29 | * @description: redo current page 30 | */ 31 | export const useRedo = (_router?: Router) => { 32 | const { replace, currentRoute } = _router || useRouter() 33 | const { query, params = {}, name, fullPath } = unref(currentRoute.value) 34 | function redo(): Promise { 35 | return new Promise((resolve) => { 36 | if (name === REDIRECT_NAME) { 37 | resolve(false) 38 | return 39 | } 40 | if (name && Object.keys(params).length > 0) { 41 | params['_redirect_type'] = 'name' 42 | params['path'] = String(name) 43 | } else { 44 | params['_redirect_type'] = 'path' 45 | params['path'] = fullPath 46 | } 47 | replace({ name: REDIRECT_NAME, params, query }).then(() => resolve(true)) 48 | }) 49 | } 50 | return redo 51 | } 52 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/config/upload/UploadConfig.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.config.upload; 2 | 3 | import com.yxboot.config.upload.uploader.LocalUploader; 4 | import com.yxboot.config.upload.uploader.OssUploader; 5 | import com.yxboot.config.upload.uploader.Uploader; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * 文件上传配置类 14 | * 15 | * @author Boya 16 | */ 17 | @Configuration 18 | @RequiredArgsConstructor 19 | public class UploadConfig { 20 | private final UploadProperties properties; 21 | 22 | @Bean("uploader") 23 | @ConditionalOnMissingBean(Uploader.class) 24 | public Uploader uploader() { 25 | switch (properties.getModel()) { 26 | case "local": 27 | return new LocalUploader(properties.getLocal()); 28 | case "oss": 29 | return new OssUploader(properties.getOss()); 30 | default: 31 | return null; 32 | } 33 | } 34 | 35 | @Bean("localUploader") 36 | @ConditionalOnProperty(name = "yxboot.upload.local.enable", havingValue = "true") 37 | public LocalUploader localUploader(){ 38 | return new LocalUploader(properties.getLocal()); 39 | } 40 | 41 | @Bean("ossUploader") 42 | @ConditionalOnProperty(name = "yxboot.upload.oss.enable", havingValue = "true") 43 | public OssUploader ossUploader(){ 44 | return new OssUploader(properties.getOss()); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /yxboot-admin/src/layout/setting/components/SelectItem.vue: -------------------------------------------------------------------------------- 1 | 14 | 53 | 66 | -------------------------------------------------------------------------------- /yxboot-admin/src/components/Table/src/hooks/useTableForm.ts: -------------------------------------------------------------------------------- 1 | import type { ComputedRef, Slots } from 'vue' 2 | import { computed, unref } from 'vue' 3 | import type { FormProps } from '@/components/Form' 4 | import { isFunction } from '@/utils/is' 5 | import type { BasicTableProps, FetchParams } from '../types/table' 6 | 7 | export function useTableForm( 8 | propsRef: ComputedRef, 9 | slots: Slots, 10 | fetch: (opt?: FetchParams | undefined) => Promise, 11 | getLoading: ComputedRef, 12 | ) { 13 | const getFormProps = computed((): Partial => { 14 | const { formConfig } = unref(propsRef) 15 | const { submitButtonOptions } = formConfig || {} 16 | return { 17 | showAdvancedButton: true, 18 | ...formConfig, 19 | submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions }, 20 | compact: true, 21 | } 22 | }) 23 | 24 | const getFormSlotKeys: ComputedRef = computed(() => { 25 | const keys = Object.keys(slots) 26 | return keys.map((item) => (item.startsWith('form-') ? item : null)).filter((item) => !!item) as string[] 27 | }) 28 | 29 | function replaceFormSlotKey(key: string) { 30 | if (!key) return '' 31 | return key?.replace?.(/form-/, '') ?? '' 32 | } 33 | 34 | function handleSearchInfoChange(info: Recordable) { 35 | const { handleSearchInfoFn } = unref(propsRef) 36 | if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) { 37 | info = handleSearchInfoFn(info) || info 38 | } 39 | fetch({ searchInfo: info, page: 1 }) 40 | } 41 | 42 | return { 43 | getFormProps, 44 | replaceFormSlotKey, 45 | getFormSlotKeys, 46 | handleSearchInfoChange, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /yxboot-admin/src/views/dashboard/analysis/components/SalesProductPie.vue: -------------------------------------------------------------------------------- 1 | 6 | 61 | -------------------------------------------------------------------------------- /yxboot-api/src/main/java/com/yxboot/common/cache/SysUserCacheUtil.java: -------------------------------------------------------------------------------- 1 | package com.yxboot.common.cache; 2 | 3 | import com.alicp.jetcache.Cache; 4 | import com.alicp.jetcache.CacheManager; 5 | import com.alicp.jetcache.anno.CacheType; 6 | import com.alicp.jetcache.template.QuickConfig; 7 | import com.yxboot.config.cache.CacheConstants; 8 | import com.yxboot.modules.sys.entity.SysUser; 9 | import com.yxboot.modules.sys.service.SysUserService; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.annotation.PostConstruct; 14 | import java.time.Duration; 15 | 16 | /** 17 | * 用户缓存类 18 | * 19 | * @author Boya 20 | */ 21 | @Component 22 | @RequiredArgsConstructor 23 | public class SysUserCacheUtil { 24 | private final CacheManager cacheManager; 25 | private final SysUserService userService; 26 | 27 | private Cache userCache; 28 | public Cache cache() { 29 | return userCache; 30 | } 31 | 32 | @PostConstruct 33 | public void init() { 34 | QuickConfig qc = QuickConfig.newBuilder(CacheConstants.SYS_USER_VALUE_CACHE_KEY) 35 | .expire(Duration.ofDays(CacheConstants.CACHE_EXPIRE_DAYS)) 36 | .cacheType(CacheType.BOTH) 37 | .localLimit(50) 38 | .syncLocal(true) 39 | .build(); 40 | userCache = cacheManager.getOrCreateCache(qc); 41 | } 42 | 43 | public SysUser getUser(Long userId) { 44 | SysUser user = userCache.get(userId); 45 | if (user == null) { 46 | user = userService.getById(userId); 47 | userCache.put(userId, user); 48 | } 49 | return user; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /yxboot-admin/src/hooks/setting/useThemeSetting.ts: -------------------------------------------------------------------------------- 1 | import { storeToRefs } from 'pinia' 2 | import { useAppConfigStore } from '@/store/modules/appConfig' 3 | 4 | export function useThemeSetting() { 5 | const appConfigStore = useAppConfigStore() 6 | const { setThemeSetting } = appConfigStore 7 | const { getThemeSetting } = storeToRefs(appConfigStore) 8 | 9 | const getTheme = computed(() => unref(getThemeSetting).theme) 10 | const getThemeType = computed(() => unref(getThemeSetting).themeType) 11 | const getBorderRadius = computed(() => unref(getThemeSetting).borderRadius) 12 | const getPrimaryColor = computed(() => unref(getThemeSetting).primaryColor) 13 | const getSuccessColor = computed(() => unref(getThemeSetting).successColor) 14 | const getWarningColor = computed(() => unref(getThemeSetting).warningColor) 15 | const getErrorColor = computed(() => unref(getThemeSetting).errorColor) 16 | const getInfoColor = computed(() => unref(getThemeSetting).infoColor) 17 | const getThemeColors = computed(() => { 18 | return { 19 | colorPrimary: getPrimaryColor.value, 20 | colorSuccess: getSuccessColor.value, 21 | colorWarning: getWarningColor.value, 22 | colorError: getErrorColor.value, 23 | colorInfo: getInfoColor.value, 24 | } 25 | }) 26 | const getToken = computed(() => { 27 | return { 28 | ...getThemeColors.value, 29 | borderRadius: getBorderRadius.value, 30 | } 31 | }) 32 | 33 | return { 34 | setThemeSetting, 35 | 36 | getTheme, 37 | getThemeType, 38 | getToken, 39 | getThemeColors, 40 | getBorderRadius, 41 | getPrimaryColor, 42 | getSuccessColor, 43 | getWarningColor, 44 | getErrorColor, 45 | getInfoColor, 46 | } 47 | } 48 | --------------------------------------------------------------------------------