feat: add docker shell
parent
d733987042
commit
38d58394e3
|
@ -0,0 +1,5 @@
|
|||
node_modules
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
dist
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
// editor
|
||||
"editor.tabSize": 2,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.cursorBlinking": "expand",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.fontFamily": "Input Mono, FiraCode-Retina, monospace",
|
||||
"editor.fontLigatures": true,
|
||||
|
@ -20,9 +22,17 @@
|
|||
"editor.cursorSmoothCaretAnimation": "on",
|
||||
"editor.guides.bracketPairs": "active",
|
||||
"editor.inlineSuggest.enabled": true,
|
||||
"editor.suggestSelection": "first",
|
||||
"editor.suggestSelection": "recentlyUsedByPrefix",
|
||||
"editor.acceptSuggestionOnEnter": "smart",
|
||||
"editor.suggest.snippetsPreventQuickSuggestions": false,
|
||||
"editor.stickyScroll.enabled": true,
|
||||
"editor.hover.sticky": true,
|
||||
"editor.suggest.insertMode": "replace",
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.autoClosingBrackets": "beforeWhitespace",
|
||||
"editor.autoClosingDelete": "always",
|
||||
"editor.autoClosingOvertype": "always",
|
||||
"editor.autoClosingQuotes": "beforeWhitespace",
|
||||
"editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
|
@ -38,6 +48,7 @@
|
|||
"terminal.integrated.persistentSessionReviveProcess": "never",
|
||||
"terminal.integrated.tabs.enabled": true,
|
||||
"terminal.integrated.scrollback": 10000,
|
||||
"terminal.integrated.stickyScroll.enabled": true,
|
||||
|
||||
// files
|
||||
"files.eol": "\n",
|
||||
|
@ -46,8 +57,8 @@
|
|||
"files.associations": {
|
||||
"*.ejs": "html",
|
||||
"*.art": "html",
|
||||
"**/tsconfig.json": "jsonc"
|
||||
// "*.json": "jsonc"
|
||||
"**/tsconfig.json": "jsonc",
|
||||
"*.json": "jsonc"
|
||||
},
|
||||
|
||||
"files.exclude": {
|
||||
|
@ -77,6 +88,7 @@
|
|||
},
|
||||
|
||||
// search
|
||||
"search.searchEditor.singleClickBehaviour": "peekDefinition",
|
||||
"search.followSymlinks": false,
|
||||
// 在使用搜索功能时,将这些文件夹/文件排除在外
|
||||
"search.exclude": {
|
||||
|
@ -124,6 +136,10 @@
|
|||
"stylelint.packageManager": "pnpm",
|
||||
"stylelint.validate": ["css", "less", "postcss", "scss", "vue", "sass"],
|
||||
|
||||
"typescript.inlayHints.enumMemberValues.enabled": true,
|
||||
"typescript.preferences.preferTypeOnlyAutoImports": true,
|
||||
"typescript.preferences.includePackageJsonAutoImports": "on",
|
||||
|
||||
// Enable the ESlint flat config support
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"eslint.validate": [
|
||||
|
@ -179,6 +195,7 @@
|
|||
"*.env": "$(capture).env.*",
|
||||
"README.md": "README*,CHANGELOG*,LICENSE,CNAME",
|
||||
"package.json": "pnpm-lock.yaml,pnpm-workspace.yaml,.gitattributes,.gitignore,.gitpod.yml,.npmrc,.browserslistrc,.node-version,.git*,.tazerc.json",
|
||||
"Dockerfile": "Dockerfile,.docker*,docker-entrypoint.sh,build-local-docker*",
|
||||
"eslint.config.mjs": ".eslintignore,.prettierignore,.stylelintignore,.commitlintrc.*,.prettierrc.*,stylelint.config.*,.lintstagedrc.mjs,.ls-lint*",
|
||||
"tailwind.config.mjs": "postcss.*"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
FROM node:20-slim AS builder
|
||||
|
||||
# --max-old-space-size
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
ENV NODE_OPTIONS=--max-old-space-size=8192
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
RUN corepack enable
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# copy package.json and pnpm-lock.yaml to workspace
|
||||
COPY . /app
|
||||
|
||||
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
|
||||
RUN pnpm run build
|
||||
|
||||
RUN echo "Builder Success 🎉"
|
||||
|
||||
FROM nginx:stable-alpine as production
|
||||
|
||||
COPY --from=builder /app/apps/antd-view/dist /usr/share/nginx/html
|
||||
|
||||
COPY ./deploy/nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
# start nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
|
@ -0,0 +1,33 @@
|
|||
import '@vben/styles';
|
||||
|
||||
import { setupI18n } from '@vben/locales';
|
||||
import { preference } from '@vben/preference';
|
||||
import { setupStore } from '@vben/stores';
|
||||
import { createApp } from 'vue';
|
||||
|
||||
import App from './app.vue';
|
||||
import { router } from './router';
|
||||
|
||||
async function bootstrap(namespace: string, env: string) {
|
||||
const app = createApp(App);
|
||||
|
||||
// 国际化 i18n 配置
|
||||
await setupI18n(app, { defaultLocale: preference.locale });
|
||||
|
||||
// 配置 pinia-store
|
||||
await setupStore(app, { env, namespace });
|
||||
|
||||
// 配置路由及路由守卫
|
||||
app.use(router);
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
// production mock server
|
||||
if (import.meta.env.PROD) {
|
||||
import('./mock-prod-server').then(({ setupProdMockServer }) => {
|
||||
setupProdMockServer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { bootstrap };
|
|
@ -2,12 +2,7 @@
|
|||
import type { NotificationItem } from '@vben/common-ui';
|
||||
|
||||
import { Notification, UserDropdown } from '@vben/common-ui';
|
||||
import {
|
||||
IcRoundCreditScore,
|
||||
IcRoundSettingsSuggest,
|
||||
MdiDriveDocument,
|
||||
MdiGithub,
|
||||
} from '@vben/icons';
|
||||
import { IcRoundCreditScore, MdiDriveDocument, MdiGithub } from '@vben/icons';
|
||||
import { BasicLayout } from '@vben/layouts';
|
||||
import { $t } from '@vben/locales';
|
||||
import { preference } from '@vben/preference';
|
||||
|
@ -79,15 +74,6 @@ const menus = computed(() => [
|
|||
icon: IcRoundCreditScore,
|
||||
text: $t('widgets.qa'),
|
||||
},
|
||||
{
|
||||
handler: () => {
|
||||
// openWindow('https://github.com/vbenjs/vue-vben-admin', {
|
||||
// target: '_blank',
|
||||
// });
|
||||
},
|
||||
icon: IcRoundSettingsSuggest,
|
||||
text: $t('widgets.setting'),
|
||||
},
|
||||
]);
|
||||
|
||||
const accessStore = useAccessStore();
|
||||
|
|
|
@ -1,40 +1,22 @@
|
|||
import '@vben/styles';
|
||||
import { setupPreference } from '@vben/preference';
|
||||
|
||||
import { setupI18n } from '@vben/locales';
|
||||
import { preference, setupPreference } from '@vben/preference';
|
||||
import { setupStore } from '@vben/stores';
|
||||
import { createApp } from 'vue';
|
||||
|
||||
import App from './app.vue';
|
||||
import { overridesPreference } from './preference';
|
||||
import { router } from './router';
|
||||
|
||||
async function bootstrap(cachePrefix: string) {
|
||||
// app偏好设置
|
||||
/**
|
||||
* 应用初始化完成之后再进行页面加载渲染
|
||||
*/
|
||||
async function initApplication() {
|
||||
const namespace = 'antd-view';
|
||||
const env = import.meta.env.PROD ? 'prod' : 'dev';
|
||||
|
||||
// app偏好设置初始化
|
||||
await setupPreference({
|
||||
cachePrefix,
|
||||
env,
|
||||
namespace,
|
||||
overrides: overridesPreference,
|
||||
});
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
// 国际化 i18n 配置
|
||||
await setupI18n(app, { defaultLocale: preference.locale });
|
||||
|
||||
// 配置 pinia-store
|
||||
await setupStore(app, { cachePrefix });
|
||||
|
||||
// 配置路由及路由守卫
|
||||
app.use(router);
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
// production mock server
|
||||
if (import.meta.env.PROD) {
|
||||
import('./mock-prod-server').then(({ setupProdMockServer }) => {
|
||||
setupProdMockServer();
|
||||
});
|
||||
}
|
||||
import('./bootstrap').then((m) => m.bootstrap(namespace, env));
|
||||
}
|
||||
|
||||
bootstrap('vben-admin-pro-antd');
|
||||
initApplication();
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log
|
||||
ERROR=""
|
||||
IMAGE_NAME="vben-admin-pro-local"
|
||||
|
||||
function stop_and_remove_container() {
|
||||
# Stop and remove the existing container
|
||||
docker stop ${IMAGE_NAME} >/dev/null 2>&1
|
||||
docker rm ${IMAGE_NAME} >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function remove_image() {
|
||||
# Remove the existing image
|
||||
docker rmi vben-admin-pro >/dev/null 2>&1
|
||||
}
|
||||
|
||||
function install_dependencies() {
|
||||
# Install all dependencies
|
||||
cd ${SCRIPT_DIR}
|
||||
pnpm install || ERROR="install_dependencies failed"
|
||||
}
|
||||
|
||||
function build_image() {
|
||||
# build docker
|
||||
docker build . -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed"
|
||||
}
|
||||
|
||||
function log_message() {
|
||||
if [[ ${ERROR} != "" ]];
|
||||
then
|
||||
>&2 echo "build failed, Please check build-local-docker-image.log for more details"
|
||||
>&2 echo "ERROR: ${ERROR}"
|
||||
exit 1
|
||||
else
|
||||
echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container"
|
||||
echo ""
|
||||
echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE}
|
||||
stop_and_remove_container
|
||||
remove_image
|
||||
|
||||
echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
|
||||
install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
|
||||
|
||||
if [[ ${ERROR} == "" ]]; then
|
||||
echo "Info: Building docker image" | tee -a ${LOG_FILE}
|
||||
build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
|
||||
fi
|
||||
|
||||
log_message | tee -a ${LOG_FILE}
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
#user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
#error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
types {
|
||||
application/javascript js mjs;
|
||||
text/css css;
|
||||
text/html html;
|
||||
}
|
||||
|
||||
sendfile on;
|
||||
# tcp_nopush on;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
# keepalive_timeout 65;
|
||||
|
||||
# gzip on;
|
||||
# gzip_buffers 32 16k;
|
||||
# gzip_comp_level 6;
|
||||
# gzip_min_length 1k;
|
||||
# gzip_static on;
|
||||
# gzip_types text/plain
|
||||
# text/css
|
||||
# application/javascript
|
||||
# application/json
|
||||
# application/x-javascript
|
||||
# text/xml
|
||||
# application/xml
|
||||
# application/xml+rss
|
||||
# text/javascript; #设置压缩的文件类型
|
||||
# gzip_vary on;
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
index index.html;
|
||||
# Enable CORS
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Max-Age' 1728000;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# stream { # stream 模块配置和 http 模块在相同级别
|
||||
# upstream redis {
|
||||
# server 127.0.0.1:6379 max_fails=3 fail_timeout=30s;
|
||||
# }
|
||||
# server {
|
||||
# listen 16379;
|
||||
# proxy_connect_timeout 1s;
|
||||
# proxy_timeout 3s;
|
||||
# proxy_pass redis;
|
||||
# }
|
||||
# }
|
|
@ -43,7 +43,7 @@
|
|||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-i": "^2.29.1",
|
||||
"eslint-plugin-jsdoc": "^48.2.5",
|
||||
"eslint-plugin-jsdoc": "^48.2.6",
|
||||
"eslint-plugin-jsonc": "^2.15.1",
|
||||
"eslint-plugin-n": "^17.7.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
|
|
|
@ -47,14 +47,14 @@
|
|||
"./*": "./*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/json": "^2.2.212",
|
||||
"@iconify/json": "^2.2.213",
|
||||
"@iconify/tailwind": "^1.1.1",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"cssnano": "^7.0.1",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-antd-fixes": "^0.2.0",
|
||||
"postcss-preset-env": "^9.5.13",
|
||||
"postcss-preset-env": "^9.5.14",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
|
|
|
@ -45,7 +45,8 @@
|
|||
"format": "vsh lint --format",
|
||||
"prepare": "is-ci || husky",
|
||||
"reinstall": "pnpm clean --del-lock && pnpm bootstrap",
|
||||
"test": "vitest"
|
||||
"test": "vitest",
|
||||
"build:docker": "./build-local-docker-image.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.3",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# @vben-core
|
||||
|
||||
系统一些比较基础的SDK和UI组件库,请勿将任何业务逻辑和业务包放在这里。
|
|
@ -91,6 +91,8 @@ interface Preference {
|
|||
pageTransitionEnable: boolean;
|
||||
/** 是否开启半深色菜单(只在theme='light'时生效) */
|
||||
semiDarkMenu: boolean;
|
||||
/** 是否显示偏好设置 */
|
||||
showPreference: boolean;
|
||||
/** 侧边栏是否折叠 */
|
||||
sideCollapse: boolean;
|
||||
/** 侧边栏折叠时,是否显示title */
|
||||
|
|
|
@ -80,6 +80,33 @@ type MaybeReadonlyRef<T> = (() => T) | ComputedRef<T>;
|
|||
*/
|
||||
type MaybeComputedRef<T> = MaybeReadonlyRef<T> | MaybeRef<T>;
|
||||
|
||||
type Merge<O extends object, T extends object> = {
|
||||
[K in keyof O | keyof T]: K extends keyof T
|
||||
? T[K]
|
||||
: K extends keyof O
|
||||
? O[K]
|
||||
: never;
|
||||
};
|
||||
|
||||
/**
|
||||
* T = [
|
||||
* { name: string; age: number; },
|
||||
* { sex: 'male' | 'female'; age: string }
|
||||
* ]
|
||||
* =>
|
||||
* MergeAll<T> = {
|
||||
* name: string;
|
||||
* sex: 'male' | 'female';
|
||||
* age: string
|
||||
* }
|
||||
*/
|
||||
type MergeAll<
|
||||
T extends object[],
|
||||
R extends object = Record<string, any>,
|
||||
> = T extends [infer F extends object, ...infer Rest extends object[]]
|
||||
? MergeAll<Rest, Merge<R, F>>
|
||||
: R;
|
||||
|
||||
export {
|
||||
type AnyFunction,
|
||||
type AnyNormalFunction,
|
||||
|
@ -89,6 +116,8 @@ export {
|
|||
type IntervalHandle,
|
||||
type MaybeComputedRef,
|
||||
type MaybeReadonlyRef,
|
||||
type Merge,
|
||||
type MergeAll,
|
||||
type NonNullable,
|
||||
type Nullable,
|
||||
type ReadonlyRecordable,
|
||||
|
|
|
@ -22,6 +22,6 @@ const delegatedProps = computed(() => {
|
|||
<template>
|
||||
<DropdownMenuSeparator
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('bg-muted -mx-1 my-1 h-px', props.class)"
|
||||
:class="cn('bg-border -mx-1 my-1 h-px', props.class)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
import { $t } from '@vben/locales';
|
||||
import { preference, resetPreference, usePreference } from '@vben/preference';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import {
|
||||
Animation,
|
||||
|
@ -33,6 +33,7 @@ import {
|
|||
ThemeColor,
|
||||
} from './blocks';
|
||||
import Trigger from './trigger.vue';
|
||||
import { useOpenPreference } from './use-open-preference';
|
||||
|
||||
withDefaults(defineProps<{ colorPrimaryPresets: string[] }>(), {
|
||||
colorPrimaryPresets: () => [],
|
||||
|
@ -106,11 +107,7 @@ const showBreadcrumbConfig = computed(() => {
|
|||
);
|
||||
});
|
||||
|
||||
const openSheet = ref(false);
|
||||
|
||||
function handlerOpenSheet() {
|
||||
openSheet.value = true;
|
||||
}
|
||||
const { openPreference } = useOpenPreference();
|
||||
|
||||
async function handleCopy() {
|
||||
await copy(JSON.stringify(diffPreference.value, null, 2));
|
||||
|
@ -130,11 +127,12 @@ function handleReset() {
|
|||
<template>
|
||||
<div class="z-100 fixed right-0 top-1/3">
|
||||
<VbenSheet
|
||||
v-model:open="openPreference"
|
||||
:description="$t('preference.preferences-subtitle')"
|
||||
:title="$t('preference.preferences')"
|
||||
>
|
||||
<template #trigger>
|
||||
<Trigger @click="handlerOpenSheet" />
|
||||
<Trigger />
|
||||
</template>
|
||||
<template #extra>
|
||||
<VbenIconButton
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { ref } from 'vue';
|
||||
|
||||
const openPreference = ref(false);
|
||||
|
||||
function useOpenPreference() {
|
||||
function handleOpenPreference() {
|
||||
openPreference.value = true;
|
||||
}
|
||||
|
||||
return {
|
||||
handleOpenPreference,
|
||||
openPreference,
|
||||
};
|
||||
}
|
||||
|
||||
export { useOpenPreference };
|
|
@ -1,5 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { IcRoundLogout } from '@vben-core/iconify';
|
||||
import type { AnyFunction } from '@vben/types';
|
||||
|
||||
import { IcRoundLogout, IcRoundSettingsSuggest } from '@vben-core/iconify';
|
||||
import {
|
||||
Badge,
|
||||
DropdownMenu,
|
||||
|
@ -16,9 +18,11 @@ import {
|
|||
import type { Component } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import { AnyFunction } from '@vben/types';
|
||||
import { preference } from '@vben/preference';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { useOpenPreference } from '../preference/use-open-preference';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* 头像
|
||||
|
@ -59,6 +63,8 @@ const emit = defineEmits<{ logout: [] }>();
|
|||
const openPopover = ref(false);
|
||||
const openDialog = ref(false);
|
||||
|
||||
const { handleOpenPreference } = useOpenPreference();
|
||||
|
||||
function handleLogout() {
|
||||
// emit
|
||||
openDialog.value = true;
|
||||
|
@ -90,8 +96,8 @@ function handleSubmitLogout() {
|
|||
</div>
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="mr-2 min-w-[240px] p-0">
|
||||
<DropdownMenuLabel class="border-border flex items-center border-b p-3">
|
||||
<DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
|
||||
<DropdownMenuLabel class="flex items-center p-3">
|
||||
<VbenAvatar
|
||||
:alt="text"
|
||||
:src="avatar"
|
||||
|
@ -117,22 +123,28 @@ function handleSubmitLogout() {
|
|||
<DropdownMenuItem
|
||||
v-for="menu in menus"
|
||||
:key="menu.text"
|
||||
class="mx-1 rounded-sm py-2.5"
|
||||
class="lineh mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="menu.handler"
|
||||
>
|
||||
<VbenIcon :icon="menu.icon" class="mr-2 size-4" />
|
||||
<VbenIcon :icon="menu.icon" class="mr-2 size-5" />
|
||||
{{ menu.text }}
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem class="w-full p-0">
|
||||
<div
|
||||
class="border-border flex-center hover:bg-accent hover:text-accent-foreground h-10 w-full cursor-pointer border-t"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<IcRoundLogout class="mr-2" />
|
||||
{{ $t('common.logout') }}
|
||||
</div>
|
||||
<DropdownMenuItem
|
||||
v-if="preference"
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleOpenPreference"
|
||||
>
|
||||
<IcRoundSettingsSuggest class="mr-2 size-5" />
|
||||
{{ $t('preference.preferences') }}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
|
||||
@click="handleLogout"
|
||||
>
|
||||
<IcRoundLogout class="mr-2 size-5" />
|
||||
{{ $t('common.logout') }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
|
@ -127,7 +127,7 @@ function wrapperMenus(menus: MenuRecordRaw[]) {
|
|||
(value: boolean) => updatePreference('sideExpandOnHover', value)
|
||||
"
|
||||
>
|
||||
<template #preference>
|
||||
<template v-if="preference.showPreference" #preference>
|
||||
<PreferenceWidget />
|
||||
</template>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Preference } from '@vben-core/typings';
|
|||
|
||||
class PreferenceCache {
|
||||
cachePrefix: string;
|
||||
constructor(cachePrefix: string = 'vben-admin') {
|
||||
constructor(cachePrefix: string) {
|
||||
this.cachePrefix = cachePrefix;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ class PreferenceCache {
|
|||
* 获取偏好设置的缓存键
|
||||
*/
|
||||
getCacheKey(name: string = 'preference') {
|
||||
const env = import.meta.env.DEV ? 'dev' : 'prod';
|
||||
return `__${this.cachePrefix}-${name}-${env}__`;
|
||||
return `__${this.cachePrefix}-${name}__`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,8 +34,9 @@ const defaultPreference: Preference = {
|
|||
pageTransition: 'fade-slide',
|
||||
pageTransitionEnable: true,
|
||||
semiDarkMenu: true,
|
||||
showPreference: true,
|
||||
sideCollapse: false,
|
||||
sideCollapseShowTitle: false,
|
||||
sideCollapseShowTitle: true,
|
||||
sideExpandOnHover: true,
|
||||
sideExtraCollapse: true,
|
||||
sideVisible: true,
|
||||
|
|
|
@ -4,22 +4,24 @@ import { PreferenceCache } from './cache';
|
|||
import { overridesPreference } from './preference';
|
||||
|
||||
interface SetupPreferenceOptions {
|
||||
/**
|
||||
* @zh_CN 环境
|
||||
*/
|
||||
env: string;
|
||||
/**
|
||||
* @zh_CN 应用名,由于 @vben/preference 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名
|
||||
* 应用名将被用于持久化的前缀
|
||||
*/
|
||||
cachePrefix?: string;
|
||||
namespace: string;
|
||||
/**
|
||||
* @zh_CN app自行覆盖偏好设置
|
||||
*/
|
||||
overrides?: DeepPartial<Preference>;
|
||||
}
|
||||
|
||||
async function setupPreference(options: SetupPreferenceOptions = {}) {
|
||||
const { cachePrefix = 'vben-admin-pro', overrides = {} } = options;
|
||||
|
||||
const cache = new PreferenceCache(cachePrefix);
|
||||
|
||||
async function setupPreference(options: SetupPreferenceOptions) {
|
||||
const { env, namespace, overrides = {} } = options;
|
||||
const cache = new PreferenceCache(`${namespace}-${env}`);
|
||||
overridesPreference(overrides, cache);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,26 +3,29 @@ import type { App } from 'vue';
|
|||
import { createPinia } from 'pinia';
|
||||
|
||||
interface SetupStoreOptions {
|
||||
/**
|
||||
* @zh_CN 环境
|
||||
*/
|
||||
env: string;
|
||||
/**
|
||||
* @zh_CN 应用名,由于 @vben/stores 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名
|
||||
* 应用名将被用于持久化的前缀
|
||||
*/
|
||||
cachePrefix?: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 初始化pinia
|
||||
* @param app vue app 实例
|
||||
*/
|
||||
async function setupStore(app: App, options: SetupStoreOptions = {}) {
|
||||
async function setupStore(app: App, options: SetupStoreOptions) {
|
||||
const { createPersistedState } = await import('pinia-plugin-persistedstate');
|
||||
const pinia = createPinia();
|
||||
const { cachePrefix = 'vben-admin-pro' } = options;
|
||||
const env = import.meta.env.DEV ? 'dev' : 'prod';
|
||||
const { env, namespace } = options;
|
||||
pinia.use(
|
||||
createPersistedState({
|
||||
// key $appName-$store.id
|
||||
key: (storeKey) => `__${cachePrefix}-${storeKey}-${env}__`,
|
||||
key: (storeKey) => `__${namespace}-${env}-${storeKey}__`,
|
||||
storage: localStorage,
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"sideEffects": [
|
||||
"**/*.css"
|
||||
],
|
||||
"main": "./dist/index.mjs",
|
||||
"module": "./dist/index.mjs",
|
||||
"imports": {
|
||||
|
@ -42,6 +39,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vben-core/design": "workspace:*",
|
||||
"@vben-core/design-tokens": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vben-core/design": "workspace:*",
|
||||
"@vben-core/design-tokens": "workspace:*"
|
||||
|
|
|
@ -198,8 +198,8 @@ importers:
|
|||
specifier: ^2.29.1
|
||||
version: 2.29.1(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
|
||||
eslint-plugin-jsdoc:
|
||||
specifier: ^48.2.5
|
||||
version: 48.2.5(eslint@8.57.0)
|
||||
specifier: ^48.2.6
|
||||
version: 48.2.6(eslint@8.57.0)
|
||||
eslint-plugin-jsonc:
|
||||
specifier: ^2.15.1
|
||||
version: 2.15.1(eslint@8.57.0)
|
||||
|
@ -331,8 +331,8 @@ importers:
|
|||
internal/tailwind-config:
|
||||
dependencies:
|
||||
'@iconify/json':
|
||||
specifier: ^2.2.212
|
||||
version: 2.2.212
|
||||
specifier: ^2.2.213
|
||||
version: 2.2.213
|
||||
'@iconify/tailwind':
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
|
@ -352,8 +352,8 @@ importers:
|
|||
specifier: ^0.2.0
|
||||
version: 0.2.0(postcss@8.4.38)
|
||||
postcss-preset-env:
|
||||
specifier: ^9.5.13
|
||||
version: 9.5.13(postcss@8.4.38)
|
||||
specifier: ^9.5.14
|
||||
version: 9.5.14(postcss@8.4.38)
|
||||
tailwindcss:
|
||||
specifier: ^3.4.3
|
||||
version: 3.4.3
|
||||
|
@ -1815,8 +1815,8 @@ packages:
|
|||
'@humanwhocodes/object-schema@2.0.3':
|
||||
resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
|
||||
|
||||
'@iconify/json@2.2.212':
|
||||
resolution: {integrity: sha512-d1IXjpbSwk8V3C9D+mruRTJRPqZZpCnOWh9zyG/Zc5zJmPDLBEHNTKz+ZmeiJQ6LdzgjwLJai1WgFvt1HWVIPw==}
|
||||
'@iconify/json@2.2.213':
|
||||
resolution: {integrity: sha512-5tcEn+ZDoWlBXmlJidYjMsJyFXhXuVscbg7PRpaon86GqrDlwW/cl8mR682C06Oq4AfeypmfVI18YTnczwdqxA==}
|
||||
|
||||
'@iconify/tailwind@1.1.1':
|
||||
resolution: {integrity: sha512-4mmA//qjZigv7D4KlqcVSYTqfRIJzyts2/lSCAJfCL0rVMIE76+ifJnaE5jxCo1+nYGBF8FsFo0qFOs+sX4EnA==}
|
||||
|
@ -3643,8 +3643,8 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: ^7.2.0 || ^8
|
||||
|
||||
eslint-plugin-jsdoc@48.2.5:
|
||||
resolution: {integrity: sha512-ZeTfKV474W1N9niWfawpwsXGu+ZoMXu4417eBROX31d7ZuOk8zyG66SO77DpJ2+A9Wa2scw/jRqBPnnQo7VbcQ==}
|
||||
eslint-plugin-jsdoc@48.2.6:
|
||||
resolution: {integrity: sha512-GNk9jtpYmoEVeD/U6yYYmd6T8vSOoPs7CL8ZeX85iD8P3qifDdLQGze6+cw9boobDthmYnnxvIoHrhuSffj09g==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
|
||||
|
@ -5554,8 +5554,8 @@ packages:
|
|||
peerDependencies:
|
||||
postcss: ^8.2.14
|
||||
|
||||
postcss-nesting@12.1.4:
|
||||
resolution: {integrity: sha512-CcHOq94K137E+U4Ommu7pexcpp0Tjm24zl4UcqWs1oSLAr5cLI+jLrqQ5h/bdjhMX6cMbzunyustVNnvrzF8Zg==}
|
||||
postcss-nesting@12.1.5:
|
||||
resolution: {integrity: sha512-N1NgI1PDCiAGWPTYrwqm8wpjv0bgDmkYHH72pNsqTCv9CObxjxftdYu6AKtGN+pnJa7FQjMm3v4sp8QJbFsYdQ==}
|
||||
engines: {node: ^14 || ^16 || >=18}
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
|
@ -5643,8 +5643,8 @@ packages:
|
|||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
|
||||
postcss-preset-env@9.5.13:
|
||||
resolution: {integrity: sha512-YQMwWu6MAc4Envrjf/mW2BTrb5J8WkrJ4dV2VostZVDhrmEPpYREOyhmvtlFLDxK1/AmTDY8aXjZViMC1qKu/w==}
|
||||
postcss-preset-env@9.5.14:
|
||||
resolution: {integrity: sha512-gTMi+3kENN/mN+K59aR+vEOjlkujTmmXJcM9rnAqGh9Y/euQ/ypdp9rd8mO1eoIjAD8vNS15+xbkBxoi+65BqQ==}
|
||||
engines: {node: ^14 || ^16 || >=18}
|
||||
peerDependencies:
|
||||
postcss: ^8.4
|
||||
|
@ -5703,6 +5703,10 @@ packages:
|
|||
resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-selector-parser@6.1.0:
|
||||
resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
postcss-sorting@8.0.2:
|
||||
resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==}
|
||||
peerDependencies:
|
||||
|
@ -8036,9 +8040,9 @@ snapshots:
|
|||
dependencies:
|
||||
postcss: 8.4.38
|
||||
|
||||
'@csstools/selector-resolve-nested@1.1.0(postcss-selector-parser@6.0.16)':
|
||||
'@csstools/selector-resolve-nested@1.1.0(postcss-selector-parser@6.1.0)':
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.0.16
|
||||
postcss-selector-parser: 6.1.0
|
||||
|
||||
'@csstools/selector-specificity@3.0.3(postcss-selector-parser@6.0.16)':
|
||||
dependencies:
|
||||
|
@ -8048,6 +8052,10 @@ snapshots:
|
|||
dependencies:
|
||||
postcss-selector-parser: 6.0.16
|
||||
|
||||
'@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.0)':
|
||||
dependencies:
|
||||
postcss-selector-parser: 6.1.0
|
||||
|
||||
'@csstools/utilities@1.0.0(postcss@8.4.38)':
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
|
@ -8280,7 +8288,7 @@ snapshots:
|
|||
|
||||
'@humanwhocodes/object-schema@2.0.3': {}
|
||||
|
||||
'@iconify/json@2.2.212':
|
||||
'@iconify/json@2.2.213':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
pathe: 1.1.2
|
||||
|
@ -10390,7 +10398,7 @@ snapshots:
|
|||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-jsdoc@48.2.5(eslint@8.57.0):
|
||||
eslint-plugin-jsdoc@48.2.6(eslint@8.57.0):
|
||||
dependencies:
|
||||
'@es-joy/jsdoccomment': 0.43.0
|
||||
are-docs-informative: 0.0.2
|
||||
|
@ -10399,7 +10407,6 @@ snapshots:
|
|||
escape-string-regexp: 4.0.0
|
||||
eslint: 8.57.0
|
||||
esquery: 1.5.0
|
||||
is-builtin-module: 3.2.1
|
||||
semver: 7.6.2
|
||||
spdx-expression-parse: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
|
@ -12353,12 +12360,12 @@ snapshots:
|
|||
postcss: 8.4.38
|
||||
postcss-selector-parser: 6.0.16
|
||||
|
||||
postcss-nesting@12.1.4(postcss@8.4.38):
|
||||
postcss-nesting@12.1.5(postcss@8.4.38):
|
||||
dependencies:
|
||||
'@csstools/selector-resolve-nested': 1.1.0(postcss-selector-parser@6.0.16)
|
||||
'@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.0.16)
|
||||
'@csstools/selector-resolve-nested': 1.1.0(postcss-selector-parser@6.1.0)
|
||||
'@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.0)
|
||||
postcss: 8.4.38
|
||||
postcss-selector-parser: 6.0.16
|
||||
postcss-selector-parser: 6.1.0
|
||||
|
||||
postcss-normalize-charset@7.0.0(postcss@8.4.38):
|
||||
dependencies:
|
||||
|
@ -12429,7 +12436,7 @@ snapshots:
|
|||
postcss: 8.4.38
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
postcss-preset-env@9.5.13(postcss@8.4.38):
|
||||
postcss-preset-env@9.5.14(postcss@8.4.38):
|
||||
dependencies:
|
||||
'@csstools/postcss-cascade-layers': 4.0.6(postcss@8.4.38)
|
||||
'@csstools/postcss-color-function': 3.0.16(postcss@8.4.38)
|
||||
|
@ -12484,7 +12491,7 @@ snapshots:
|
|||
postcss-image-set-function: 6.0.3(postcss@8.4.38)
|
||||
postcss-lab-function: 6.0.16(postcss@8.4.38)
|
||||
postcss-logical: 7.0.1(postcss@8.4.38)
|
||||
postcss-nesting: 12.1.4(postcss@8.4.38)
|
||||
postcss-nesting: 12.1.5(postcss@8.4.38)
|
||||
postcss-opacity-percentage: 2.0.0(postcss@8.4.38)
|
||||
postcss-overflow-shorthand: 5.0.1(postcss@8.4.38)
|
||||
postcss-page-break: 3.0.4(postcss@8.4.38)
|
||||
|
@ -12537,6 +12544,11 @@ snapshots:
|
|||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-selector-parser@6.1.0:
|
||||
dependencies:
|
||||
cssesc: 3.0.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
postcss-sorting@8.0.2(postcss@8.4.38):
|
||||
dependencies:
|
||||
postcss: 8.4.38
|
||||
|
|
Loading…
Reference in New Issue