浏览代码

文件夹树的增删改,定义了递归接口删除文件夹残余文件,以及文件夹树的level判断

Lijiahao 1 周之前
父节点
当前提交
8ba8d5e2d0

+ 45 - 3
xzl-admin/src/main/java/com/xzl/web/controller/SysFileFolderController.java

@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import com.xzl.common.core.domain.entity.SysFileFolder;
 import com.xzl.web.service.ISysFileFolderService;
+import lombok.Getter;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -26,7 +27,7 @@ import com.xzl.common.core.page.TableDataInfo;
  * 文件文件夹(麻城知识库四级结构)Controller
  *
  * @author xzl
- * @date 2025-06-17
+ * @date  2025-06-17
  */
 @RestController
 @RequestMapping("/system/folder")
@@ -56,7 +57,7 @@ public class SysFileFolderController extends BaseController
     public void export(HttpServletResponse response, SysFileFolder sysFileFolder)
     {
         List<SysFileFolder> list = sysFileFolderService.selectSysFileFolderList(sysFileFolder);
-        ExcelUtil<SysFileFolder> util = new ExcelUtil<SysFileFolder>(SysFileFolder.class);
+        ExcelUtil<SysFileFolder> util = new ExcelUtil<>(SysFileFolder.class);
         util.exportExcel(response, list, "文件文件夹(麻城知识库四级结构)数据");
     }
 
@@ -97,7 +98,7 @@ public class SysFileFolderController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('system:folder:remove')")
     @Log(title = "文件文件夹(麻城知识库四级结构)", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{folderIds}")
+	@DeleteMapping("/batchRemove/{folderIds}")
     public AjaxResult remove(@PathVariable Long[] folderIds)
     {
         return toAjax(sysFileFolderService.deleteSysFileFolderByFolderIds(folderIds));
@@ -111,6 +112,47 @@ public class SysFileFolderController extends BaseController
     @GetMapping("/folderTree")
     public AjaxResult folderTree(SysFileFolder sysFileFolder)
     {
+        logger.info("返回的文件夹树数据: {}",sysFileFolderService.selectSysFileFolderTree(sysFileFolder).toString());
         return success(sysFileFolderService.selectSysFileFolderTree(sysFileFolder));
     }
+
+
+    /**
+     * 检查文件文件夹是否可以删除(是否包含子文件夹或文件)
+     */
+    @PreAuthorize("@ss.hasPermi('system:folder:remove')")
+    @GetMapping("/checkDeletable/{folderId}")
+    public AjaxResult checkDeletable(@PathVariable Long folderId)
+    {
+        // 判断是否包含子文件夹或文件
+        boolean hasChildren = sysFileFolderService.hasChildren(folderId);
+        int fileCount = sysFileFolderService.getFileCountByFolderId(folderId);
+
+        return success(new CheckResult(hasChildren, fileCount));
+    }
+
+    // 内部类用于封装返回结果
+    @Getter
+    private static class CheckResult {
+        private final boolean hasChildren;
+        private final int fileCount;
+
+        public CheckResult(boolean hasChildren, int fileCount) {
+            this.hasChildren = hasChildren;
+            this.fileCount = fileCount;
+        }
+
+    }
+
+    // ... existing code ...
+
+    /**
+     * 删除指定文件夹下的所有文件(软删除)
+     */
+    @PreAuthorize("@ss.hasPermi('system:folder:remove')")
+    @Log(title = "文件操作", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{folderId}")
+    public AjaxResult deleteFilesByFolderId(@PathVariable Long folderId) {
+        return success(sysFileFolderService.deleteFilesByFolderId(folderId));
+    }
 }

+ 7 - 3
xzl-admin/src/main/java/com/xzl/web/mapper/SysFileFolderMapper.java

@@ -9,7 +9,7 @@ import org.apache.ibatis.annotations.Mapper;
  * 文件文件夹(麻城知识库四级结构)Mapper接口
  *
  * @author xzl
- * @date 2025-06-17
+ * &#064;date  2025-06-17
  */
 @Mapper
 public interface SysFileFolderMapper
@@ -50,9 +50,8 @@ public interface SysFileFolderMapper
      * 删除文件文件夹(麻城知识库四级结构)
      *
      * @param folderId 文件文件夹(麻城知识库四级结构)主键
-     * @return 结果
      */
-    public int deleteSysFileFolderByFolderId(Long folderId);
+    public void deleteSysFileFolderByFolderId(Long folderId);
 
     /**
      * 批量删除文件文件夹(麻城知识库四级结构)
@@ -65,4 +64,9 @@ public interface SysFileFolderMapper
     int updateSysFileFolderStatus(Long folderId, String status);
 
 
+    List<SysFileFolder> selectSysFileFolderByParentId(Long parentId);
+
+    int countFilesByFolderId(Long folderId);
+
+    void deleteFilesByFolderId(Long folderId);
 }

+ 30 - 3
xzl-admin/src/main/java/com/xzl/web/service/ISysFileFolderService.java

@@ -57,9 +57,36 @@ public interface ISysFileFolderService
      * 删除文件文件夹(麻城知识库四级结构)信息
      *
      * @param folderId 文件文件夹(麻城知识库四级结构)主键
-     * @return 结果
      */
-    public int deleteSysFileFolderByFolderId(Long folderId);
+     void deleteSysFileFolderByFolderId(Long folderId);
+
+    /**
+     * 获取系统文件夹树结构
+     * @param knowledgeFileFolder 文件夹实体
+     * @return TreeSelect类型的列表,表示文件夹树结构
+     */
+    List<TreeSelect> selectSysFileFolderTree(SysFileFolder knowledgeFileFolder);
+
+    /**
+     * 判断文件夹是否有子文件夹
+     * @param folderId 文件夹ID
+     * @return boolean类型,存在子文件夹返回true,否则返回false
+     */
+    boolean hasChildren(Long folderId);
+
+    /**
+     * 获取文件夹下的文件数量
+     * @param folderId 文件夹ID
+     * @return int类型,返回文件夹下的文件数量
+     */
+    int getFileCountByFolderId(Long folderId);
+
+    /**
+     * 根据文件夹ID删除文件
+     *
+     * @param folderId 文件夹ID
+     * @return int类型,返回删除的文件数量
+     */
+     int deleteFilesByFolderId(Long folderId);
 
-    public List<TreeSelect> selectSysFileFolderTree(SysFileFolder knowledgeFileFolder);
 }

+ 42 - 17
xzl-admin/src/main/java/com/xzl/web/service/impl/SysFileFolderServiceImpl.java

@@ -19,11 +19,10 @@ import com.xzl.web.mapper.SysFileFolderMapper;
  * 文件文件夹(麻城知识库四级结构)Service业务层处理
  *
  * @author xzl
- * @date 2025-06-17
+ * &#064;date  2025-06-17
  */
 @Service
-public class SysFileFolderServiceImpl implements ISysFileFolderService
-{
+public class SysFileFolderServiceImpl implements ISysFileFolderService {
     @Autowired
     private SysFileFolderMapper sysFileFolderMapper;
 
@@ -34,8 +33,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * @return 文件文件夹(麻城知识库四级结构)
      */
     @Override
-    public SysFileFolder selectSysFileFolderByFolderId(Long folderId)
-    {
+    public SysFileFolder selectSysFileFolderByFolderId(Long folderId) {
         return sysFileFolderMapper.selectSysFileFolderByFolderId(folderId);
     }
 
@@ -46,8 +44,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * @return 文件文件夹(麻城知识库四级结构)
      */
     @Override
-    public List<SysFileFolder> selectSysFileFolderList(SysFileFolder sysFileFolder)
-    {
+    public List<SysFileFolder> selectSysFileFolderList(SysFileFolder sysFileFolder) {
         return sysFileFolderMapper.selectSysFileFolderList(sysFileFolder);
     }
 
@@ -58,8 +55,12 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * @return 结果
      */
     @Override
-    public int insertSysFileFolder(SysFileFolder sysFileFolder)
-    {
+    public int insertSysFileFolder(SysFileFolder sysFileFolder) {
+        SysFileFolder folder = sysFileFolderMapper.selectSysFileFolderByFolderId(sysFileFolder.getParentId());
+        sysFileFolder.setFullPath(folder.getFullPath() + "/" + sysFileFolder.getFolderName());
+        sysFileFolder.setAncestors(sysFileFolderMapper.selectSysFileFolderByFolderId(sysFileFolder.getParentId()).getAncestors() + "," + sysFileFolder.getParentId());
+        sysFileFolder.setOrderNum(sysFileFolderMapper.selectSysFileFolderByFolderId(sysFileFolder.getParentId()).getOrderNum() + 1);
+        sysFileFolder.setLevel(sysFileFolderMapper.selectSysFileFolderByFolderId(sysFileFolder.getParentId()).getLevel() + 1);
         sysFileFolder.setCreateTime(DateUtils.getNowDate());
         return sysFileFolderMapper.insertSysFileFolder(sysFileFolder);
     }
@@ -71,8 +72,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * @return 结果
      */
     @Override
-    public int updateSysFileFolder(SysFileFolder sysFileFolder)
-    {
+    public int updateSysFileFolder(SysFileFolder sysFileFolder) {
         sysFileFolder.setUpdateTime(DateUtils.getNowDate());
         return sysFileFolderMapper.updateSysFileFolder(sysFileFolder);
     }
@@ -84,8 +84,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * @return 结果
      */
     @Override
-    public int deleteSysFileFolderByFolderIds(Long[] folderIds)
-    {
+    public int deleteSysFileFolderByFolderIds(Long[] folderIds) {
         return sysFileFolderMapper.deleteSysFileFolderByFolderIds(folderIds);
     }
 
@@ -93,12 +92,10 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
      * 删除文件文件夹(麻城知识库四级结构)信息
      *
      * @param folderId 文件文件夹(麻城知识库四级结构)主键
-     * @return 结果
      */
     @Override
-    public int deleteSysFileFolderByFolderId(Long folderId)
-    {
-        return sysFileFolderMapper.deleteSysFileFolderByFolderId(folderId);
+    public void deleteSysFileFolderByFolderId(Long folderId) {
+        sysFileFolderMapper.deleteSysFileFolderByFolderId(folderId);
     }
 
     private List<SysFileFolder> getChildList(List<SysFileFolder> list, SysFileFolder t) {
@@ -127,6 +124,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
     private boolean hasChild(List<SysFileFolder> list, SysFileFolder t) {
         return !getChildList(list, t).isEmpty();
     }
+
     public List<SysFileFolder> buildDeptTree(List<SysFileFolder> depts) {
         List<SysFileFolder> returnList = new ArrayList<SysFileFolder>();
         List<Long> tempList = depts.stream().map(SysFileFolder::getFolderId).collect(Collectors.toList());
@@ -142,6 +140,7 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
         }
         return returnList;
     }
+
     /**
      * 构建前端所需要下拉树结构
      *
@@ -160,5 +159,31 @@ public class SysFileFolderServiceImpl implements ISysFileFolderService
         return buildSysFileFolderTreeSelect(sysFileFolders);
     }
 
+    @Override
+    public boolean hasChildren(Long folderId) {
+        List<SysFileFolder> children = sysFileFolderMapper.selectSysFileFolderByParentId(folderId);
+        return children != null && !children.isEmpty();
+    }
+
+    @Override
+    public int getFileCountByFolderId(Long folderId) {
+        return sysFileFolderMapper.countFilesByFolderId(folderId);
+    }
+
+    @Override
+    public int deleteFilesByFolderId(Long folderId) {
+        // 删除当前文件夹下的所有文件
+        sysFileFolderMapper.deleteFilesByFolderId(folderId);
+        
+        // 再递归删除子文件夹及其文件
+        List<SysFileFolder> children = sysFileFolderMapper.selectSysFileFolderByParentId(folderId);
+        for (SysFileFolder child : children) {
+            deleteFilesByFolderId(child.getFolderId());
+            deleteSysFileFolderByFolderId(child.getFolderId());
+        }
 
+        // 最后删除当前文件夹
+        sysFileFolderMapper.deleteSysFileFolderByFolderId(folderId);
+        return 0;
+    }
 }

+ 14 - 0
xzl-admin/src/main/resources/mapper/SysFileFolderMapper.xml

@@ -103,4 +103,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{folderId}
         </foreach>
     </delete>
+
+    <select id="selectSysFileFolderByParentId"  parameterType="Long" resultMap="SysFileFolderResult">
+        SELECT * FROM sys_file_folder WHERE parent_id = #{parentId} AND del_flag = '0'
+    </select>
+
+    <select id="countFilesByFolderId"  parameterType="Long" resultType="int">
+        SELECT COUNT(*) FROM sys_file WHERE folder_id = #{folderId} AND del_flag = '0'
+    </select>
+
+    <!-- 删除指定文件夹下的所有文件 -->
+    <delete id="deleteFilesByFolderId" parameterType="Long">
+        DELETE FROM sys_file WHERE folder_id = #{folderId}
+    </delete>
+
 </mapper>

+ 1 - 1
xzl-ui/package.json

@@ -36,7 +36,7 @@
     "url": "https://gitee.com/y_project/xzl-Vue.git"
   },
   "dependencies": {
-    "@riophae/vue-treeselect": "0.4.0",
+    "@riophae/vue-treeselect": "^0.4.0",
     "axios": "0.24.0",
     "clipboard": "2.0.8",
     "core-js": "3.25.3",

+ 3 - 0
xzl-ui/src/api/system/file.js

@@ -52,3 +52,6 @@ export function updateFileStatus(fileId, status) {
   });
 }
 
+//显示所属文件夹名称
+
+

+ 9 - 0
xzl-ui/src/api/system/folder.js

@@ -50,3 +50,12 @@ export function folderTreeSelect() {
     method: 'get'
   })
 }
+
+// 检查文件夹是否可删除(是否包含子文件夹或文件)
+export function checkFolderDeletable(folderId) {
+  return request({
+    url: '/system/folder/checkDeletable/' + folderId,
+    method: 'get'
+  })
+}
+

+ 221 - 80
xzl-ui/src/views/fileTree/folder/index.vue

@@ -15,7 +15,7 @@
         </div>
         <div class="head-container">
           <el-tree
-            :data="deptOptions"
+            :data="fileOptions"
             :props="defaultProps"
             :expand-on-click-node="false"
             :filter-node-method="filterNode"
@@ -26,9 +26,10 @@
             @node-click="handleNodeClick"
           >
             <template #default="{ node, data }">
-    <span class="custom-tree-node">
+  <span class="custom-tree-node" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
+    <span style="display: flex; align-items: center;">
       <!-- 文件夹图标 -->
-      <svg t="1750230337349" class="icon" viewBox="0 0 1024 1024" version="1.1"
+      <svg x="1750230337349" class="icon" viewBox="0 0 1024 1024"
            xmlns="http://www.w3.org/2000/svg" p-id="1538" width="1em" height="1em">
         <path
           d="M918.673 883H104.327C82.578 883 65 867.368 65 848.027V276.973C65 257.632 82.578 242 104.327 242h814.346C940.422 242 958 257.632 958 276.973v571.054C958 867.28 940.323 883 918.673 883z"
@@ -42,7 +43,50 @@
       </svg>
 
       <!-- 文件夹名称 -->
-      <span style="margin-left: 6px;">{{ data.label }}</span>
+       <span style="margin-left: 6px;">{{ data.label}}</span>
+    </span>
+
+      <!-- 文件操作 -->
+     <span class="tree-node-actions" @click.stop="">
+  <el-dropdown placement="bottom-end" trigger="click"  @visible-change="(visible) => { if (visible) getLevel(data.id); }"
+  >
+    <el-button size="small" type="text" icon="el-icon-setting" style="margin-left: auto;"></el-button>
+    <template #dropdown>
+    <el-dropdown-menu style="min-width: 120px;">
+  <!-- 新增按钮:仅当层级小于4时显示 -->
+  <el-button
+    v-if="levels[data.id] !== undefined && levels[data.id] >= 0 && levels[data.id] < 4"
+    size="mini"
+    type="primary"
+    plain
+    style="width: 60px; border: none; text-align: center;"
+    @click="handleAddFolder(data)">
+    新增
+  </el-button>
+
+      <!-- 修改按钮始终显示 -->
+  <el-button
+    size="mini"
+    type="primary"
+    plain
+    style="width: 60px;border: none; text-align: center;"
+    @click="handleUpdateFolderName(data)">
+    修改
+  </el-button>
+
+      <!-- 删除按钮始终显示 -->
+  <el-button
+    size="mini"
+    type="primary"
+    plain
+    style="width: 60px; border:none; text-align: center;"
+    @click="handleDeleteFolder(data)">
+    删除
+  </el-button>
+</el-dropdown-menu>
+      </template>
+  </el-dropdown>
+</span>
     </span>
             </template>
           </el-tree>
@@ -70,7 +114,7 @@
               style="width: 240px"
             >
               <el-option
-                v-for="dict in dict.type.sys_normal_disable"
+                v-for="dict in dict.type.sys_file_status"
                 :key="dict.value"
                 :label="dict.label"
                 :value="dict.value"
@@ -82,7 +126,7 @@
               v-model="dateRange"
               style="width: 240px"
               value-format="yyyy-MM-dd"
-              type="daterange"
+              type="dateRange"
               range-separator="-"
               start-placeholder="开始日期"
               end-placeholder="结束日期"
@@ -102,7 +146,7 @@
               icon="el-icon-plus"
               size="mini"
               @click="handleAdd"
-              v-hasPermi="['system:user:add']"
+              v-hasPermi="['system:file:add']"
             >新增
             </el-button>
           </el-col>
@@ -114,7 +158,7 @@
               size="mini"
               :disabled="single"
               @click="handleUpdate"
-              v-hasPermi="['system:user:edit']"
+              v-hasPermi="['system:file:edit']"
             >修改
             </el-button>
           </el-col>
@@ -126,7 +170,7 @@
               size="mini"
               :disabled="multiple"
               @click="handleDelete"
-              v-hasPermi="['system:user:remove']"
+              v-hasPermi="['system:file:remove']"
             >删除
             </el-button>
           </el-col>
@@ -137,7 +181,7 @@
               icon="el-icon-upload2"
               size="mini"
               @click="handleImport"
-              v-hasPermi="['system:user:import']"
+              v-hasPermi="['system:file:import']"
             >导入
             </el-button>
           </el-col>
@@ -148,7 +192,7 @@
               icon="el-icon-download"
               size="mini"
               @click="handleExport"
-              v-hasPermi="['system:user:export']"
+              v-hasPermi="['system:file:export']"
             >导出
             </el-button>
           </el-col>
@@ -158,36 +202,41 @@
               plain
               icon="el-icon-refresh"
               size="mini"
-              @click="handleDingtalk"
+              @click="handleDingTalk"
             >同步钉钉
             </el-button>
           </el-col>
           <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
         </el-row>
 
-        <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+        <el-table v-loading="loading" :data="fileList" @selection-change="handleSelectionChange">
           <el-table-column type="selection" width="50" align="center"/>
-          <el-table-column label="文件编号" align="center" key="filelId" prop="fileId" v-if="columns[0].visible"/>
+          <el-table-column label="文件编号" type="index" width="50" :index="indexMethod" align="center" key="filelId"
+                           prop="fileId" v-if="columns[0].visible"/>
           <el-table-column label="文件名称" align="center" key="fileName" prop="fileName" v-if="columns[1].visible"
                            :show-overflow-tooltip="true"/>
           <el-table-column label="文件类型" align="center" key="fileType" prop="fileType" v-if="columns[2].visible"
                            :show-overflow-tooltip="true"/>
           <el-table-column label="所属文件夹" align="center" key="folderId" prop="folderId" v-if="columns[3].visible"
-                           :show-overflow-tooltip="true" :formatter="getParentFolderName"/>
+                           :show-overflow-tooltip="true" :formatter="getFolderName"/>
           <el-table-column label="创建者" align="center" key="ceateBy" prop="createBy" v-if="columns[4].visible"
                            width="120"/>
           <el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
-            <template slot-scope="scope">
-              <el-switch
-                v-model="scope.row.status"
-                active-value="0"
-                inactive-value="1"
-                @change="handleStatusChange(scope.row)"
-              ></el-switch>
-            </template>
+            <template #default="{ row }">
+  <el-switch
+    v-model="row.status"
+    :active-value="'0'"
+    :inactive-value="'1'"
+    @change="handleStatusChange(row)"
+    active-text="正常"
+    inactive-text="停用"
+    active-color="#13ce66"
+    inactive-color="#ff4949"
+  />
+</template>
           </el-table-column>
           <el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
-            <template slot-scope="scope">
+            <template v-slot="scope">
               <span>{{ parseTime(scope.row.createTime) }}</span>
             </template>
           </el-table-column>
@@ -197,39 +246,42 @@
             width="160"
             class-name="small-padding fixed-width"
           >
-            <template slot-scope="scope" v-if="scope.row.userId !== 1">
-              <el-button
-                size="mini"
-                type="text"
-                icon="el-icon-edit"
-                @click="handleUpdate(scope.row)"
-                v-hasPermi="['system:user:edit']"
-              >修改
-              </el-button>
-              <el-button
-                size="mini"
-                type="text"
-                icon="el-icon-delete"
-                @click="handleDelete(scope.row)"
-                v-hasPermi="['system:user:remove']"
-              >删除
-              </el-button>
-              <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
-                           v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
-                <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
-                <el-dropdown-menu slot="dropdown">
-                  <el-dropdown-item command="handleResetPwd" icon="el-icon-key"
-                                    v-hasPermi="['system:user:resetPwd']">重置密码
-                  </el-dropdown-item>
-                  <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
-                                    v-hasPermi="['system:user:edit']">分配角色
-                  </el-dropdown-item>
-                </el-dropdown-menu>
-              </el-dropdown>
+            <template #default="scope">
+              <div v-if="scope.row.fileId !== 1">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-edit"
+                  @click="handleUpdate(scope.row)"
+                  v-hasPermi="['system:file:edit']"
+                >修改
+                </el-button>
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-delete"
+                  @click="handleDelete(scope.row)"
+                  v-hasPermi="['system:file:remove']"
+                >删除
+                </el-button>
+                <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
+                             v-hasPermi="['system:file:resetPwd', 'system:file:edit']">
+                  <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
+                  <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item command="handleResetPwd" icon="el-icon-key"
+                                      v-hasPermi="['system:file:resetPwd']">重置密码
+                    </el-dropdown-item>
+                    <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
+                                      v-hasPermi="['system:file:edit']">分配角色
+                    </el-dropdown-item>
+                  </el-dropdown-menu>
+                  </template>
+                </el-dropdown>
+              </div>
             </template>
           </el-table-column>
         </el-table>
-
         <pagination
           v-show="total>0"
           :total="total"
@@ -258,7 +310,7 @@
         <el-row>
           <el-col :span="12">
             <el-form-item label="归属文件夹" prop="folderId">
-              <treeselect v-model="form.folderId" :options="deptOptions" :show-count="true"
+              <treeselect v-model="form.folderId" :options="fileOptions" :show-count="true"
                           placeholder="请选择归属文件夹"/>
             </el-form-item>
           </el-col>
@@ -276,7 +328,7 @@
           </el-col>
 
           <el-table-column label="状态" prop="status" v-if="columns[4].visible">
-            <template slot-scope="{row}">
+            <template v-slot="{row}">
               <el-switch
                 v-model="row.status"
                 :active-value="'0'"
@@ -342,30 +394,21 @@
 
 <script>
 import {
-  listUser,
-  getUser,
-  delUser,
-  addUser,
-  updateUser,
-  resetUserPwd,
-  changeUserStatus,
-  deptTreeSelect,
   initDingTalk
 } from "@/api/system/user";
 import {getToken} from "@/utils/auth";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-import {folderTreeSelect, getFolder} from "@/api/system/folder";
+import {addFolder, delFolder, folderTreeSelect, getFolder, updateFolder,checkFolderDeletable} from "@/api/system/folder";
 import {addFile, delFile, getFile, listFile, updateFile} from "@/api/system/file";
 import dict from "@/utils/dict";
-import {parseTime} from "../../../utils/xzl";
+import {parseTime} from "@/utils/xzl";
 import {updateFileStatus} from "@/api/system/file";
-import {getDept, listDeptExcludeChild} from "@/api/system/dept";
 
 
 export default {
-  name: "User",
-  dicts: ['sys_normal_disable', 'sys_user_sex'],
+  name: "File",
+  dicts: ['sys_file_status', 'sys_user_sex'],
   components: {Treeselect},
   data() {
     return {
@@ -382,11 +425,11 @@ export default {
       // 总条数
       total: 0,
       // 文件表格数据
-      userList: null,
+      fileList: [],
       // 弹出层标题
       title: "",
       // 文件夹树选项
-      deptOptions: [],
+      fileOptions: [],
       // 是否显示弹出层
       open: false,
       // 文件夹名称
@@ -397,6 +440,10 @@ export default {
       dateRange: [],
       //父文件夹名称
       parentFolderCache: [],
+      // 用于缓存每个文件夹的 level 值
+      levels: [],
+      // 新增字段:用于缓存选中的文件夹ID
+      selectedFolderId: null,
       // 表单参数
       form: {
         fileId: null,
@@ -408,8 +455,11 @@ export default {
         status: '0', // 默认启用
         remark: null
       },
+      // 配置 el-tree 组件的数据结构映射规则
       defaultProps: {
+        // 指定数据对象中表示子节点数组的字段名
         children: "children",
+        // 指定数据对象中表示节点显示文本的字段名
         label: "label"
       },
       // 文件导入参数
@@ -425,13 +475,14 @@ export default {
         // 设置上传的请求头部
         headers: {Authorization: "Bearer " + getToken()},
         // 上传的地址
-        url: process.env.VUE_APP_BASE_API + "/system/user/importData"
+        url: process.env.VUE_APP_BASE_API + "/system/file/importData"
       },
       // 查询参数
       queryParams: {
         pageNum: 1,
         pageSize: 10,
         fileName: undefined,
+        fileType: undefined,
         status: undefined,
         folderId: undefined
       },
@@ -484,7 +535,7 @@ export default {
   },
   created() {
     this.getList();
-    this.getDeptTree();
+    this.getFileTree();
     this.getConfigKey("sys.user.initPassword").then(response => {
       this.initPassword = response.msg;
     });
@@ -496,16 +547,17 @@ export default {
     getList() {
       this.loading = true;
       listFile(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
-          this.userList = response.rows;
+          this.fileList = response.rows;
           this.total = response.total;
           this.loading = false;
         }
       );
     },
     /** 查询文件夹下拉树结构 */
-    getDeptTree() {
+    getFileTree() {
       folderTreeSelect().then(response => {
-        this.deptOptions = response.data;
+        this.fileOptions = response.data;
+        console.log(this.fileOptions)
       });
     },
     // 筛选节点
@@ -516,6 +568,7 @@ export default {
     // 节点单击事件
     handleNodeClick(data) {
       this.queryParams.folderId = data.id;
+      this.selectedFolderId = data.id;
       this.handleQuery();
     },
     // 文件状态修改
@@ -569,8 +622,8 @@ export default {
     },
     // 多选框选中数据
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.userId);
-      this.single = selection.length != 1;
+      this.ids = selection.map(item => item.fileId);
+      this.single = selection.length !== 1;
       this.multiple = !selection.length;
     },
     // 更多操作触发
@@ -589,6 +642,9 @@ export default {
     /** 新增按钮操作 */
     handleAdd() {
       this.reset();
+      if (this.selectedFolderId) {
+        this.form.folderId = this.selectedFolderId;
+      }
       this.open = true;
       this.title = "添加文件";
     },
@@ -637,7 +693,7 @@ export default {
         ...this.queryParams
       }, `file_${new Date().getTime()}.xlsx`)
     },
-    handleDingtalk() {
+    handleDingTalk() {
       initDingTalk().then(res => {
         this.$modal.msgSuccess("同步成功");
       })
@@ -663,7 +719,7 @@ export default {
       this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", {dangerouslyUseHTMLString: true});
       this.getList();
     },
-     getParentFolderName(row, column, cellValue, index) {
+    getFolderName(row, column, cellValue, index) {
       return row.folderName
       // if (!cellValue) {
       //   return '根目录';
@@ -686,6 +742,91 @@ export default {
       //   return '错误';
       // }
     },
+    indexMethod(index) {
+      // 支持分页:当前页码 * 每页条数 + 当前行索引
+      return (this.queryParams.pageNum - 1) * this.queryParams.pageSize + index + 1;
+    },
+
+    handleAddFolder(data) {
+      this.$prompt('请输入新文件夹名称', '新增文件夹', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        inputPattern: /.+/,
+        inputErrorMessage: '文件夹名称不能为空'
+      }).then(({ value }) => {
+        const newFolder = {
+          parentId: data.id,
+          folderName: value
+        };
+        addFolder(newFolder).then(() => {
+          this.$modal.msgSuccess("新增成功");
+          this.getFileTree(); // 刷新树
+        });
+      }).catch(() => {
+        this.$message.info("已取消新增");
+      });
+    },
+
+    getLevel(folderId) {
+      if (this.levels[folderId] !== undefined) {
+        return this.levels[folderId];
+      }
+      getFolder(folderId).then(res => {
+        const level = res.data?.level;
+        this.$set(this.levels, folderId, level); // Vue.set 确保响应式更新
+      }).catch(() => {
+        this.$set(this.levels, folderId, -1); // 错误情况设为 -1
+      });
+    },
+
+    handleUpdateFolderName(data){
+      this.$prompt('请输入新的文件夹名称', '修改文件夹', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        inputValue: data.label,
+        inputPattern: /.+/,
+        inputErrorMessage: '文件夹名称不能为空'
+      }).then(({ value }) => {
+        updateFolder({ folderId: data.id, folderName: value }).then(() => {
+          this.$modal.msgSuccess("修改成功");
+          this.getFileTree(); // 刷新树
+        });
+      });
+    },
+
+    handleDeleteFolder(data){
+      this.$confirm(`是否确认删除文件夹 “${data.label}”?`, '提示', {
+        type: 'warning'
+      }).then(() => {
+        checkFolderDeletable(data.id).then(res => {
+          if (res.data.hasChildren || res.data.fileCount > 0) {
+            const msg = res.data.hasChildren
+              ? "该文件夹包含子文件夹,确定要删除吗?"
+              : `该文件夹中有 ${res.data.fileCount || 0} 个文件,确定要删除吗?`;
+
+            this.$confirm(msg, '二次确认', {
+              type: 'warning'
+            }).then(() => {
+              delFolder(data.id).then(() => {
+                this.$modal.msgSuccess("删除成功");
+                this.getFileTree(); // 刷新树
+                this.getList(); // 刷新文件列表
+              });
+            });
+          } else {
+            delFolder(data.id).then(() => {
+              this.$modal.msgSuccess("删除成功");
+              this.getFileTree(); // 刷新树
+              this.getList(); // 刷新文件列表
+            });
+          }
+        }).catch(() => {
+          this.$message.info("已取消删除");
+        });
+      }).catch(() => {
+        this.$message.info("操作已取消");
+      });
+    }
   }
 };
 </script>

+ 4 - 2
xzl-ui/src/views/system/role/index.vue

@@ -39,7 +39,7 @@
           v-model="dateRange"
           style="width: 240px"
           value-format="yyyy-MM-dd"
-          type="daterange"
+          type="dateRange"
           range-separator="-"
           start-placeholder="开始日期"
           end-placeholder="结束日期"
@@ -254,6 +254,7 @@
 <script>
 import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus, deptTreeSelect } from "@/api/system/role";
 import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
+import {parseTime} from "../../../utils/xzl";
 
 export default {
   name: "Role",
@@ -345,6 +346,7 @@ export default {
     this.getList();
   },
   methods: {
+    parseTime,
     /** 查询角色列表 */
     getList() {
       this.loading = true;
@@ -602,4 +604,4 @@ export default {
     }
   }
 };
-</script>
+</script>