mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
Compare commits
8 Commits
flow
...
8aeb73627a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8aeb73627a | |||
| 3f148a4e62 | |||
| 34ab7d5da2 | |||
| 513dc31eaa | |||
| dc2fbbd556 | |||
| 56fd5434ca | |||
| ad207255bb | |||
| 3146c039f0 |
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -31,7 +31,8 @@
|
|||||||
"vue.server.hybridMode": true,
|
"vue.server.hybridMode": true,
|
||||||
"files.exclude": { "/docs": true },
|
"files.exclude": { "/docs": true },
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"/docs": true
|
"/docs": true,
|
||||||
|
"**/dist/**": true
|
||||||
},
|
},
|
||||||
"cSpell.words": ["Axios", "tinymce"]
|
"cSpell.words": ["Axios", "tinymce"]
|
||||||
}
|
}
|
||||||
|
|||||||
681
pnpm-lock.yaml
generated
681
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -4,5 +4,6 @@ export enum SetupStoreId {
|
|||||||
Auth = 'auth-store',
|
Auth = 'auth-store',
|
||||||
Route = 'route-store',
|
Route = 'route-store',
|
||||||
Tab = 'tab-store',
|
Tab = 'tab-store',
|
||||||
Notice = 'notice-store'
|
Notice = 'notice-store',
|
||||||
|
Dict = 'dict-store'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { localStg } from '@/utils/storage';
|
|||||||
import { SetupStoreId } from '@/enum';
|
import { SetupStoreId } from '@/enum';
|
||||||
import { useRouteStore } from '../route';
|
import { useRouteStore } from '../route';
|
||||||
import { useTabStore } from '../tab';
|
import { useTabStore } from '../tab';
|
||||||
|
import useNoticeStore from '../notice';
|
||||||
import { clearAuthStorage, getToken } from './shared';
|
import { clearAuthStorage, getToken } from './shared';
|
||||||
|
|
||||||
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||||
@ -15,6 +16,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
const tabStore = useTabStore();
|
const tabStore = useTabStore();
|
||||||
|
const noticeStore = useNoticeStore();
|
||||||
const { toLogin, redirectFromLogin } = useRouterPush(false);
|
const { toLogin, redirectFromLogin } = useRouterPush(false);
|
||||||
const { loading: loginLoading, startLoading, endLoading } = useLoading();
|
const { loading: loginLoading, startLoading, endLoading } = useLoading();
|
||||||
|
|
||||||
@ -48,6 +50,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
await toLogin();
|
await toLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noticeStore.clearNotice();
|
||||||
tabStore.cacheTabs();
|
tabStore.cacheTabs();
|
||||||
routeStore.resetStore();
|
routeStore.resetStore();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
import { SetupStoreId } from '@/enum';
|
||||||
|
|
||||||
export const useDictStore = defineStore('dict', () => {
|
export const useDictStore = defineStore(SetupStoreId.Dict, () => {
|
||||||
const dictData = ref<{ [key: string]: Api.System.DictData[] }>({});
|
const dictData = ref<{ [key: string]: Api.System.DictData[] }>({});
|
||||||
|
|
||||||
const getDict = (key: string) => {
|
const getDict = (key: string) => {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import { useEventSource } from '@vueuse/core';
|
import { useEventSource } from '@vueuse/core';
|
||||||
import useNoticeStore from '@/store/modules/notice';
|
import useNoticeStore from '@/store/modules/notice';
|
||||||
|
import { $t } from '@/locales';
|
||||||
import { localStg } from './storage';
|
import { localStg } from './storage';
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
@ -34,9 +35,14 @@ export const initSSE = (url: any) => {
|
|||||||
read: false,
|
read: false,
|
||||||
time: new Date().toLocaleString()
|
time: new Date().toLocaleString()
|
||||||
});
|
});
|
||||||
|
let content = data.value;
|
||||||
|
const noticeType = content.match(/\[dict\.(.*?)\]/)?.[1];
|
||||||
|
if (noticeType) {
|
||||||
|
content = content.replace(`dict.${noticeType}`, $t(`dict.${noticeType}` as App.I18n.I18nKey));
|
||||||
|
}
|
||||||
window.$notification?.create({
|
window.$notification?.create({
|
||||||
title: '消息',
|
title: '消息',
|
||||||
content: data.value,
|
content,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
duration: 3000
|
duration: 3000
|
||||||
});
|
});
|
||||||
|
|||||||
@ -39,8 +39,7 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- Copyright By https://github.com/Daymychen/art-design-pro/blob/main/src/components/core/views/login/LoginLeftView.vue -->
|
<div class="scroll box-border size-full flex">
|
||||||
<div class="box-border size-full flex">
|
|
||||||
<div class="relative box-border hidden h-full w-65vw overflow-hidden bg-primary-50 xl:block dark:bg-primary-900">
|
<div class="relative box-border hidden h-full w-65vw overflow-hidden bg-primary-50 xl:block dark:bg-primary-900">
|
||||||
<div class="relative z-100 flex items-center pl-30px pt-30px">
|
<div class="relative z-100 flex items-center pl-30px pt-30px">
|
||||||
<SystemLogo class="text-32px text-primary" />
|
<SystemLogo class="text-32px text-primary" />
|
||||||
@ -55,13 +54,13 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
</div>
|
</div>
|
||||||
<WaveBg />
|
<WaveBg />
|
||||||
</div>
|
</div>
|
||||||
<header class="relative h-full flex-1 xl:m-auto sm:!w-full">
|
<div class="relative h-full flex-1 xl:m-auto sm:!w-full">
|
||||||
<div class="relative z-100 block flex items-center pl-30px pt-30px xl:hidden">
|
<header class="flex-y-center justify-between px-30px pt-30px xl:justify-end">
|
||||||
<SystemLogo class="text-32px text-primary" />
|
<div class="relative z-100 block flex items-center xl:hidden">
|
||||||
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
<SystemLogo class="text-32px text-primary" />
|
||||||
</div>
|
<h3 class="ml-10px text-20px font-400">{{ $t('system.title') }}</h3>
|
||||||
<div class="position-fixed right-30px top-24px z-100 flex items-center justify-end">
|
</div>
|
||||||
<div class="ml-15px inline-block flex cursor-pointer select-none p-5px">
|
<div class="flex items-center justify-end">
|
||||||
<ThemeSchemaSwitch
|
<ThemeSchemaSwitch
|
||||||
:theme-schema="themeStore.themeScheme"
|
:theme-schema="themeStore.themeScheme"
|
||||||
:show-tooltip="false"
|
:show-tooltip="false"
|
||||||
@ -77,14 +76,30 @@ const activeModule = computed(() => moduleMap[props.module || 'pwd-login']);
|
|||||||
@change-lang="appStore.changeLocale"
|
@change-lang="appStore.changeLocale"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
<main class="absolute inset-0 m-auto h-630px max-w-450px w-full overflow-hidden rounded-5px bg-cover px-24px">
|
<main class="mt-10% max-w-450px w-full rounded-5px bg-cover px-24px xl:absolute xl:m-auto">
|
||||||
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
||||||
<component :is="activeModule.component" />
|
<component :is="activeModule.component" />
|
||||||
</Transition>
|
</Transition>
|
||||||
</main>
|
</main>
|
||||||
</header>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.scroll {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -38,6 +38,8 @@ const visible = defineModel<boolean>('visible', {
|
|||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const defaultIcon = import.meta.env.VITE_MENU_ICON;
|
||||||
|
|
||||||
const iconType = ref<Api.System.IconType>('1');
|
const iconType = ref<Api.System.IconType>('1');
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||||
const { createRequiredRule, createNumberRequiredRule } = useFormRules();
|
const { createRequiredRule, createNumberRequiredRule } = useFormRules();
|
||||||
@ -69,7 +71,7 @@ function createDefaultModel(): Model {
|
|||||||
visible: '0',
|
visible: '0',
|
||||||
status: '0',
|
status: '0',
|
||||||
perms: '',
|
perms: '',
|
||||||
icon: undefined,
|
icon: defaultIcon,
|
||||||
remark: ''
|
remark: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -118,6 +120,7 @@ const localIconOptions = localIcons.map<SelectOption>(item => ({
|
|||||||
|
|
||||||
function handleInitModel() {
|
function handleInitModel() {
|
||||||
queryList.value = [];
|
queryList.value = [];
|
||||||
|
iconType.value = '1';
|
||||||
Object.assign(model, createDefaultModel());
|
Object.assign(model, createDefaultModel());
|
||||||
|
|
||||||
if (props.operateType === 'edit' && props.rowData) {
|
if (props.operateType === 'edit' && props.rowData) {
|
||||||
@ -208,7 +211,7 @@ async function handleSubmit() {
|
|||||||
visible: menuVisible,
|
visible: menuVisible,
|
||||||
status,
|
status,
|
||||||
perms,
|
perms,
|
||||||
icon,
|
icon: icon || defaultIcon,
|
||||||
component: processComponent(component),
|
component: processComponent(component),
|
||||||
remark
|
remark
|
||||||
};
|
};
|
||||||
|
|||||||
@ -323,11 +323,11 @@ function handleResetSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node) {
|
:deep(.n-tree-node) {
|
||||||
height: 33px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher) {
|
:deep(.n-tree-node-switcher) {
|
||||||
height: 33px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher__icon) {
|
:deep(.n-tree-node-switcher__icon) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { NButton, NDivider } from 'naive-ui';
|
import { NAvatar, NButton, NDivider, NEllipsis } from 'naive-ui';
|
||||||
import { useBoolean, useLoading } from '@sa/hooks';
|
import { useBoolean, useLoading } from '@sa/hooks';
|
||||||
import { jsonClone } from '@sa/utils';
|
import { jsonClone } from '@sa/utils';
|
||||||
import { fetchBatchDeleteUser, fetchGetDeptTree, fetchGetUserList, fetchUpdateUserStatus } from '@/service/api/system';
|
import { fetchBatchDeleteUser, fetchGetDeptTree, fetchGetUserList, fetchUpdateUserStatus } from '@/service/api/system';
|
||||||
@ -12,6 +12,7 @@ import { useDownload } from '@/hooks/business/download';
|
|||||||
import ButtonIcon from '@/components/custom/button-icon.vue';
|
import ButtonIcon from '@/components/custom/button-icon.vue';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import StatusSwitch from '@/components/custom/status-switch.vue';
|
import StatusSwitch from '@/components/custom/status-switch.vue';
|
||||||
|
import DictTag from '@/components/custom/dict-tag.vue';
|
||||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||||
import UserImportModal from './modules/user-import-modal.vue';
|
import UserImportModal from './modules/user-import-modal.vue';
|
||||||
import UserPasswordDrawer from './modules/user-password-drawer.vue';
|
import UserPasswordDrawer from './modules/user-password-drawer.vue';
|
||||||
@ -65,41 +66,64 @@ const {
|
|||||||
key: 'index',
|
key: 'index',
|
||||||
title: $t('common.index'),
|
title: $t('common.index'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 64
|
width: 48
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'userName',
|
key: 'userName',
|
||||||
title: $t('page.system.user.userName'),
|
title: $t('page.system.user.userName'),
|
||||||
align: 'center',
|
align: 'left',
|
||||||
minWidth: 120,
|
width: 200,
|
||||||
ellipsis: true
|
ellipsis: true,
|
||||||
|
render: row => {
|
||||||
|
return (
|
||||||
|
<div class="flex items-center justify-center gap-2">
|
||||||
|
<NAvatar src={row.avatar} class="bg-primary">
|
||||||
|
{row.avatar ? undefined : row.nickName.charAt(0)}
|
||||||
|
</NAvatar>
|
||||||
|
<div class="max-w-160px flex flex-col">
|
||||||
|
<NEllipsis>{row.userName}</NEllipsis>
|
||||||
|
<NEllipsis>{row.nickName}</NEllipsis>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'nickName',
|
key: 'sex',
|
||||||
title: $t('page.system.user.nickName'),
|
title: $t('page.system.user.sex'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120,
|
width: 80,
|
||||||
ellipsis: true
|
ellipsis: true,
|
||||||
|
render(row) {
|
||||||
|
return <DictTag value={row.sex} dictCode="sys_user_sex" />;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'deptName',
|
key: 'deptName',
|
||||||
title: $t('page.system.user.deptName'),
|
title: $t('page.system.user.deptName'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120,
|
width: 120,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
title: $t('page.system.user.email'),
|
||||||
|
align: 'center',
|
||||||
|
width: 120,
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'phonenumber',
|
key: 'phonenumber',
|
||||||
title: $t('page.system.user.phonenumber'),
|
title: $t('page.system.user.phonenumber'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120,
|
width: 120,
|
||||||
ellipsis: true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'status',
|
key: 'status',
|
||||||
title: $t('page.system.user.status'),
|
title: $t('page.system.user.status'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 80,
|
width: 80,
|
||||||
render(row) {
|
render(row) {
|
||||||
return (
|
return (
|
||||||
<StatusSwitch
|
<StatusSwitch
|
||||||
@ -115,7 +139,7 @@ const {
|
|||||||
key: 'createTime',
|
key: 'createTime',
|
||||||
title: $t('page.system.user.createTime'),
|
title: $t('page.system.user.createTime'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
minWidth: 120
|
width: 120
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'operate',
|
key: 'operate',
|
||||||
@ -341,7 +365,7 @@ function handleResetSearch() {
|
|||||||
:data="data"
|
:data="data"
|
||||||
size="small"
|
size="small"
|
||||||
:flex-height="!appStore.isMobile"
|
:flex-height="!appStore.isMobile"
|
||||||
:scroll-x="962"
|
:scroll-x="1200"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
remote
|
remote
|
||||||
:row-key="row => row.userId"
|
:row-key="row => row.userId"
|
||||||
@ -391,11 +415,11 @@ function handleResetSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node) {
|
:deep(.n-tree-node) {
|
||||||
height: 25px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher) {
|
:deep(.n-tree-node-switcher) {
|
||||||
height: 25px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.n-tree-node-switcher__icon) {
|
:deep(.n-tree-node-switcher__icon) {
|
||||||
|
|||||||
Reference in New Issue
Block a user