diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ README.md b/README.md similarity index 95% rename from README.md rename to README.md index 15f8f19..00e699a 100644 --- a/ README.md +++ b/README.md @@ -79,3 +79,9 @@ server: ``` +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 +4. 新建 Pull Request \ No newline at end of file diff --git a/driver/src/main/java/xyz/longicorn/driver/controller/FolderController.java b/driver/src/main/java/xyz/longicorn/driver/controller/FolderController.java index 664c9f7..0b17e4b 100644 --- a/driver/src/main/java/xyz/longicorn/driver/controller/FolderController.java +++ b/driver/src/main/java/xyz/longicorn/driver/controller/FolderController.java @@ -4,15 +4,16 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import xyz.longicorn.driver.dto.ApiResult; +import xyz.longicorn.driver.dto.FileItem; +import xyz.longicorn.driver.dto.FolderDto; import xyz.longicorn.driver.pojo.FolderInfo; import xyz.longicorn.driver.service.FolderService; import javax.annotation.Resource; import java.util.List; +import java.util.Map; @RestController @RequestMapping("/api/folder") @@ -23,14 +24,20 @@ public class FolderController { @RequestMapping("/list") //接口文档的名称 - @ApiOperation(value = "查询目录信息", notes = "查询相应目录下的所有文件(夹)信息",httpMethod = "GET") + @ApiOperation(value = "查询目录信息", notes = "查询相应目录下的所有文件(夹)信息", httpMethod = "GET") public ApiResult listFolder(@RequestParam(required = false, defaultValue = "/") String folderPath) { - return ApiResult.success(folderService.listFolder(1, folderPath)); + return ApiResult.success( + folderService.listFolder(1, folderPath) + ); } // 创建目录 + @PostMapping("/create") @ApiOperation(value = "创建目录", notes = "创建目录1") - public FolderInfo create(String parent, String name) { - return null; + public ApiResult create(@RequestBody FolderDto f) { + String parent = f.getParent(), name = f.getName(); + return ApiResult.success( + folderService.create(1, parent, name) + ); } } diff --git a/driver/src/main/java/xyz/longicorn/driver/dao/FileInfoMapper.java b/driver/src/main/java/xyz/longicorn/driver/dao/FileInfoMapper.java new file mode 100644 index 0000000..ecc3b54 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/dao/FileInfoMapper.java @@ -0,0 +1,10 @@ +package xyz.longicorn.driver.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import xyz.longicorn.driver.pojo.FileInfo; +import xyz.longicorn.driver.pojo.FolderInfo; + +@Mapper +public interface FileInfoMapper extends BaseMapper { +} diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java b/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java new file mode 100644 index 0000000..54c5de0 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/dto/FileItem.java @@ -0,0 +1,69 @@ +package xyz.longicorn.driver.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import xyz.longicorn.driver.pojo.FileInfo; +import xyz.longicorn.driver.pojo.FolderInfo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** + * 文件项 可以是文件也可以是目录 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class FileItem { + private Long id; + private String name; + private Integer size; + private String path; + private Date createTime; + private Date updateTime; + private String type; + + public static List buildFolderList(List list) { + List listItems = new ArrayList<>(); + list.forEach(f -> listItems.add(build(f))); + return listItems; + } + + public static FileItem build(FolderInfo f) { + return new FileItem() + .setCreateTime(f.getCreateTime()) + .setId(f.getId()) + .setName(f.getName()) + .setSize(0) + .setType("folder") + .setPath(f.getPath()) + .setUpdateTime(f.getUpdateTime()); + } + + public static List buildFileList(List list) { + List listItems = new ArrayList<>(); + list.forEach(f -> listItems.add(build(f))); + return listItems; + } + + /** + * 将文件转成fileItem + * @param f + * @return + */ + public static FileItem build(FileInfo f) { + return new FileItem() + .setCreateTime(f.getCreateTime()) + .setId(f.getId()) + .setName(f.getName()) + .setSize(f.getSize()) + .setType(f.getType()) + .setPath(f.getPath()) + .setUpdateTime(f.getUpdateTime()); + } +} diff --git a/driver/src/main/java/xyz/longicorn/driver/dto/FolderDto.java b/driver/src/main/java/xyz/longicorn/driver/dto/FolderDto.java new file mode 100644 index 0000000..cefbd76 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/dto/FolderDto.java @@ -0,0 +1,9 @@ +package xyz.longicorn.driver.dto; + +import lombok.Data; + +@Data +public class FolderDto { + private String parent; + private String name; +} diff --git a/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java b/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java new file mode 100644 index 0000000..d17faa3 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/pojo/FileInfo.java @@ -0,0 +1,32 @@ +package xyz.longicorn.driver.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import io.swagger.models.auth.In; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@ToString +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class FileInfo implements Serializable { + private Long id; + private Long uid; + private String name; + private String hash; + private Long folderId; + private String type; + private Integer size; + private String path; + private Date createTime; + private Date updateTime; + private Long status; +} diff --git a/driver/src/main/java/xyz/longicorn/driver/service/FileService.java b/driver/src/main/java/xyz/longicorn/driver/service/FileService.java new file mode 100644 index 0000000..00c5812 --- /dev/null +++ b/driver/src/main/java/xyz/longicorn/driver/service/FileService.java @@ -0,0 +1,26 @@ +package xyz.longicorn.driver.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; +import xyz.longicorn.driver.dao.FileInfoMapper; +import xyz.longicorn.driver.pojo.FileInfo; + +import java.util.List; + +@Service +public class FileService extends ServiceImpl { + /** + * 查询了目录下的文件列表集合 + * @param uid + * @param folderId + * @return + */ + public List listByFolderId(int uid,long folderId){ + QueryWrapper q = new QueryWrapper(); + q.eq("uid",uid); + q.eq("folder_id",folderId); + q.eq("status",1); // TODO 枚举 + return this.list(q); + } +} diff --git a/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java b/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java index ebbb766..9ae8035 100644 --- a/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java +++ b/driver/src/main/java/xyz/longicorn/driver/service/FolderService.java @@ -5,12 +5,26 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import xyz.longicorn.driver.config.BizException; import xyz.longicorn.driver.dao.FolderInfoMapper; +import xyz.longicorn.driver.dto.FileItem; +import xyz.longicorn.driver.pojo.FileInfo; import xyz.longicorn.driver.pojo.FolderInfo; +import javax.annotation.Resource; +import java.util.ArrayList; import java.util.List; @Service public class FolderService extends ServiceImpl { + @Resource + private FileService fileService; + + /** + * 根据路径查询目录信息 + * + * @param uid + * @param path + * @return + */ public FolderInfo getByPath(int uid, String path) { QueryWrapper q = new QueryWrapper(); q.eq("uid", uid); @@ -18,7 +32,23 @@ public class FolderService extends ServiceImpl { return this.getOne(q); } - public List listFolder(int uid, String path) { + /** + * 根据目录的名称查询信息 + * + * @param uid + * @param name + * @param parentId + * @return + */ + public FolderInfo getByNameAndParent(int uid, String name, long parentId) { + QueryWrapper q = new QueryWrapper(); + q.eq("uid", uid); + q.eq("name", name); + q.eq("parent_id", parentId); + return this.getOne(q); + } + + public List listFolder(int uid, String path) { long parentId = 0; // 默认查询根目录 // 路径为空或者 / 表示根目录 if (path != null && !path.equals("/")) { @@ -29,12 +59,34 @@ public class FolderService extends ServiceImpl { QueryWrapper q = new QueryWrapper(); q.eq("parent_id", parentId); // 设置查询条件 q.eq("uid", uid); - return this.list(q); + // 查询目录集合 + final List folderList = this.list(q); + List fsList = FileItem.buildFolderList(folderList); // 直接将folder集合转成fileitem集合 + + final List fileInfos = fileService.listByFolderId(uid, parentId);//文件信息 + fsList.addAll(FileItem.buildFileList(fileInfos)); // 合并目录和文件 + return fsList; } - public FolderInfo create() { - // 验证是否存在相同路径的文件夹 -// if(xxx) throw new RuntimeException("创建失败,名称相同l") - return null; + + public FolderInfo create(int uid, String parent, String name) { + long parentId = 0; // 默认根目录 + if (parent != null && !parent.equals("/")) { + FolderInfo f = this.getByPath(uid, parent); // 根据路径查询目录信息 + if (f == null) throw BizException.create("父目录不存在"); // 没有查询到信息 + parentId = f.getId(); // 设置查询的父目录id + } + // 根据目录查询是否存在 + FolderInfo myFolderInfo = this.getByNameAndParent(uid, name, parentId);//根据名称查询目录信息 + if (myFolderInfo != null) { + throw BizException.create("文件夹已经存在了"); + } + FolderInfo fNew = new FolderInfo(); + fNew.setUid(uid); + fNew.setName(name); + fNew.setParentId(parentId); + fNew.setPath(parent + "/" + name); + ; + return this.save(fNew) ? fNew : null; } } diff --git a/driver/src/main/resources/db.sql b/driver/src/main/resources/db.sql index b206b04..722bf57 100644 --- a/driver/src/main/resources/db.sql +++ b/driver/src/main/resources/db.sql @@ -12,4 +12,20 @@ create table folder_info index ix_name (name), index ix_path (path), index ix_uid (uid) +); + +# 编号、用户编号、文件名、目录编号 、类型、大小、位置、创建时间、状态、hash +create table file_info( + id bigint(20) not null primary key auto_increment, + uid int(10) not null, + name varchar(50) not null, + hash varchar(32) not null comment '文件MD5特征码', + folder_id bigint(20) null default 0 comment '所在目录的编号,0表示根目录', + type varchar(5) null, + size int null default 0, + path varchar(500) not null comment '文件的物理存储位置,可以是本地路径也可以是一个网址', -- file://d:/a/b/c.txt http:// + create_time datetime default current_timestamp, + update_time datetime on update current_timestamp, + status tinyint(1) default 1, + index ix_file_name(name) ); \ No newline at end of file diff --git a/web/index.html b/web/index.html index 2ad38c2..b72e4b2 100644 --- a/web/index.html +++ b/web/index.html @@ -2,7 +2,7 @@ - + 天牛网盘 diff --git a/web/package-lock.json b/web/package-lock.json index 31a2c35..aaad2da 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -14,7 +14,8 @@ "less-loader": "^10.2.0", "qs": "^6.10.3", "vue": "^3.2.25", - "vue-router": "^4.0.15" + "vue-router": "^4.0.15", + "vue-simple-context-menu": "^4.0.2" }, "devDependencies": { "@vitejs/plugin-vue": "^2.3.1", @@ -539,6 +540,14 @@ "node": ">=6.0" } }, + "node_modules/click-outside-vue3": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/click-outside-vue3/-/click-outside-vue3-4.0.1.tgz", + "integrity": "sha512-sbplNecrup5oGqA3o4bo8XmvHRT6q9fvw21Z67aDbTqB9M6LF7CuYLTlLvNtOgKU6W3zst5H5zJuEh4auqA34g==", + "engines": { + "node": ">=6" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", @@ -1799,6 +1808,17 @@ "vue": "^3.2.0" } }, + "node_modules/vue-simple-context-menu": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/vue-simple-context-menu/-/vue-simple-context-menu-4.0.2.tgz", + "integrity": "sha512-3DcKuNtEZkh6Gi70NIODTXvPlHnVJgyg3ejXNqVHFWTRWSGoZsfeqZKAfSRANAPLshEhUGcVzT4kTPrXvC5WNQ==", + "dependencies": { + "click-outside-vue3": "^4.0.1" + }, + "peerDependencies": { + "vue": "^3.2.31" + } + }, "node_modules/watchpack": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.3.1.tgz", @@ -2337,6 +2357,11 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "peer": true }, + "click-outside-vue3": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/click-outside-vue3/-/click-outside-vue3-4.0.1.tgz", + "integrity": "sha512-sbplNecrup5oGqA3o4bo8XmvHRT6q9fvw21Z67aDbTqB9M6LF7CuYLTlLvNtOgKU6W3zst5H5zJuEh4auqA34g==" + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", @@ -3193,6 +3218,14 @@ "@vue/devtools-api": "^6.0.0" } }, + "vue-simple-context-menu": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/vue-simple-context-menu/-/vue-simple-context-menu-4.0.2.tgz", + "integrity": "sha512-3DcKuNtEZkh6Gi70NIODTXvPlHnVJgyg3ejXNqVHFWTRWSGoZsfeqZKAfSRANAPLshEhUGcVzT4kTPrXvC5WNQ==", + "requires": { + "click-outside-vue3": "^4.0.1" + } + }, "watchpack": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.3.1.tgz", diff --git a/web/package.json b/web/package.json index 3200035..d1023f6 100644 --- a/web/package.json +++ b/web/package.json @@ -14,7 +14,8 @@ "less-loader": "^10.2.0", "qs": "^6.10.3", "vue": "^3.2.25", - "vue-router": "^4.0.15" + "vue-router": "^4.0.15", + "vue-simple-context-menu": "^4.0.2" }, "devDependencies": { "@vitejs/plugin-vue": "^2.3.1", diff --git a/web/public/logo.svg b/web/public/logo.svg new file mode 100644 index 0000000..6736ab0 --- /dev/null +++ b/web/public/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/web/src/Main.vue b/web/src/Main.vue index c2ea036..d3cc5a8 100644 --- a/web/src/Main.vue +++ b/web/src/Main.vue @@ -1,147 +1,360 @@ \ No newline at end of file diff --git a/web/src/main.js b/web/src/main.js index a665943..9a487a2 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -1,11 +1,16 @@ -import { createApp } from "vue"; +import {createApp} from "vue"; // 导入element-plus的依赖 import ElementPlus from "element-plus"; import "element-plus/dist/index.css"; +import './assets/main.less' + +import ContextMenu from 'vue-simple-context-menu' +import 'vue-simple-context-menu/dist/vue-simple-context-menu.css'; // 导入入口组件 import App from "./Main.vue"; -createApp(App) - .use(ElementPlus) +const app = createApp(App) +app.component('ContextMenu', ContextMenu); +app.use(ElementPlus) .mount("#app"); diff --git a/web/src/service/api.js b/web/src/service/api.js index cd2f48a..d29c550 100644 --- a/web/src/service/api.js +++ b/web/src/service/api.js @@ -1,4 +1,3 @@ - const API_PATH = "http://localhost:8080" /** @@ -64,6 +63,9 @@ export default { */ list(folderPath = '/') { return request(`/api/folder/list`, 'GET', {folderPath}) + }, + create(parent, name) { + return request(`/api/folder/create`, 'POST', {parent, name}); } } } \ No newline at end of file diff --git a/web/src/service/type.d.ts b/web/src/service/type.d.ts index e282031..dcf406d 100644 --- a/web/src/service/type.d.ts +++ b/web/src/service/type.d.ts @@ -1 +1,10 @@ -declare type ApiResult = { code: number, message: string, data: any } \ No newline at end of file +declare type ApiResult = { code: number, message: string, data: any } +declare type FileItem = { + createTime: string, + id: number, + name: string, + path: string, + size: number, + type: 'folder' | string, + updateTime: string +} \ No newline at end of file