mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-11-14 04:33:41 +08:00
Merge branch 'main' into example
This commit is contained in:
@@ -210,6 +210,10 @@ export function useEcharts<T extends ECOption>(optionsFactory: () => T, hooks: C
|
||||
|
||||
// render chart
|
||||
await render();
|
||||
|
||||
if (chart) {
|
||||
await onUpdated?.(chart);
|
||||
}
|
||||
}
|
||||
|
||||
scope.run(() => {
|
||||
|
||||
@@ -38,7 +38,7 @@ const { isFullscreen, toggle } = useFullscreen();
|
||||
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
|
||||
</div>
|
||||
<div class="h-full flex-y-center justify-end">
|
||||
<GlobalSearch />
|
||||
<GlobalSearch v-if="themeStore.header.globalSearch.visible" />
|
||||
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
||||
<LangSwitch
|
||||
v-if="themeStore.header.multilingual.visible"
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useElementBounding } from '@vueuse/core';
|
||||
import { PageTab } from '@sa/materials';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import { useRouteStore } from '@/store/modules/route';
|
||||
import { useTabStore } from '@/store/modules/tab';
|
||||
import { isPC } from '@/utils/agent';
|
||||
import BetterScroll from '@/components/custom/better-scroll.vue';
|
||||
@@ -18,7 +17,6 @@ defineOptions({
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const routeStore = useRouteStore();
|
||||
const tabStore = useTabStore();
|
||||
|
||||
const bsWrapper = ref<HTMLElement>();
|
||||
@@ -82,12 +80,8 @@ function getContextMenuDisabledKeys(tabId: string) {
|
||||
return disabledKeys;
|
||||
}
|
||||
|
||||
async function handleCloseTab(tab: App.Global.Tab) {
|
||||
await tabStore.removeTab(tab.id);
|
||||
|
||||
if (themeStore.resetCacheStrategy === 'close') {
|
||||
routeStore.resetRouteCache(tab.routeKey);
|
||||
}
|
||||
function handleCloseTab(tab: App.Global.Tab) {
|
||||
tabStore.removeTab(tab.id);
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
|
||||
@@ -130,6 +130,9 @@ const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wra
|
||||
<SettingItem key="9" :label="$t('theme.header.multilingual.visible')">
|
||||
<NSwitch v-model:value="themeStore.header.multilingual.visible" />
|
||||
</SettingItem>
|
||||
<SettingItem key="10" :label="$t('theme.header.globalSearch.visible')">
|
||||
<NSwitch v-model:value="themeStore.header.globalSearch.visible" />
|
||||
</SettingItem>
|
||||
</TransitionGroup>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -112,6 +112,9 @@ const local: App.I18n.Schema = {
|
||||
},
|
||||
multilingual: {
|
||||
visible: 'Display multilingual button'
|
||||
},
|
||||
globalSearch: {
|
||||
visible: 'Display GlobalSearch button'
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
|
||||
@@ -112,6 +112,9 @@ const local: App.I18n.Schema = {
|
||||
},
|
||||
multilingual: {
|
||||
visible: '显示多语言按钮'
|
||||
},
|
||||
globalSearch: {
|
||||
visible: '显示全局搜索按钮'
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
|
||||
@@ -25,8 +25,8 @@ export function setupAppVersionNotification() {
|
||||
|
||||
const buildTime = await getHtmlBuildTime();
|
||||
|
||||
// If build time hasn't changed, no update is needed
|
||||
if (buildTime === BUILD_TIME) {
|
||||
// If failed to get build time or build time hasn't changed, no update is needed.
|
||||
if (!buildTime || buildTime === BUILD_TIME) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,16 +88,22 @@ export function setupAppVersionNotification() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getHtmlBuildTime() {
|
||||
async function getHtmlBuildTime(): Promise<string | null> {
|
||||
const baseUrl = import.meta.env.VITE_BASE_URL || '/';
|
||||
|
||||
const res = await fetch(`${baseUrl}index.html?time=${Date.now()}`);
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}index.html?time=${Date.now()}`);
|
||||
|
||||
const html = await res.text();
|
||||
if (!res.ok) {
|
||||
console.error('getHtmlBuildTime error:', res.status, res.statusText);
|
||||
return null;
|
||||
}
|
||||
|
||||
const match = html.match(/<meta name="buildTime" content="(.*)">/);
|
||||
|
||||
const buildTime = match?.[1] || '';
|
||||
|
||||
return buildTime;
|
||||
const html = await res.text();
|
||||
const match = html.match(/<meta name="buildTime" content="(.*)">/);
|
||||
return match?.[1] || null;
|
||||
} catch (error) {
|
||||
console.error('getHtmlBuildTime error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { addAPIProvider, disableCache } from '@iconify/vue';
|
||||
import { addAPIProvider } from '@iconify/vue';
|
||||
|
||||
/** Setup the iconify offline */
|
||||
export function setupIconifyOffline() {
|
||||
@@ -6,7 +6,5 @@ export function setupIconifyOffline() {
|
||||
|
||||
if (VITE_ICONIFY_URL) {
|
||||
addAPIProvider('', { resources: [VITE_ICONIFY_URL] });
|
||||
|
||||
disableCache('all');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { createAlovaRequest } from '@sa/alova';
|
||||
import { createAlovaMockAdapter } from '@sa/alova/mock';
|
||||
import adapterFetch from '@sa/alova/fetch';
|
||||
import { useAuthStore } from '@/store/modules/auth';
|
||||
import { $t } from '@/locales';
|
||||
import { getServiceBaseURL } from '@/utils/service';
|
||||
import { $t } from '@/locales';
|
||||
import featureUsers20241014 from '../mocks/feature-users-20241014';
|
||||
import { getAuthorization, handleRefreshToken, showErrorMsg } from './shared';
|
||||
import type { RequestInstanceState } from './type';
|
||||
|
||||
@@ -40,6 +40,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
|
||||
/** Reset auth store */
|
||||
async function resetStore() {
|
||||
recordUserId();
|
||||
|
||||
clearAuthStorage();
|
||||
|
||||
authStore.$reset();
|
||||
@@ -52,6 +54,41 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
routeStore.resetStore();
|
||||
}
|
||||
|
||||
/** Record the user ID of the previous login session Used to compare with the current user ID on next login */
|
||||
function recordUserId() {
|
||||
if (!userInfo.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store current user ID locally for next login comparison
|
||||
localStg.set('lastLoginUserId', userInfo.userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current login user is different from previous login user If different, clear all tabs
|
||||
*
|
||||
* @returns {boolean} Whether to clear all tabs
|
||||
*/
|
||||
function checkTabClear(): boolean {
|
||||
if (!userInfo.userId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const lastLoginUserId = localStg.get('lastLoginUserId');
|
||||
|
||||
// Clear all tabs if current user is different from previous user
|
||||
if (!lastLoginUserId || lastLoginUserId !== userInfo.userId) {
|
||||
localStg.remove('globalTabs');
|
||||
tabStore.clearTabs();
|
||||
|
||||
localStg.remove('lastLoginUserId');
|
||||
return true;
|
||||
}
|
||||
|
||||
localStg.remove('lastLoginUserId');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login
|
||||
*
|
||||
@@ -68,7 +105,15 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||
const pass = await loginByToken(loginToken);
|
||||
|
||||
if (pass) {
|
||||
await redirectFromLogin(redirect);
|
||||
// Check if the tab needs to be cleared
|
||||
const isClear = checkTabClear();
|
||||
let needRedirect = redirect;
|
||||
|
||||
if (isClear) {
|
||||
// If the tab needs to be cleared,it means we don't need to redirect.
|
||||
needRedirect = false;
|
||||
}
|
||||
await redirectFromLogin(needRedirect);
|
||||
|
||||
window.$notification?.success({
|
||||
title: $t('page.login.common.loginSuccess'),
|
||||
|
||||
@@ -98,13 +98,24 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
||||
const removeTabIndex = tabs.value.findIndex(tab => tab.id === tabId);
|
||||
if (removeTabIndex === -1) return;
|
||||
|
||||
const removedTabRouteKey = tabs.value[removeTabIndex].routeKey;
|
||||
const isRemoveActiveTab = activeTabId.value === tabId;
|
||||
const nextTab = tabs.value[removeTabIndex + 1] || homeTab.value;
|
||||
|
||||
// if remove the last tab, then switch to the second last tab
|
||||
const nextTab = tabs.value[removeTabIndex + 1] || tabs.value[removeTabIndex - 1] || homeTab.value;
|
||||
|
||||
// remove tab
|
||||
tabs.value.splice(removeTabIndex, 1);
|
||||
|
||||
// if current tab is removed, then switch to next tab
|
||||
if (isRemoveActiveTab && nextTab) {
|
||||
await switchRouteByTab(nextTab);
|
||||
}
|
||||
|
||||
// reset route cache if cache strategy is close
|
||||
if (themeStore.resetCacheStrategy === 'close') {
|
||||
routeStore.resetRouteCache(removedTabRouteKey);
|
||||
}
|
||||
}
|
||||
|
||||
/** remove active tab */
|
||||
@@ -131,9 +142,26 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
||||
*/
|
||||
async function clearTabs(excludes: string[] = []) {
|
||||
const remainTabIds = [...getFixedTabIds(tabs.value), ...excludes];
|
||||
const removedTabsIds = tabs.value.map(tab => tab.id).filter(id => !remainTabIds.includes(id));
|
||||
|
||||
// Identify tabs to be removed and collect their routeKeys if strategy is 'close'
|
||||
const tabsToRemove = tabs.value.filter(tab => !remainTabIds.includes(tab.id));
|
||||
const routeKeysToReset: RouteKey[] = [];
|
||||
|
||||
if (themeStore.resetCacheStrategy === 'close') {
|
||||
for (const tab of tabsToRemove) {
|
||||
routeKeysToReset.push(tab.routeKey);
|
||||
}
|
||||
}
|
||||
|
||||
const removedTabsIds = tabsToRemove.map(tab => tab.id);
|
||||
|
||||
// If no tabs are actually being removed based on excludes and fixed tabs, exit
|
||||
if (removedTabsIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRemoveActiveTab = removedTabsIds.includes(activeTabId.value);
|
||||
// filterTabsByIds returns tabs NOT in removedTabsIds, so these are the tabs that will remain
|
||||
const updatedTabs = filterTabsByIds(removedTabsIds, tabs.value);
|
||||
|
||||
function update() {
|
||||
@@ -142,13 +170,21 @@ export const useTabStore = defineStore(SetupStoreId.Tab, () => {
|
||||
|
||||
if (!isRemoveActiveTab) {
|
||||
update();
|
||||
return;
|
||||
} else {
|
||||
const activeTabCandidate = updatedTabs[updatedTabs.length - 1] || homeTab.value;
|
||||
|
||||
if (activeTabCandidate) {
|
||||
// Ensure there's a tab to switch to
|
||||
await switchRouteByTab(activeTabCandidate);
|
||||
}
|
||||
// Update the tabs array regardless of switch success or if a candidate was found
|
||||
update();
|
||||
}
|
||||
|
||||
const activeTab = updatedTabs[updatedTabs.length - 1] || homeTab.value;
|
||||
|
||||
await switchRouteByTab(activeTab);
|
||||
update();
|
||||
// After tabs are updated and route potentially switched, reset cache for removed tabs
|
||||
for (const routeKey of routeKeysToReset) {
|
||||
routeStore.resetRouteCache(routeKey);
|
||||
}
|
||||
}
|
||||
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
@@ -30,6 +30,9 @@ export const themeSettings: App.Theme.ThemeSetting = {
|
||||
},
|
||||
multilingual: {
|
||||
visible: true
|
||||
},
|
||||
globalSearch: {
|
||||
visible: true
|
||||
}
|
||||
},
|
||||
tab: {
|
||||
|
||||
7
src/typings/app.d.ts
vendored
7
src/typings/app.d.ts
vendored
@@ -58,6 +58,10 @@ declare namespace App {
|
||||
/** Whether to show the multilingual */
|
||||
visible: boolean;
|
||||
};
|
||||
globalSearch: {
|
||||
/** Whether to show the GlobalSearch */
|
||||
visible: boolean;
|
||||
};
|
||||
};
|
||||
/** Tab */
|
||||
tab: {
|
||||
@@ -377,6 +381,9 @@ declare namespace App {
|
||||
multilingual: {
|
||||
visible: string;
|
||||
};
|
||||
globalSearch: {
|
||||
visible: string;
|
||||
};
|
||||
};
|
||||
tab: {
|
||||
visible: string;
|
||||
|
||||
2
src/typings/common.d.ts
vendored
2
src/typings/common.d.ts
vendored
@@ -14,7 +14,7 @@ declare namespace CommonType {
|
||||
* @property value: The option value
|
||||
* @property label: The option label
|
||||
*/
|
||||
type Option<K = string> = { value: K; label: string };
|
||||
type Option<K = string, M = string> = { value: K; label: M };
|
||||
|
||||
type YesOrNo = 'Y' | 'N';
|
||||
|
||||
|
||||
2
src/typings/storage.d.ts
vendored
2
src/typings/storage.d.ts
vendored
@@ -37,5 +37,7 @@ declare namespace StorageType {
|
||||
layout: UnionKey.ThemeLayoutMode;
|
||||
siderCollapse: boolean;
|
||||
};
|
||||
/** The last login user id */
|
||||
lastLoginUserId: string;
|
||||
}
|
||||
}
|
||||
|
||||
2
src/typings/vite-env.d.ts
vendored
2
src/typings/vite-env.d.ts
vendored
@@ -108,6 +108,8 @@ declare namespace Env {
|
||||
readonly VITE_AUTOMATICALLY_DETECT_UPDATE?: CommonType.YesOrNo;
|
||||
/** show proxy url log in terminal */
|
||||
readonly VITE_PROXY_LOG?: CommonType.YesOrNo;
|
||||
/** The launch editor */
|
||||
readonly VITE_DEVTOOLS_LAUNCH_EDITOR?: import('vite-plugin-vue-devtools').VitePluginVueDevToolsOptions['launchEditor'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ export function transformRecordToOption<T extends Record<string, string>>(record
|
||||
return Object.entries(record).map(([value, label]) => ({
|
||||
value,
|
||||
label
|
||||
})) as CommonType.Option<keyof T>[];
|
||||
})) as CommonType.Option<keyof T, T[keyof T]>[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,10 +30,10 @@ export function transformRecordToOption<T extends Record<string, string>>(record
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
export function translateOptions(options: CommonType.Option<string>[]) {
|
||||
export function translateOptions(options: CommonType.Option<string, App.I18n.I18nKey>[]) {
|
||||
return options.map(option => ({
|
||||
...option,
|
||||
label: $t(option.label as App.I18n.I18nKey)
|
||||
label: $t(option.label)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { $t } from '@/locales';
|
||||
import pkg from '~/package.json';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { ref } from 'vue';
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { alova } from '@/service-alova/request';
|
||||
|
||||
const getLastTime = alova.Get<{ time: string }>('/mock/getLastTime', { cacheFor: null });
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { actionDelegationMiddleware, useCaptcha, useForm } from '@sa/alova/client';
|
||||
import { $t } from '@/locales';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
import { sendCaptcha, verifyCaptcha } from '@/service-alova/api';
|
||||
|
||||
defineOptions({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { ref } from 'vue';
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { alova } from '@/service-alova/request';
|
||||
|
||||
const getLastTime = alova.Get<{ time: string }>('/mock/getLastTime', { cacheFor: null });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { ref } from 'vue';
|
||||
import { actionDelegationMiddleware, useAutoRequest } from '@sa/alova/client';
|
||||
import { alova } from '@/service-alova/request';
|
||||
|
||||
const getLastTime = alova.Get<{ time: string }>('/mock/getLastTime', { cacheFor: null });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TableColumnCheck } from '@sa/hooks';
|
||||
import { computed, ref } from 'vue';
|
||||
import type { DataTableBaseColumn, DataTableColumn } from 'naive-ui';
|
||||
import type { TableColumnCheck } from '@sa/hooks';
|
||||
import { $t } from '@/locales';
|
||||
import type { AlovaGenerics, Method } from '~/packages/alova/src';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import type { Ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { usePagination } from '@sa/alova/client';
|
||||
import { reactive } from 'vue';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { batchDeleteUser, deleteUser, fetchGetUserList } from '@/service-alova/api';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import useCheckedColumns from './hooks/use-checked-columns';
|
||||
import useTableOperate from './hooks/use-table-operate';
|
||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue';
|
||||
import { useForm, useWatcher } from '@sa/alova/client';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import type { UserModel } from '@/service-alova/api';
|
||||
import { addUser, fetchGetAllRoles, updateUser } from '@/service-alova/api';
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserOperateDrawer'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserSearch'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@/locales';
|
||||
import { fetchCustomBackendError } from '@/service/api';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
async function logout() {
|
||||
await fetchCustomBackendError('8888', $t('request.logoutMsg'));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useTabStore } from '@/store/modules/tab';
|
||||
import { useRouterPush } from '@/hooks/common/router';
|
||||
import { $t } from '@/locales';
|
||||
import { useTabStore } from '@/store/modules/tab';
|
||||
|
||||
const tabStore = useTabStore();
|
||||
const { routerPushByKey } = useRouterPush();
|
||||
|
||||
@@ -3,12 +3,12 @@ import { ref } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { yesOrNoRecord } from '@/constants/common';
|
||||
import { enableStatusRecord, menuTypeRecord } from '@/constants/business';
|
||||
import { fetchGetAllPages, fetchGetMenuList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import { yesOrNoRecord } from '@/constants/common';
|
||||
import { enableStatusRecord, menuTypeRecord } from '@/constants/business';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
import MenuOperateModal, { type OperateType } from './modules/menu-operate-modal.vue';
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script setup lang="tsx">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import type { SelectOption } from 'naive-ui';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusOptions, menuIconTypeOptions, menuTypeOptions } from '@/constants/business';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
import { getLocalIcons } from '@/utils/icon';
|
||||
import { fetchGetAllRoles } from '@/service/api';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { getLocalIcons } from '@/utils/icon';
|
||||
import { $t } from '@/locales';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
import {
|
||||
getLayoutAndPage,
|
||||
getPathParamFromRoutePath,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { enableStatusRecord } from '@/constants/business';
|
||||
import { fetchGetRoleList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusRecord } from '@/constants/business';
|
||||
import RoleOperateDrawer from './modules/role-operate-drawer.vue';
|
||||
import RoleSearch from './modules/role-search.vue';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, shallowRef, watch } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { fetchGetAllPages, fetchGetMenuTree } from '@/service/api';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'MenuAuthModal'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { enableStatusOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusOptions } from '@/constants/business';
|
||||
import MenuAuthModal from './menu-auth-modal.vue';
|
||||
import ButtonAuthModal from './button-auth-modal.vue';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusOptions } from '@/constants/business';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'RoleSearch'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { $t } from '@/locales';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||
import UserSearch from './modules/user-search.vue';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { fetchGetAllRoles } from '@/service/api';
|
||||
import { $t } from '@/locales';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { fetchGetAllRoles } from '@/service/api';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserOperateDrawer'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { $t } from '@/locales';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserSearch'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
import JsBarcode from 'jsbarcode';
|
||||
import type { Options } from 'jsbarcode';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const text = 'Soybean';
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script setup lang="tsx">
|
||||
import { NButton, NTag } from 'naive-ui';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable } from '@/hooks/common/table';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
Reference in New Issue
Block a user