Merge branch 'ts' into future/flowable

This commit is contained in:
gssong 2023-09-22 23:23:38 +08:00
commit f4684fb0dc
45 changed files with 241 additions and 187 deletions

View File

@ -30,7 +30,7 @@ module.exports = {
extendDefaults: true, extendDefaults: true,
types: { types: {
'{}': false, '{}': false,
'Function': false Function: false
} }
} }
] ]

20
LICENSE Normal file
View File

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

View File

@ -76,7 +76,7 @@
"vite": "4.3.1", "vite": "4.3.1",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-setup-extend": "^0.4.0", "unplugin-vue-setup-extend-plus": "0.4.9",
"vitest": "^0.29.7", "vitest": "^0.29.7",
"vue-eslint-parser": "9.1.0", "vue-eslint-parser": "9.1.0",
"vue-tsc": "0.35.0" "vue-tsc": "0.35.0"

View File

@ -32,7 +32,8 @@ export function register(data: any) {
return request({ return request({
url: '/auth/register', url: '/auth/register',
headers: { headers: {
isToken: false isToken: false,
isEncrypt: true
}, },
method: 'post', method: 'post',
data: data data: data

View File

@ -43,7 +43,6 @@ export interface ClientVO {
* 0 1 * 0 1
*/ */
status: string; status: string;
} }
export interface ClientForm extends BaseEntity { export interface ClientForm extends BaseEntity {
@ -91,7 +90,6 @@ export interface ClientForm extends BaseEntity {
* 0 1 * 0 1
*/ */
status?: string; status?: string;
} }
export interface ClientQuery extends PageQuery { export interface ClientQuery extends PageQuery {
@ -134,5 +132,4 @@ export interface ClientQuery extends PageQuery {
* 0 1 * 0 1
*/ */
status?: string; status?: string;
} }

View File

@ -24,6 +24,9 @@ export function addTenant(data: TenantForm) {
return request({ return request({
url: '/system/tenant', url: '/system/tenant',
method: 'post', method: 'post',
headers: {
isEncrypt: true
},
data: data data: data
}); });
} }

View File

@ -74,6 +74,9 @@ export const resetUserPwd = (userId: string | number, password: string) => {
return request({ return request({
url: '/system/user/resetPwd', url: '/system/user/resetPwd',
method: 'put', method: 'put',
headers: {
isEncrypt: true
},
data: data data: data
}); });
}; };
@ -130,6 +133,9 @@ export const updateUserPwd = (oldPassword: string, newPassword: string) => {
return request({ return request({
url: '/system/user/profile/updatePwd', url: '/system/user/profile/updatePwd',
method: 'put', method: 'put',
headers: {
isEncrypt: true
},
params: data params: data
}); });
}; };
@ -175,8 +181,8 @@ export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
*/ */
export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]> => { export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]> => {
return request({ return request({
url: "/system/user/list/dept/" + deptId, url: '/system/user/list/dept/' + deptId,
method: "get" method: 'get'
}); });
}; };

View File

@ -37,7 +37,7 @@ export const updateGenTable = (data: DbTableForm) => {
}; };
// 导入表 // 导入表
export const importTable = (data: { tables: string, dataName: string }) => { export const importTable = (data: { tables: string; dataName: string }) => {
return request({ return request({
url: '/tool/gen/importTable', url: '/tool/gen/importTable',
method: 'post', method: 'post',

View File

@ -78,8 +78,6 @@
overflow-x: hidden; overflow-x: hidden;
} }
// refine element ui upload // refine element ui upload
.upload-container { .upload-container {
.el-upload { .el-upload {
@ -109,7 +107,7 @@
box-sizing: content-box; box-sizing: content-box;
} }
.el-menu--collapse>div>.el-submenu>.el-submenu__title .el-submenu__icon-arrow { .el-menu--collapse > div > .el-submenu > .el-submenu__title .el-submenu__icon-arrow {
display: none; display: none;
} }

View File

@ -26,7 +26,8 @@ html {
box-sizing: border-box; box-sizing: border-box;
} }
html.dark .svg-icon, html.dark svg { html.dark .svg-icon,
html.dark svg {
fill: var(--el-text-color-regular); fill: var(--el-text-color-regular);
} }

View File

@ -81,10 +81,16 @@
} }
// menu hover // menu hover
.theme-dark .sub-menu-title-noDropdown,
.theme-dark .el-sub-menu__title {
&:hover {
background-color: $base-sub-menu-title-hover !important;
}
}
.sub-menu-title-noDropdown, .sub-menu-title-noDropdown,
.el-sub-menu__title { .el-sub-menu__title {
&:hover { &:hover {
background-color: $base-sub-menu-title-hover !important; background-color: rgba(0, 0, 0, 0.05) !important;
} }
} }
@ -95,12 +101,12 @@
& .nest-menu .el-sub-menu > .el-sub-menu__title, & .nest-menu .el-sub-menu > .el-sub-menu__title,
& .el-sub-menu .el-menu-item { & .el-sub-menu .el-menu-item {
min-width: $base-sidebar-width !important; min-width: $base-sidebar-width !important;
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.06) !important; background-color: rgba(0, 0, 0, 0.1) !important;
} }
} }
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title, & .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
& .theme-dark .el-sub-menu .el-menu-item { & .theme-dark .el-sub-menu .el-menu-item {
background-color: $base-sub-menu-background !important; background-color: $base-sub-menu-background !important;
@ -109,6 +115,21 @@
background-color: $base-sub-menu-hover !important; background-color: $base-sub-menu-hover !important;
} }
} }
& .theme-dark .nest-menu .el-sub-menu > .el-sub-menu__title,
& .theme-dark .el-menu-item {
&:hover {
// you can use $sub-menuHover
background-color: $base-menu-hover !important;
}
}
& .nest-menu .el-sub-menu > .el-sub-menu__title,
& .el-menu-item {
&:hover {
// you can use $sub-menuHover
background-color: rgba(0, 0, 0, 0.04) !important;
}
}
} }
.hideSidebar { .hideSidebar {
@ -207,14 +228,6 @@
} }
} }
.nest-menu .el-sub-menu > .el-sub-menu__title,
.el-menu-item {
&:hover {
// you can use $sub-menuHover
background-color: $base-menu-hover !important;
}
}
// the scroll bar appears when the sub-menu is too long // the scroll bar appears when the sub-menu is too long
> .el-menu--popup { > .el-menu--popup {
max-height: 100vh; max-height: 100vh;

View File

@ -4,11 +4,11 @@
const props = defineProps({ const props = defineProps({
formJson: { formJson: {
type: [String, Object], type: [String, Object],
default: {} default: ""
}, },
formData: { formData: {
type: [String, Object], type: [String, Object],
default: {} default: ""
}, },
isView: { isView: {
type: Boolean, type: Boolean,

View File

@ -2,7 +2,8 @@
<div> <div>
<template v-for="(item, index) in options"> <template v-for="(item, index) in options">
<template v-if="values.includes(item.value)"> <template v-if="values.includes(item.value)">
<span v-if="item.elTagType == 'default' || item.elTagType == ''" :key="item.value" :index="index" :class="item.elTagClass"> <span v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
:key="item.value" :index="index" :class="item.elTagClass">
{{ item.label + " " }} {{ item.label + " " }}
</span> </span>
<el-tag <el-tag
@ -37,46 +38,33 @@ const props = defineProps({
value: [Number, String, Array] as PropType<number | string | Array<number | string>>, value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
// value // value
showValue: propTypes.bool.def(true), showValue: propTypes.bool.def(true),
separator: propTypes.string.def(","),
}); });
const values = computed(() => { const values = computed(() => {
if (props.value !== null && typeof props.value !== "undefined") { if (props.value === '' || props.value === null || typeof props.value === "undefined") return []
return Array.isArray(props.value) ? props.value : [String(props.value)]; return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator);
} else {
return [];
}
}); });
const unmatch = computed(() => { const unmatch = computed(() => {
if (props.value !== null && typeof props.value !== "undefined") { if (props.options?.length == 0 || props.value === '' || props.value === null || typeof props.value === "undefined") return false
// //
if (!Array.isArray(props.value)) { values.value.forEach(item => {
if (props.options.some((v) => v.value == props.value)) { if (!props.options.some(v => v.value === item)) {
return false; return true // true
} }
return true; })
} return false //
return true;
}
// value
return false;
}); });
const unmatchArray = computed(() => { const unmatchArray = computed(() => {
// //
const itemUnmatchArray: Array<string | number> = []; const itemUnmatchArray: Array<string | number> = [];
if (props.value !== null && typeof props.value !== "undefined") { if (props.value !== '' && props.value !== null && typeof props.value !== "undefined") {
// values.value.forEach(item => {
if (!Array.isArray(props.value)) { if (!props.options.some(v => v.value === item)) {
itemUnmatchArray.push(props.value);
} else {
// Array
props.value.forEach((item) => {
if (!props.options.some((v) => v.value == item)) {
itemUnmatchArray.push(item); itemUnmatchArray.push(item);
} }
}); })
}
} }
// value // value
return handleArray(itemUnmatchArray); return handleArray(itemUnmatchArray);

View File

@ -68,6 +68,10 @@ const selectedIcon = (iconName: string) => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.el-scrollbar {
max-height: calc(50vh - 100px)!important;
overflow-y: auto;
}
.el-divider--horizontal { .el-divider--horizontal {
margin: 10px auto !important; margin: 10px auto !important;
} }

View File

@ -2,7 +2,9 @@
<el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false"> <el-menu :default-active="activeMenu" mode="horizontal" @select="handleSelect" :ellipsis="false">
<template v-for="(item, index) in topMenus"> <template v-for="(item, index) in topMenus">
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber" <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
><svg-icon :icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item ><svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta ? item.meta.icon : '' " /> {{ item.meta?.title }}</el-menu-item
> >
</template> </template>
@ -180,4 +182,14 @@ onMounted(() => {
padding: 0 5px !important; padding: 0 5px !important;
margin: 0 10px !important; margin: 0 10px !important;
} }
/* 背景色隐藏 */
.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
background-color: #ffffff !important;
}
/* 图标右间距 */
.topmenu-container .svg-icon {
margin-right: 4px;
}
</style> </style>

View File

@ -0,0 +1,4 @@
export enum SideThemeEnum {
DARK = 'theme-dark',
LIGHT = 'theme-light'
}

View File

@ -58,7 +58,7 @@
<router-link to="/user/profile" v-if="!dynamic"> <router-link to="/user/profile" v-if="!dynamic">
<el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item> <el-dropdown-item>{{ $t('navbar.personalCenter') }}</el-dropdown-item>
</router-link> </router-link>
<el-dropdown-item command="setLayout"> <el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
<span>{{ $t('navbar.layoutSetting') }}</span> <span>{{ $t('navbar.layoutSetting') }}</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided command="logout"> <el-dropdown-item divided command="logout">
@ -73,7 +73,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import SearchMenu from './topBar/search.vue'; import SearchMenu from './TopBar/search.vue';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings'; import useSettingsStore from '@/store/modules/settings';

View File

@ -3,7 +3,7 @@
<h3 class="drawer-title">主题风格设置</h3> <h3 class="drawer-title">主题风格设置</h3>
<div class="setting-drawer-block-checbox"> <div class="setting-drawer-block-checbox">
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')"> <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.DARK)">
<img src="@/assets/images/dark.svg" alt="dark" /> <img src="@/assets/images/dark.svg" alt="dark" />
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
<i aria-label="图标: check" class="anticon anticon-check"> <i aria-label="图标: check" class="anticon anticon-check">
@ -15,7 +15,7 @@
</i> </i>
</div> </div>
</div> </div>
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')"> <div class="setting-drawer-block-checbox-item" @click="handleTheme(SideThemeEnum.LIGHT)">
<img src="@/assets/images/light.svg" alt="light" /> <img src="@/assets/images/light.svg" alt="light" />
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;"> <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
<i aria-label="图标: check" class="anticon anticon-check"> <i aria-label="图标: check" class="anticon anticon-check">
@ -95,6 +95,7 @@ import usePermissionStore from '@/store/modules/permission'
import { handleThemeStyle } from '@/utils/theme' import { handleThemeStyle } from '@/utils/theme'
import { ComponentInternalInstance } from "vue"; import { ComponentInternalInstance } from "vue";
import { SettingTypeEnum } from "@/enums/SettingTypeEnum"; import { SettingTypeEnum } from "@/enums/SettingTypeEnum";
import { SideThemeEnum } from "@/enums/SideThemeEnum";
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const appStore = useAppStore() const appStore = useAppStore()
@ -114,6 +115,13 @@ const isDark = useDark({
valueDark: 'dark', valueDark: 'dark',
valueLight: 'light', valueLight: 'light',
}); });
watch(isDark, ()=> {
if (isDark.value) {
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
} else {
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: sideTheme.value })
}
})
const toggleDark = () => useToggle(isDark); const toggleDark = () => useToggle(isDark);
/** 是否需要topNav */ /** 是否需要topNav */
@ -166,8 +174,13 @@ const themeChange = (val: string | null) => {
} }
} }
const handleTheme = (val: string) => { const handleTheme = (val: string) => {
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
sideTheme.value = val; sideTheme.value = val;
if (isDark.value && val === SideThemeEnum.LIGHT) {
//
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: SideThemeEnum.DARK })
return
}
settingsStore.changeSetting({ key: SettingTypeEnum.SIDE_THEME, value: val })
} }
const saveSetting = () => { const saveSetting = () => {
proxy?.$modal.loading("正在保存到本地,请稍候..."); proxy?.$modal.loading("正在保存到本地,请稍候...");

View File

@ -27,7 +27,6 @@ import variables from '@/assets/styles/variables.module.scss'
import useAppStore from '@/store/modules/app' import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings' import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission' import usePermissionStore from '@/store/modules/permission'
import { ComponentInternalInstance } from "vue";
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute(); const route = useRoute();

View File

@ -4,9 +4,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { login, callback } from '@/api/login'; import { login, callback } from '@/api/login';
import { setToken } from '@/utils/auth'; import { setToken, getToken } from '@/utils/auth';
import Cookies from 'js-cookie';
import { getToken } from '@/utils/auth';
import { LoginData } from '@/api/types'; import { LoginData } from '@/api/types';
const route = useRoute(); const route = useRoute();
@ -20,7 +18,7 @@ const loading = ref(true);
const code = route.query.code as string; const code = route.query.code as string;
const state = route.query.state as string; const state = route.query.state as string;
const source = route.query.source as string; const source = route.query.source as string;
const tenantId = Cookies.get("tenantId") ? Cookies.get("tenantId") as string : '000000'; const tenantId = localStorage.getItem("tenantId") ? localStorage.getItem("tenantId") as string : '000000';
const processResponse = async (res: any) => { const processResponse = async (res: any) => {

View File

@ -278,7 +278,7 @@ onMounted(() => {
height: 8px; height: 8px;
border-radius: 50%; border-radius: 50%;
position: relative; position: relative;
margin-right: 2px; margin-right: 5px;
} }
} }
} }

View File

@ -3,7 +3,7 @@ import FileSaver from 'file-saver';
import errorCode from '@/utils/errorCode'; import errorCode from '@/utils/errorCode';
import { blobValidate } from '@/utils/ruoyi'; import { blobValidate } from '@/utils/ruoyi';
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading'; import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
import { globalHeaders } from "@/utils/request"; import { globalHeaders } from '@/utils/request';
const baseURL = import.meta.env.VITE_APP_BASE_API; const baseURL = import.meta.env.VITE_APP_BASE_API;
let downloadLoadingInstance: LoadingInstance; let downloadLoadingInstance: LoadingInstance;
@ -16,7 +16,7 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: globalHeaders(), headers: globalHeaders()
}); });
const isBlob = blobValidate(res.data); const isBlob = blobValidate(res.data);
if (isBlob) { if (isBlob) {
@ -40,7 +40,7 @@ export default {
method: 'get', method: 'get',
url: url, url: url,
responseType: 'blob', responseType: 'blob',
headers: globalHeaders(), headers: globalHeaders()
}); });
const isBlob = blobValidate(res.data); const isBlob = blobValidate(res.data);
if (isBlob) { if (isBlob) {

View File

@ -181,5 +181,4 @@ const router = createRouter({
} }
}); });
export default router; export default router;

View File

@ -13,7 +13,7 @@ const setting: DefaultSettings = {
/** /**
* *
*/ */
showSettings: false, showSettings: true,
/** /**
* *

View File

@ -11,13 +11,13 @@ export const useSettingsStore = defineStore('setting', () => {
title: ref<string>(''), title: ref<string>(''),
theme: ref<string>(storageSetting.theme || defaultSettings.theme), theme: ref<string>(storageSetting.theme || defaultSettings.theme),
sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme), sideTheme: ref<string>(storageSetting.sideTheme || defaultSettings.sideTheme),
showSettings: ref<boolean>(storageSetting.showSettings), showSettings: ref<boolean>(storageSetting.showSettings || defaultSettings.showSettings),
topNav: ref<boolean>(storageSetting.topNav || defaultSettings.topNav), topNav: ref<boolean>(storageSetting.topNav === undefined ? defaultSettings.topNav : storageSetting.topNav),
tagsView: ref<boolean>(storageSetting.tagsView || defaultSettings.tagsView), tagsView: ref<boolean>(storageSetting.tagsView === undefined ? defaultSettings.tagsView : storageSetting.tagsView),
fixedHeader: ref<boolean>(storageSetting.fixedHeader || defaultSettings.fixedHeader), fixedHeader: ref<boolean>(storageSetting.fixedHeader === undefined ? defaultSettings.fixedHeader : storageSetting.fixedHeader),
sidebarLogo: ref<boolean>(storageSetting.sidebarLogo || defaultSettings.sidebarLogo), sidebarLogo: ref<boolean>(storageSetting.sidebarLogo === undefined ? defaultSettings.sidebarLogo : storageSetting.sidebarLogo),
dynamicTitle: ref<boolean>(storageSetting.dynamicTitle || defaultSettings.dynamicTitle), dynamicTitle: ref<boolean>(storageSetting.dynamicTitle === undefined ? defaultSettings.dynamicTitle : storageSetting.dynamicTitle),
animationEnable: ref<boolean>(storageSetting.animationEnable || defaultSettings.animationEnable), animationEnable: ref<boolean>(storageSetting.animationEnable === undefined ? defaultSettings.animationEnable : storageSetting.animationEnable),
dark: ref<boolean>(storageSetting.dark || defaultSettings.dark) dark: ref<boolean>(storageSetting.dark || defaultSettings.dark)
}; };

View File

@ -16,10 +16,10 @@ let downloadLoadingInstance: LoadingInstance;
export const isRelogin = { show: false }; export const isRelogin = { show: false };
export const globalHeaders = () => { export const globalHeaders = () => {
return { return {
Authorization: "Bearer " + getToken(), Authorization: 'Bearer ' + getToken(),
clientid: import.meta.env.VITE_APP_CLIENT_ID clientid: import.meta.env.VITE_APP_CLIENT_ID
} };
} };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'; axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID; axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;

View File

@ -68,7 +68,7 @@ export const validAlphabets = (str: string) => {
*/ */
export const validEmail = (email: string) => { export const validEmail = (email: string) => {
const reg = const reg =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; /^(([^<>()\]\\.,;:\s@"]+(\.[^<>()\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return reg.test(email); return reg.test(email);
}; };

View File

@ -5,19 +5,19 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="部门id" prop="deptId"> <el-form-item label="部门id" prop="deptId">
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="用户id" prop="userId"> <el-form-item label="用户id" prop="userId">
<el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="排序号" prop="orderNum"> <el-form-item label="排序号" prop="orderNum">
<el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.orderNum" placeholder="请输入排序号" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="key键" prop="testKey"> <el-form-item label="key键" prop="testKey">
<el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.testKey" placeholder="请输入key键" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="值" prop="value"> <el-form-item label="值" prop="value">
<el-input v-model="queryParams.value" placeholder="请输入值" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.value" placeholder="请输入值" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>

View File

@ -5,7 +5,7 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="树节点名" prop="treeName"> <el-form-item label="树节点名" prop="treeName">
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>

View File

@ -61,7 +61,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { getCodeImg, getTenantList } from '@/api/login'; import { getCodeImg, getTenantList } from '@/api/login';
import { authBinding } from '@/api/system/social/auth'; import { authBinding } from '@/api/system/social/auth';
import Cookies from 'js-cookie';
import { useUserStore } from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { LoginData, TenantVO } from '@/api/types'; import { LoginData, TenantVO } from '@/api/types';
import { to } from 'await-to-js'; import { to } from 'await-to-js';
@ -101,27 +100,32 @@ const loginRef = ref<ElFormInstance>();
// //
const tenantList = ref<TenantVO[]>([]); const tenantList = ref<TenantVO[]>([]);
watch(() => router.currentRoute.value, (newRoute: any) => {
redirect.value = newRoute.query && newRoute.query.redirect;
}, { immediate: true });
const handleLogin = () => { const handleLogin = () => {
loginRef.value?.validate(async (valid: boolean, fields: any) => { loginRef.value?.validate(async (valid: boolean, fields: any) => {
if (valid) { if (valid) {
loading.value = true; loading.value = true;
// cookie // localStorage
if (loginForm.value.rememberMe) { if (loginForm.value.rememberMe) {
Cookies.set("tenantId", String(loginForm.value.tenantId), { expires: 30 }); localStorage.setItem("tenantId", String(loginForm.value.tenantId));
Cookies.set('username', String(loginForm.value.username), { expires: 30 }); localStorage.setItem('username', String(loginForm.value.username));
Cookies.set('password', String(loginForm.value.password), { expires: 30 }); localStorage.setItem('password', String(loginForm.value.password));
Cookies.set('rememberMe', String(loginForm.value.rememberMe), { expires: 30 }); localStorage.setItem('rememberMe', String(loginForm.value.rememberMe));
} else { } else {
// //
Cookies.remove("tenantId"); localStorage.removeItem("tenantId");
Cookies.remove('username'); localStorage.removeItem('username');
Cookies.remove('password'); localStorage.removeItem('password');
Cookies.remove('rememberMe'); localStorage.removeItem('rememberMe');
} }
// action // action
const [err] = await to(userStore.login(loginForm.value)); const [err] = await to(userStore.login(loginForm.value));
if (!err) { if (!err) {
await router.push({ path: redirect.value || '/' }); await router.push({ path: redirect.value || '/' });
loading.value = false;
} else { } else {
loading.value = false; loading.value = false;
// //
@ -148,16 +152,16 @@ const getCode = async () => {
} }
}; };
const getCookie = () => { const getLoginData = () => {
const tenantId = Cookies.get("tenantId"); const tenantId = localStorage.getItem("tenantId");
const username = Cookies.get('username'); const username = localStorage.getItem('username');
const password = Cookies.get('password'); const password = localStorage.getItem('password');
const rememberMe = Cookies.get('rememberMe'); const rememberMe = localStorage.getItem('rememberMe');
loginForm.value = { loginForm.value = {
tenantId: tenantId === undefined ? String(loginForm.value.tenantId) : tenantId, tenantId: tenantId === null ? String(loginForm.value.tenantId) : tenantId,
username: username === undefined ? String(loginForm.value.username) : username, username: username === null ? String(loginForm.value.username) : username,
password: password === undefined ? String(loginForm.value.password) : String(password), password: password === null ? String(loginForm.value.password) : String(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) rememberMe: rememberMe === null ? false : Boolean(rememberMe)
} as LoginData; } as LoginData;
} }
@ -178,7 +182,7 @@ const initTenantList = async () => {
// //
watch(() => loginForm.value.tenantId, () => { watch(() => loginForm.value.tenantId, () => {
Cookies.set("tenantId", String(loginForm.value.tenantId), { expires: 30 }) localStorage.setItem("tenantId", String(loginForm.value.tenantId))
}); });
/** /**
@ -201,7 +205,7 @@ const doSocialLogin = (type: string) => {
onMounted(() => { onMounted(() => {
getCode(); getCode();
initTenantList(); initTenantList();
getCookie(); getLoginData();
}); });
</script> </script>

View File

@ -4,10 +4,10 @@
<div class="search" v-show="showSearch"> <div class="search" v-show="showSearch">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
<el-form-item label="客户端key" prop="clientKey"> <el-form-item label="客户端key" prop="clientKey">
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="客户端秘钥" prop="clientSecret"> <el-form-item label="客户端秘钥" prop="clientSecret">
<el-input v-model="queryParams.clientSecret" placeholder="请输入客户端秘钥" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.clientSecret" placeholder="请输入客户端秘钥" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="状态" clearable> <el-select v-model="queryParams.status" placeholder="状态" clearable>
@ -53,11 +53,7 @@
<el-table-column label="客户端秘钥" align="center" prop="clientSecret" /> <el-table-column label="客户端秘钥" align="center" prop="clientSecret" />
<el-table-column label="授权类型" align="center"> <el-table-column label="授权类型" align="center">
<template #default="scope"> <template #default="scope">
<div> <dict-tag :options="sys_grant_type" :value="scope.row.grantTypeList" />
<template v-for="(type, index) in scope.row.grantTypeList" :key="index">
<dict-tag class="el-check-tag" :options="sys_grant_type" :value="type" />
</template>
</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="设备类型" align="center"> <el-table-column label="设备类型" align="center">

View File

@ -5,7 +5,7 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="部门名称" prop="deptName"> <el-form-item label="部门名称" prop="deptName">
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable> <el-select v-model="queryParams.status" placeholder="部门状态" clearable>

View File

@ -49,9 +49,8 @@
<el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" /> <el-table-column label="字典编码" align="center" prop="dictCode" v-if="false" />
<el-table-column label="字典标签" align="center" prop="dictLabel"> <el-table-column label="字典标签" align="center" prop="dictLabel">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.listClass === '' || scope.row.listClass === 'default'">{{ scope.row.dictLabel }}</span> <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
<el-tag v-else :type="scope.row.listClass === 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="字典键值" align="center" prop="dictValue" /> <el-table-column label="字典键值" align="center" prop="dictValue" />

View File

@ -5,7 +5,7 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px"> <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
<el-form-item label="菜单名称" prop="menuName"> <el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable> <el-select v-model="queryParams.status" placeholder="菜单状态" clearable>

View File

@ -5,16 +5,16 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="租户编号" prop="tenantId"> <el-form-item label="租户编号" prop="tenantId">
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="联系人" prop="contactUserName"> <el-form-item label="联系人" prop="contactUserName">
<el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="联系电话" prop="contactPhone"> <el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item label="企业名称" prop="companyName"> <el-form-item label="企业名称" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>

View File

@ -5,7 +5,7 @@
<el-card shadow="hover"> <el-card shadow="hover">
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="套餐名称" prop="packageName"> <el-form-item label="套餐名称" prop="packageName">
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>

View File

@ -299,7 +299,6 @@
<script setup name="User" lang="ts"> <script setup name="User" lang="ts">
import api from "@/api/system/user" import api from "@/api/system/user"
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types'; import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import { getToken } from "@/utils/auth";
import { treeselect } from "@/api/system/dept"; import { treeselect } from "@/api/system/dept";
import { DeptVO } from "@/api/system/dept/types"; import { DeptVO } from "@/api/system/dept/types";
import { RoleVO } from "@/api/system/role/types"; import { RoleVO } from "@/api/system/role/types";

View File

@ -10,7 +10,7 @@
</template> </template>
<div> <div>
<div class="text-center"> <div class="text-center">
<userAvatar :user="state.user" /> <userAvatar/>
</div> </div>
<ul class="list-group list-group-striped"> <ul class="list-group list-group-striped">
<li class="list-group-item"> <li class="list-group-item">
@ -66,10 +66,10 @@
</template> </template>
<script setup name="Profile" lang="ts"> <script setup name="Profile" lang="ts">
import userAvatar from "./userAvatar.vue"; import UserAvatar from "./userAvatar.vue";
import userInfo from "./userInfo.vue"; import UserInfo from "./userInfo.vue";
import resetPwd from "./resetPwd.vue"; import ResetPwd from "./resetPwd.vue";
import thirdParty from "./thirdParty.vue"; import ThirdParty from "./thirdParty.vue";
import { getAuthList } from "@/api/system/social/auth"; import { getAuthList } from "@/api/system/social/auth";
import { getUserProfile } from "@/api/system/user"; import { getUserProfile } from "@/api/system/user";

View File

@ -5,7 +5,7 @@ import createComponents from './components';
import createIcons from './icons'; import createIcons from './icons';
import createSvgIconsPlugin from './svg-icon'; import createSvgIconsPlugin from './svg-icon';
import createCompression from './compression'; import createCompression from './compression';
import createVueSetupExtend from './vue-setup-extend'; import createSetupExtend from './setup-extend';
import path from 'path'; import path from 'path';
export default (viteEnv: any, isBuild = false): [] => { export default (viteEnv: any, isBuild = false): [] => {
@ -17,6 +17,6 @@ export default (viteEnv: any, isBuild = false): [] => {
vitePlusgins.push(createCompression(viteEnv)); vitePlusgins.push(createCompression(viteEnv));
vitePlusgins.push(createIcons()); vitePlusgins.push(createIcons());
vitePlusgins.push(createSvgIconsPlugin(path, isBuild)); vitePlusgins.push(createSvgIconsPlugin(path, isBuild));
vitePlusgins.push(createVueSetupExtend()); vitePlusgins.push(createSetupExtend());
return vitePlusgins; return vitePlusgins;
}; };

View File

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

View File

@ -9,6 +9,6 @@ export default () => {
'panel-title': 'panel-title':
'pb-[5px] font-sans leading-[1.1] font-medium text-base text-[#6379bb] border-b border-b-solid border-[var(--el-border-color-light)] mb-5 mt-0' 'pb-[5px] font-sans leading-[1.1] font-medium text-base text-[#6379bb] border-b border-b-solid border-[var(--el-border-color-light)] mb-5 mt-0'
}, },
hmrTopLevelAwait: false, // unocss默认是true低版本浏览器是不支持的启动后会报错 hmrTopLevelAwait: false // unocss默认是true低版本浏览器是不支持的启动后会报错
}); });
}; };

View File

@ -1,5 +0,0 @@
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
export default () => {
return VueSetupExtend();
};