vben пре 9 месеци
родитељ
комит
36a4fcfad2
25 измењених фајлова са 607 додато и 302 уклоњено
  1. 105 2
      apps/web-antd/src/views/dashboard/workspace/index.vue
  2. 1 1
      apps/web-antd/vite.config.mts
  3. 2 2
      internal/lint-configs/eslint-config/package.json
  4. 1 1
      internal/lint-configs/stylelint-config/package.json
  5. 2 2
      internal/tailwind-config/package.json
  6. 1 1
      internal/vite-config/package.json
  7. 7 2
      internal/vite-config/src/config/library.ts
  8. 3 3
      package.json
  9. 15 18
      packages/@core/forward/preferences/src/preferences.ts
  10. 1 1
      packages/business/chart-ui/src/echarts/echarts.ts
  11. 1 1
      packages/business/chart-ui/src/echarts/use-echarts.ts
  12. 17 0
      packages/business/universal-ui/src/dashboard/typing.ts
  13. 2 0
      packages/business/universal-ui/src/dashboard/workbench/index.ts
  14. 6 2
      packages/business/universal-ui/src/dashboard/workbench/workbench-project.vue
  15. 6 2
      packages/business/universal-ui/src/dashboard/workbench/workbench-quick-nav.vue
  16. 63 0
      packages/business/universal-ui/src/dashboard/workbench/workbench-todo.vue
  17. 64 0
      packages/business/universal-ui/src/dashboard/workbench/workbench-trends.vue
  18. 3 2
      packages/business/widgets/src/preferences/preferences.vue
  19. 0 0
      packages/icons/src/svg/icons/avatar-1.svg
  20. 0 0
      packages/icons/src/svg/icons/avatar-2.svg
  21. 0 0
      packages/icons/src/svg/icons/avatar-3.svg
  22. 0 0
      packages/icons/src/svg/icons/avatar-4.svg
  23. 0 0
      packages/icons/src/svg/icons/avatar.svg
  24. 8 2
      packages/icons/src/svg/index.ts
  25. 299 260
      pnpm-lock.yaml

+ 105 - 2
apps/web-antd/src/views/dashboard/workspace/index.vue

@@ -2,17 +2,26 @@
 import type {
   WorkbenchProjectItem,
   WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
 } from '@vben/universal-ui';
 
+import { ref } from 'vue';
+
 import {
+  AnalysisChartCard,
   WorkbenchHeader,
   WorkbenchProject,
   WorkbenchQuickNav,
+  WorkbenchTodo,
+  WorkbenchTrends,
 } from '@vben/universal-ui';
 import { preferences } from '@vben-core/preferences';
 
 import { useAccessStore } from '#/store';
 
+import AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';
+
 defineOptions({ name: 'Workspace' });
 
 const { userInfo } = useAccessStore();
@@ -100,6 +109,95 @@ const quickNavItems: WorkbenchQuickNavItem[] = [
     title: '图表',
   },
 ];
+
+const todoItems = ref<WorkbenchTodoItem[]>([
+  {
+    completed: false,
+    content: `审查最近提交到Git仓库的前端代码,确保代码质量和规范。`,
+    date: '2024-07-30 11:00:00',
+    title: '审查前端代码提交',
+  },
+  {
+    completed: true,
+    content: `检查并优化系统性能,降低CPU使用率。`,
+    date: '2024-07-30 11:00:00',
+    title: '系统性能优化',
+  },
+  {
+    completed: false,
+    content: `进行系统安全检查,确保没有安全漏洞或未授权的访问。 `,
+    date: '2024-07-30 11:00:00',
+    title: '安全检查',
+  },
+  {
+    completed: false,
+    content: `更新项目中的所有npm依赖包,确保使用最新版本。`,
+    date: '2024-07-30 11:00:00',
+    title: '更新项目依赖',
+  },
+  {
+    completed: false,
+    content: `修复用户报告的页面UI显示问题,确保在不同浏览器中显示一致。 `,
+    date: '2024-07-30 11:00:00',
+    title: '修复UI显示问题',
+  },
+]);
+const trendItems: WorkbenchTrendItem[] = [
+  {
+    avatar: 'svg:avatar-1',
+    content: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,
+    date: '刚刚',
+    title: '威廉',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `关注了 <a>威廉</a> `,
+    date: '1个小时前',
+    title: '艾文',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `发布了 <a>个人动态</a> `,
+    date: '1天前',
+    title: '克里斯',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `发表文章 <a>如何编写一个Vite插件</a> `,
+    date: '2天前',
+    title: 'Vben',
+  },
+  {
+    avatar: 'svg:avatar-1',
+    content: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化?</a>`,
+    date: '3天前',
+    title: '皮特',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `关闭了问题 <a>如何运行项目</a> `,
+    date: '1周前',
+    title: '杰克',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `发布了 <a>个人动态</a> `,
+    date: '1周前',
+    title: '威廉',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `推送了代码到 <a>Github</a>`,
+    date: '2021-04-01 20:00',
+    title: '威廉',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `发表文章 <a>如何编写使用 Admin Vben</a> `,
+    date: '2021-03-01 20:00',
+    title: 'Vben',
+  },
+];
 </script>
 
 <template>
@@ -114,11 +212,16 @@ const quickNavItems: WorkbenchQuickNavItem[] = [
     </WorkbenchHeader>
 
     <div class="mt-5 flex">
-      <div class="mr-4 w-full md:w-2/3">
+      <div class="mr-4 w-full md:w-3/5">
         <WorkbenchProject :items="projectItems" title="项目" />
+        <WorkbenchTrends :items="trendItems" class="mt-5" title="最新动态" />
       </div>
-      <div class="w-full md:w-1/3">
+      <div class="w-full md:w-2/5">
         <WorkbenchQuickNav :items="quickNavItems" title="快捷导航" />
+        <WorkbenchTodo :items="todoItems" class="mt-5" title="待办事项" />
+        <AnalysisChartCard class="mt-5" title="访问来源">
+          <AnalyticsVisitsSource />
+        </AnalysisChartCard>
       </div>
     </div>
   </div>

+ 1 - 1
apps/web-antd/vite.config.mts

@@ -3,7 +3,7 @@ import { defineConfig } from '@vben/vite-config';
 export default defineConfig({
   application: ({ mode }) => {
     return {
-      compress: false,
+      compress: true,
       compressTypes: ['brotli', 'gzip'],
       importmap: false,
       importmapOptions: {

+ 2 - 2
internal/lint-configs/eslint-config/package.json

@@ -30,7 +30,7 @@
     "eslint-plugin-command": "^0.2.3"
   },
   "devDependencies": {
-    "@eslint/js": "^9.5.0",
+    "@eslint/js": "^9.6.0",
     "@types/eslint": "^8.56.10",
     "@typescript-eslint/eslint-plugin": "^7.14.1",
     "@typescript-eslint/parser": "^7.14.1",
@@ -49,7 +49,7 @@
     "eslint-plugin-unused-imports": "^4.0.0",
     "eslint-plugin-vitest": "^0.5.4",
     "eslint-plugin-vue": "^9.26.0",
-    "globals": "^15.6.0",
+    "globals": "^15.7.0",
     "jsonc-eslint-parser": "^2.4.0",
     "vue-eslint-parser": "^9.4.3"
   }

+ 1 - 1
internal/lint-configs/stylelint-config/package.json

@@ -33,7 +33,7 @@
     "stylelint-scss": "^6.3.2"
   },
   "devDependencies": {
-    "postcss": "^8.4.38",
+    "postcss": "^8.4.39",
     "postcss-html": "^1.7.0",
     "postcss-scss": "^4.0.9",
     "prettier": "^3.3.2",

+ 2 - 2
internal/tailwind-config/package.json

@@ -52,10 +52,10 @@
     "@tailwindcss/typography": "^0.5.13",
     "autoprefixer": "^10.4.19",
     "cssnano": "^7.0.3",
-    "postcss": "^8.4.38",
+    "postcss": "^8.4.39",
     "postcss-antd-fixes": "^0.2.0",
     "postcss-import": "^16.1.0",
-    "postcss-preset-env": "^9.5.14",
+    "postcss-preset-env": "^9.5.15",
     "tailwindcss": "^3.4.4",
     "tailwindcss-animate": "^1.0.7"
   },

+ 1 - 1
internal/vite-config/package.json

@@ -34,7 +34,7 @@
     "resolve.exports": "^2.0.2",
     "vite-plugin-lib-inject-css": "^2.1.1",
     "vite-plugin-pwa": "^0.20.0",
-    "vite-plugin-vue-devtools": "^7.3.4"
+    "vite-plugin-vue-devtools": "^7.3.5"
   },
   "devDependencies": {
     "@types/html-minifier-terser": "^7.0.2",

+ 7 - 2
internal/vite-config/src/config/library.ts

@@ -28,10 +28,11 @@ function defineLibraryConfig(options: DefineLibraryOptions = {}) {
     const { dependencies = {}, peerDependencies = {} } =
       await readPackageJSON(root);
 
-    const external = [
+    const externalPackages = [
       ...Object.keys(dependencies),
       ...Object.keys(peerDependencies),
     ];
+
     const packageConfig: UserConfig = {
       build: {
         lib: {
@@ -40,7 +41,11 @@ function defineLibraryConfig(options: DefineLibraryOptions = {}) {
           formats: ['es'],
         },
         rollupOptions: {
-          external,
+          external: (id) => {
+            return externalPackages.some(
+              (pkg) => id === pkg || id.startsWith(`${pkg}/`),
+            );
+          },
         },
       },
       plugins,

+ 3 - 3
package.json

@@ -68,13 +68,13 @@
     "is-ci": "^3.0.1",
     "jsdom": "^24.1.0",
     "rimraf": "^5.0.7",
-    "taze": "^0.13.9",
-    "turbo": "^2.0.5",
+    "taze": "^0.14.0",
+    "turbo": "^2.0.6",
     "typescript": "^5.5.2",
     "unbuild": "^2.0.0",
     "vite": "^5.3.2",
     "vitest": "^2.0.0-beta.10",
-    "vue-tsc": "^2.0.22"
+    "vue-tsc": "^2.0.24"
   },
   "engines": {
     "node": ">=20",

+ 15 - 18
packages/@core/forward/preferences/src/preferences.ts

@@ -77,7 +77,10 @@ class PreferenceManager {
       this.updateTheme(this.state);
     }
 
-    if (appUpdates.colorGrayMode || appUpdates.colorWeakMode) {
+    if (
+      Reflect.has(appUpdates, 'colorGrayMode') ||
+      Reflect.has(appUpdates, 'colorWeakMode')
+    ) {
       this.updateColorMode(this.state);
     }
   }
@@ -229,22 +232,16 @@ class PreferenceManager {
       return;
     }
 
-    const {
-      builtinType,
-      colorDestructive,
-      colorPrimary,
-      colorSuccess,
-      colorWarning,
-      mode,
-      radius,
-    } = preferences?.theme ?? {};
-
-    if (mode) {
+    const theme = preferences?.theme ?? {};
+
+    const { builtinType, colorPrimary, mode, radius } = theme;
+
+    if (Reflect.has(theme, 'mode')) {
       const dark = isDarkTheme(mode);
       root.classList.toggle('dark', dark);
     }
 
-    if (builtinType) {
+    if (Reflect.has(theme, 'builtinType')) {
       const rootTheme = root.dataset.theme;
       if (rootTheme !== builtinType) {
         root.dataset.theme = builtinType;
@@ -268,16 +265,16 @@ class PreferenceManager {
 
     if (
       builtinTypeColorPrimary ||
-      colorPrimary ||
-      colorDestructive ||
-      colorSuccess ||
-      colorWarning
+      Reflect.has(theme, 'colorPrimary') ||
+      Reflect.has(theme, 'colorDestructive') ||
+      Reflect.has(theme, 'colorSuccess') ||
+      Reflect.has(theme, 'colorWarning')
     ) {
       preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
       this.updateMainColors(preferences);
     }
 
-    if (radius) {
+    if (Reflect.has(theme, 'radius')) {
       document.documentElement.style.setProperty('--radius', `${radius}rem`);
     }
   }

+ 1 - 1
packages/business/chart-ui/src/echarts/echarts.ts

@@ -56,4 +56,4 @@ echarts.use([
   ToolboxComponent,
 ]);
 
-export { echarts };
+export default echarts;

+ 1 - 1
packages/business/chart-ui/src/echarts/use-echarts.ts

@@ -14,7 +14,7 @@ import {
   useWindowSize,
 } from '@vueuse/core';
 
-import { echarts } from './echarts';
+import echarts from './echarts';
 
 type EchartsUIType = typeof EchartsUI | undefined;
 

+ 17 - 0
packages/business/universal-ui/src/dashboard/typing.ts

@@ -16,6 +16,21 @@ interface WorkbenchProjectItem {
   icon: Component | string;
   title: string;
 }
+
+interface WorkbenchTrendItem {
+  avatar: string;
+  content: string;
+  date: string;
+  title: string;
+}
+
+interface WorkbenchTodoItem {
+  completed: boolean;
+  content: string;
+  date: string;
+  title: string;
+}
+
 interface WorkbenchQuickNavItem {
   color?: string;
   icon: Component | string;
@@ -26,4 +41,6 @@ export type {
   AnalysisOverviewItem,
   WorkbenchProjectItem,
   WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
 };

+ 2 - 0
packages/business/universal-ui/src/dashboard/workbench/index.ts

@@ -1,3 +1,5 @@
 export { default as WorkbenchHeader } from './workbench-header.vue';
 export { default as WorkbenchProject } from './workbench-project.vue';
 export { default as WorkbenchQuickNav } from './workbench-quick-nav.vue';
+export { default as WorkbenchTodo } from './workbench-todo.vue';
+export { default as WorkbenchTrends } from './workbench-trends.vue';

+ 6 - 2
packages/business/universal-ui/src/dashboard/workbench/workbench-project.vue

@@ -36,10 +36,14 @@ withDefaults(defineProps<Props>(), {
             'border-b-0': index < 3,
             'pb-4': index > 2,
           }"
-          class="border-border w-1/3 border-b border-r border-t p-4 transition-all hover:shadow-xl"
+          class="border-border group w-1/3 cursor-pointer border-b border-r border-t p-4 transition-all hover:shadow-xl"
         >
           <div class="flex items-center">
-            <VbenIcon :color="item.color" :icon="item.icon" class="size-8" />
+            <VbenIcon
+              :color="item.color"
+              :icon="item.icon"
+              class="size-8 transition-all duration-300 group-hover:scale-110"
+            />
             <span class="ml-4 text-lg font-medium">{{ item.title }}</span>
           </div>
           <div class="text-foreground/80 mt-4 flex h-10">

+ 6 - 2
packages/business/universal-ui/src/dashboard/workbench/workbench-quick-nav.vue

@@ -36,9 +36,13 @@ withDefaults(defineProps<Props>(), {
             'pb-4': index > 2,
             'border-b-0': index < 3,
           }"
-          class="flex-col-center border-border w-1/3 border-b border-r border-t py-5 transition-all hover:shadow-xl"
+          class="flex-col-center border-border group w-1/3 cursor-pointer border-b border-r border-t py-8 hover:shadow-xl"
         >
-          <VbenIcon :color="item.color" :icon="item.icon" class="size-5" />
+          <VbenIcon
+            :color="item.color"
+            :icon="item.icon"
+            class="size-7 transition-all duration-300 group-hover:scale-125"
+          />
           <span class="text-md mt-2 truncate">{{ item.title }}</span>
         </div>
       </template>

+ 63 - 0
packages/business/universal-ui/src/dashboard/workbench/workbench-todo.vue

@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { WorkbenchTodoItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenCheckbox,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchTodoItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchTodo',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-5 pt-0">
+      <ul class="divide-border w-full divide-y" role="list">
+        <li
+          v-for="item in items"
+          :key="item.title"
+          :class="{
+            'select-none line-through opacity-60': item.completed,
+          }"
+          class="flex cursor-pointer justify-between gap-x-6 py-5"
+        >
+          <div class="flex min-w-0 items-center gap-x-4">
+            <VbenCheckbox v-model:checked="item.completed" name="completed" />
+            <div class="min-w-0 flex-auto">
+              <p class="text-foreground text-sm font-semibold leading-6">
+                {{ item.title }}
+              </p>
+              <!-- eslint-disable vue/no-v-html -->
+              <p
+                class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
+                v-html="item.content"
+              ></p>
+            </div>
+          </div>
+          <div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
+            <span class="text-foreground/80 mt-6 text-xs leading-6">
+              {{ item.date }}
+            </span>
+          </div>
+        </li>
+      </ul>
+    </CardContent>
+  </Card>
+</template>

+ 64 - 0
packages/business/universal-ui/src/dashboard/workbench/workbench-trends.vue

@@ -0,0 +1,64 @@
+<script setup lang="ts">
+import type { WorkbenchTrendItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchTrendItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchTrends',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-5 pt-0">
+      <ul class="divide-border w-full divide-y" role="list">
+        <li
+          v-for="item in items"
+          :key="item.title"
+          class="flex justify-between gap-x-6 py-5"
+        >
+          <div class="flex min-w-0 items-center gap-x-4">
+            <VbenIcon
+              :icon="item.avatar"
+              alt=""
+              class="size-10 flex-none rounded-full"
+            />
+            <div class="min-w-0 flex-auto">
+              <p class="text-foreground text-sm font-semibold leading-6">
+                {{ item.title }}
+              </p>
+              <!-- eslint-disable vue/no-v-html -->
+              <p
+                class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
+                v-html="item.content"
+              ></p>
+            </div>
+          </div>
+          <div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
+            <span class="text-foreground/80 mt-6 text-xs leading-6">
+              {{ item.date }}
+            </span>
+          </div>
+        </li>
+      </ul>
+    </CardContent>
+  </Card>
+</template>

+ 3 - 2
packages/business/widgets/src/preferences/preferences.vue

@@ -15,7 +15,7 @@ import type { SegmentedItem } from '@vben-core/shadcn-ui';
 
 import { computed, ref } from 'vue';
 
-import { $t } from '@vben/locales';
+import { $t, loadLocaleMessages } from '@vben/locales';
 import { IcRoundFolderCopy, IcRoundRestartAlt } from '@vben-core/iconify';
 import {
   preferences,
@@ -166,11 +166,12 @@ async function handleCopy() {
   toast($t('preferences.copy-success'));
 }
 
-function handleReset() {
+async function handleReset() {
   if (!diffPreference.value) {
     return;
   }
   resetPreferences();
+  await loadLocaleMessages(preferences.app.locale);
   toast($t('preferences.reset-success'));
 }
 </script>

Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
packages/icons/src/svg/icons/avatar-1.svg


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
packages/icons/src/svg/icons/avatar-2.svg


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
packages/icons/src/svg/icons/avatar-3.svg


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
packages/icons/src/svg/icons/avatar-4.svg


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
packages/icons/src/svg/icons/avatar.svg


+ 8 - 2
packages/icons/src/svg/index.ts

@@ -8,14 +8,20 @@ if (!loaded) {
   loaded = true;
 }
 
-const SvgAvatarIcon = createIcon('svg:avatar');
+const SvgAvatar1Icon = createIcon('svg:avatar-1');
+const SvgAvatar2Icon = createIcon('svg:avatar-2');
+const SvgAvatar3Icon = createIcon('svg:avatar-3');
+const SvgAvatar4Icon = createIcon('svg:avatar-4');
 const SvgDownloadIcon = createIcon('svg:download');
 const SvgCardIcon = createIcon('svg:card');
 const SvgBellIcon = createIcon('svg:bell');
 const SvgCakeIcon = createIcon('svg:cake');
 
 export {
-  SvgAvatarIcon,
+  SvgAvatar1Icon,
+  SvgAvatar2Icon,
+  SvgAvatar3Icon,
+  SvgAvatar4Icon,
   SvgBellIcon,
   SvgCakeIcon,
   SvgCardIcon,

Разлика између датотеке није приказан због своје велике величине
+ 299 - 260
pnpm-lock.yaml


Неке датотеке нису приказане због велике количине промена