Bladeren bron

添加@wangeditor/editor和@wangeditor/editor-for-vue依赖,更新package.json和pnpm-lock.yaml以反映新依赖;在rspack配置中设置output的publicPath以确保资源从根路径加载;优化App.vue组件,初始化app状态监听器;重构Editor.vue组件,移除不必要的上传配置,简化代码结构;更新路由类型定义,调整requiresAuth属性为可选;清理书库管理页面,移除不再使用的元素,提升代码整洁性。

xbx 1 week geleden
bovenliggende
commit
466a5fd9f4

+ 3 - 0
config/rspack.dev.config.ts

@@ -10,6 +10,9 @@ export default defineConfig(
     entry: {
       main: './src/main.ts',
     },
+    output: {
+      publicPath: '/', // 确保所有资源从根路径加载
+    },
     devtool: 'eval-cheap-module-source-map',
     devServer: {
       hot: true,

+ 2 - 0
package.json

@@ -27,6 +27,8 @@
     "@tailwindcss/postcss": "^4.1.11",
     "@types/lodash-es": "^4.17.12",
     "@vueuse/core": "^13.5.0",
+    "@wangeditor/editor": "^5.1.23",
+    "@wangeditor/editor-for-vue": "^1.0.2",
     "axios": "^1.9.0",
     "dayjs": "^1.11.13",
     "element-plus": "^2.10.3",

File diff suppressed because it is too large
+ 488 - 0
pnpm-lock.yaml


+ 12 - 1
src/App.vue

@@ -1,4 +1,15 @@
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { useAppStore } from '@/store';
+import { onMounted } from 'vue';
+
+// 获取app状态
+const appStore = useAppStore();
+
+// 组件挂载时初始化监听器
+onMounted(() => {
+  appStore.initResizeListener();
+});
+</script>
 
 <template>
   <el-config-provider>

+ 2 - 109
src/components/Editor/src/Editor.vue

@@ -1,23 +1,14 @@
 <script lang="ts" setup>
-import { PropType, computed, ref, shallowRef, unref, watch } from 'vue'
+import { PropType, computed, ref, shallowRef, unref, watch, onBeforeUnmount, nextTick } from 'vue'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
-import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor/editor'
+import { IDomEditor, IEditorConfig } from '@wangeditor/editor'
 import { isNumber } from '@/utils/is'
 import { ElMessage } from 'element-plus'
-import { useLocaleStore } from '@/store/modules/locale'
-import { getAccessToken, getTenantId } from '@/utils/auth'
-import { getUploadUrl } from '@/components/UploadFile/src/useUpload'
 
 defineOptions({ name: 'Editor' })
 
 type InsertFnType = (url: string, alt: string, href: string) => void
 
-const localeStore = useLocaleStore()
-
-const currentLocale = computed(() => localeStore.getCurrentLocale)
-
-i18nChangeLanguage(unref(currentLocale).lang)
-
 // 使用普通的props定义方式,不使用propTypes
 const props = defineProps({
   editorId: { type: String, default: 'wangeEditor-1' },
@@ -87,104 +78,6 @@ const editorConfig = computed((): IEditorConfig => {
       },
       autoFocus: false,
       scroll: true,
-      MENU_CONF: {
-        ['uploadImage']: {
-          server: getUploadUrl(),
-          // 单个文件的最大体积限制,默认为 2M
-          maxFileSize: 5 * 1024 * 1024,
-          // 最多可上传几个文件,默认为 100
-          maxNumberOfFiles: 10,
-          // 选择文件时的类型限制,默认为 ['image/*'] 。如不想限制,则设置为 []
-          allowedFileTypes: ['image/*'],
-
-          // 自定义增加 http  header
-          headers: {
-            Accept: '*',
-            Authorization: 'Bearer ' + getAccessToken(),
-            'tenant-id': getTenantId()
-          },
-
-          // 超时时间,默认为 10 秒
-          timeout: 5 * 1000, // 5 秒
-
-          // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
-          fieldName: 'file',
-
-          // 上传之前触发
-          onBeforeUpload(file: File) {
-            // console.log(file)
-            return file
-          },
-          // 上传进度的回调函数
-          onProgress(progress: number) {
-            // progress 是 0-100 的数字
-            console.log('progress', progress)
-          },
-          onSuccess(file: File, res: any) {
-            console.log('onSuccess', file, res)
-          },
-          onFailed(file: File, res: any) {
-            alert(res.message)
-            console.log('onFailed', file, res)
-          },
-          onError(file: File, err: any, res: any) {
-            alert(err.message)
-            console.error('onError', file, err, res)
-          },
-          // 自定义插入图片
-          customInsert(res: any, insertFn: InsertFnType) {
-            insertFn(res.data, 'image', res.data)
-          }
-        },
-        ['uploadVideo']: {
-          server: getUploadUrl(),
-          // 单个文件的最大体积限制,默认为 10M
-          maxFileSize: 10 * 1024 * 1024,
-          // 最多可上传几个文件,默认为 100
-          maxNumberOfFiles: 10,
-          // 选择文件时的类型限制,默认为 ['video/*'] 。如不想限制,则设置为 []
-          allowedFileTypes: ['video/*'],
-
-          // 自定义增加 http  header
-          headers: {
-            Accept: '*',
-            Authorization: 'Bearer ' + getAccessToken(),
-            'tenant-id': getTenantId()
-          },
-
-          // 超时时间,默认为 30 秒
-          timeout: 15 * 1000, // 15 秒
-
-          // form-data fieldName,后端接口参数名称,默认值wangeditor-uploaded-image
-          fieldName: 'file',
-
-          // 上传之前触发
-          onBeforeUpload(file: File) {
-            // console.log(file)
-            return file
-          },
-          // 上传进度的回调函数
-          onProgress(progress: number) {
-            // progress 是 0-100 的数字
-            console.log('progress', progress)
-          },
-          onSuccess(file: File, res: any) {
-            console.log('onSuccess', file, res)
-          },
-          onFailed(file: File, res: any) {
-            alert(res.message)
-            console.log('onFailed', file, res)
-          },
-          onError(file: File, err: any, res: any) {
-            alert(err.message)
-            console.error('onError', file, err, res)
-          },
-          // 自定义插入图片
-          customInsert(res: any, insertFn: InsertFnType) {
-            insertFn(res.data, 'mp4', res.data)
-          }
-        }
-      },
       uploadImgShowBase64: true
     },
     props.editorConfig || {}

+ 3 - 1
src/router/routes/index.ts

@@ -3,7 +3,7 @@ import type { RouteRecordRaw } from 'vue-router';
 import { REDIRECT_MAIN, NOT_FOUND_ROUTE } from './base';
 
 // 使用 require.context 导入 modules 文件夹下的所有路由模块
-// @ts-expect-error: webpack 特定功能,TypeScript 不识别
+// @ts-expect-error
 const modulesFiles = require.context('./modules', false, /\.ts$/);
 
 // 处理导入的模块,提取路由配置
@@ -35,4 +35,6 @@ const appRoutes: RouteRecordRaw[] = [
   NOT_FOUND_ROUTE,
 ];
 
+console.log(appRoutes,'appRoutes');
+
 export default appRoutes;

+ 1 - 2
src/router/routes/modules/library.ts

@@ -6,7 +6,6 @@ const LIBRARY_MANAGEMENT: AppRouteRecordRaw = {
   component: () => import('@/layout/default-layout.vue'),
   meta: {
     title: '书库管理',
-    
     order: 1,
     icon: 'BookFilled',
   },
@@ -17,7 +16,7 @@ const LIBRARY_MANAGEMENT: AppRouteRecordRaw = {
       component: () => import('@/views/library/stack/index.vue'),
       meta: {
         title: '书库列表',
-        requiresAuth: true,
+       
       },
     }
   ]

+ 1 - 1
src/router/type.d.ts

@@ -3,7 +3,7 @@ import 'vue-router';
 declare module 'vue-router' {
   interface RouteMeta {
     roles?: string[]; // Controls roles that have access to the page
-    requiresAuth: boolean; // Whether login is required to access the current page (every route must declare)
+    requiresAuth?: boolean; // Whether login is required to access the current page (every route must declare)
     icon?: string; // The icon show in the side menu
     locale?: string; // The locale name show in side menu and breadcrumb
     hideInMenu?: boolean; // If true, it is not displayed in the side menu

+ 7 - 1
src/store/index.ts

@@ -3,12 +3,14 @@ import type { App } from 'vue';
 
 // 导入模块
 import userModule from './modules/user';
+import appModule from './modules/app';
 
 // 创建 pinia 实例
 const pinia = createPinia();
 
 // 导出各个模块的 store
 export const useUserStore = userModule.store;
+export const useAppStore = appModule.store;
 
 // 导出 store 实例
 export const store = {
@@ -17,7 +19,7 @@ export const store = {
     app.use(pinia);
     
     // 在 pinia 安装后初始化 store 状态
-    //this.initializeStores();
+    this.initializeStores();
   },
   
   // 初始化所有 store
@@ -25,6 +27,10 @@ export const store = {
     // 恢复用户状态
     const userStore = useUserStore();
     userStore.restoreFromStorage();
+    
+    // 初始化app状态
+    const appStore = useAppStore();
+    appStore.initResizeListener();
   }
 };
 

+ 83 - 0
src/store/modules/app/index.ts

@@ -0,0 +1,83 @@
+import { defineStore } from 'pinia';
+import { ref, computed, watch } from 'vue';
+import { useWindowSize } from '@vueuse/core';
+import type { AppState } from './types';
+
+// 定义App模块 Store
+export const useAppStore = defineStore('app', {
+  // 状态
+  state: (): AppState => {
+    // 获取窗口大小
+    const { width } = useWindowSize();
+    
+    return {
+      // 默认以当前窗口宽度判断是否是移动端
+      isMobile: width.value < 768,
+      // 默认折叠状态为false
+      isCollapse: false,
+      // 移动端断点宽度
+      mobileBreakpoint: 768
+    };
+  },
+
+  // Getters
+  getters: {
+    // 获取移动端状态
+    getIsMobile(): boolean {
+      return this.isMobile;
+    },
+    // 获取折叠状态
+    getIsCollapse(): boolean {
+      return this.isCollapse;
+    }
+  },
+
+  // Actions
+  actions: {
+    // 设置移动端状态
+    setIsMobile(isMobile: boolean) {
+      this.isMobile = isMobile;
+      
+      // 在移动端时自动折叠侧边栏
+      if (isMobile && !this.isCollapse) {
+        this.setCollapse(true);
+      }
+    },
+    
+    // 设置折叠状态
+    setCollapse(isCollapse: boolean) {
+      this.isCollapse = isCollapse;
+    },
+    
+    // 切换折叠状态
+    toggleCollapse() {
+      this.setCollapse(!this.isCollapse);
+    },
+    
+    // 根据窗口大小更新移动端状态
+    updateMobileStatus() {
+      const { width } = useWindowSize();
+      const isMobile = width.value < this.mobileBreakpoint;
+      this.setIsMobile(isMobile);
+    },
+    
+    // 初始化监听器
+    initResizeListener() {
+      // 使用 vueuse 的 useWindowSize 监听窗口大小变化
+      const { width } = useWindowSize();
+      
+      // 创建计算属性监听窗口宽度
+      const isMobile = computed(() => width.value < this.mobileBreakpoint);
+      
+      // 监听计算属性的变化
+      watch(isMobile, (newValue) => {
+        this.setIsMobile(newValue);
+      }, { immediate: true });
+    }
+  }
+});
+
+// 导出默认模块
+export default {
+  store: useAppStore
+}; 

+ 11 - 0
src/store/modules/app/types.ts

@@ -0,0 +1,11 @@
+// app模块类型定义
+
+// App模块状态接口
+export interface AppState {
+  // 是否是移动端设备(屏幕宽度小于768px)
+  isMobile: boolean;
+  // 侧边栏是否折叠
+  isCollapse: boolean;
+  // 移动端断点宽度(默认768px)
+  mobileBreakpoint: number;
+} 

+ 0 - 12
src/types/components.d.ts

@@ -13,22 +13,13 @@ declare module 'vue' {
     Dialog: typeof import('./../components/Dialog/index.vue')['default']
     EditorSrcEditor: typeof import('./../components/Editor/src/Editor.vue')['default']
     ElButton: typeof import('element-plus/es')['ElButton']
-    ElCard: typeof import('element-plus/es')['ElCard']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDialog: typeof import('element-plus/es')['ElDialog']
-    ElForm: typeof import('element-plus/es')['ElForm']
-    ElFormItem: typeof import('element-plus/es')['ElFormItem']
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElInput: typeof import('element-plus/es')['ElInput']
-    ElOption: typeof import('element-plus/es')['ElOption']
-    ElPagination: typeof import('element-plus/es')['ElPagination']
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
-    ElSelect: typeof import('element-plus/es')['ElSelect']
     ElSpace: typeof import('element-plus/es')['ElSpace']
-    ElTable: typeof import('element-plus/es')['ElTable']
-    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
-    ElTag: typeof import('element-plus/es')['ElTag']
     HelpMessageSrc: typeof import('./../components/helpMessage/src/index.vue')['default']
     Icon: typeof import('./../components/Icon/Index.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
@@ -44,7 +35,4 @@ declare module 'vue' {
     TableComponentsZtTableSetting: typeof import('./../components/Table/components/ztTableSetting.vue')['default']
     TableSrcZtTable: typeof import('./../components/Table/src/ztTable.vue')['default']
   }
-  export interface GlobalDirectives {
-    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
-  }
 }

+ 2 - 62
src/views/library/stack/index.vue

@@ -1,67 +1,7 @@
 <template>
   <div class="library-stack-container">
-    <el-card class="box-card">
-      <template #header>
-        <div class="card-header">
-          <span>书库列表</span>
-          <el-button type="primary">添加书库</el-button>
-        </div>
-      </template>
-      
-      <!-- 搜索区域 -->
-      <div class="search-container">
-        <el-form :inline="true" :model="searchForm" class="form-inline">
-          <el-form-item label="书库名称">
-            <el-input v-model="searchForm.name" placeholder="请输入书库名称" clearable></el-input>
-          </el-form-item>
-          <el-form-item label="状态">
-            <el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
-              <el-option label="正常" value="normal"></el-option>
-              <el-option label="禁用" value="disabled"></el-option>
-            </el-select>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" @click="handleSearch">搜索</el-button>
-            <el-button @click="resetSearch">重置</el-button>
-          </el-form-item>
-        </el-form>
-      </div>
-      
-      <!-- 表格区域 -->
-      <el-table :data="tableData" style="width: 100%" v-loading="loading">
-        <el-table-column prop="id" label="ID" width="80"></el-table-column>
-        <el-table-column prop="name" label="书库名称"></el-table-column>
-        <el-table-column prop="bookCount" label="书籍数量"></el-table-column>
-        <el-table-column prop="createdTime" label="创建时间"></el-table-column>
-        <el-table-column prop="status" label="状态">
-          <template #default="scope">
-            <el-tag :type="scope.row.status === 'normal' ? 'success' : 'danger'">
-              {{ scope.row.status === 'normal' ? '正常' : '禁用' }}
-            </el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="操作" width="180">
-          <template #default="scope">
-            <el-button type="primary" link size="small" @click="handleEdit(scope.row)">编辑</el-button>
-            <el-button type="primary" link size="small" @click="handleView(scope.row)">查看</el-button>
-            <el-button type="danger" link size="small" @click="handleDelete(scope.row)">删除</el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-      
-      <!-- 分页区域 -->
-      <div class="pagination-container">
-        <el-pagination
-          v-model:current-page="currentPage"
-          v-model:page-size="pageSize"
-          :page-sizes="[10, 20, 50, 100]"
-          layout="total, sizes, prev, pager, next, jumper"
-          :total="total"
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
-      </div>
-    </el-card>
+  
+    测试啊
   </div>
 </template>