feat(qianduan): 重构前端结构并添加新功能
- 新增分类创建功能 - 新增笔记创建功能 - 优化笔记列表展示 - 改进笔记预览界面 - 添加删除笔记功能 - 重构菜单选择逻辑 - 优化文件上传处理 - 更新Markdown编辑器配置
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
package com.test.bijihoudaun.controller;
|
package com.test.bijihoudaun.controller;
|
||||||
|
|
||||||
|
import com.test.bijihoudaun.common.response.R;
|
||||||
import com.test.bijihoudaun.entity.Grouping;
|
import com.test.bijihoudaun.entity.Grouping;
|
||||||
import com.test.bijihoudaun.service.GroupingService;
|
import com.test.bijihoudaun.service.GroupingService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -20,32 +20,32 @@ public class GroupingController {
|
|||||||
|
|
||||||
@Operation(summary = "创建分组")
|
@Operation(summary = "创建分组")
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<Grouping> createGrouping(@RequestBody Grouping grouping) {
|
public R<Grouping> createGrouping(@RequestBody Grouping grouping) {
|
||||||
Grouping created = groupingService.createGrouping(grouping);
|
Grouping created = groupingService.createGrouping(grouping);
|
||||||
return ResponseEntity.ok(created);
|
return R.success(created);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "获取全部分组")
|
@Operation(summary = "获取全部分组")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity<List<Grouping>> getAllGroupings() {
|
public R<List<Grouping>> getAllGroupings() {
|
||||||
List<Grouping> groupings = groupingService.getAllGroupings();
|
List<Grouping> groupings = groupingService.getAllGroupings();
|
||||||
return ResponseEntity.ok(groupings);
|
return R.success(groupings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "更新分组名称")
|
@Operation(summary = "更新分组名称")
|
||||||
@PutMapping("/{id}")
|
@PutMapping("/{id}")
|
||||||
public ResponseEntity<Grouping> updateGrouping(
|
public R<Grouping> updateGrouping(
|
||||||
@PathVariable Long id,
|
@PathVariable Long id,
|
||||||
@RequestBody Grouping grouping) {
|
@RequestBody Grouping grouping) {
|
||||||
grouping.setId(id);
|
grouping.setId(id);
|
||||||
Grouping updated = groupingService.updateGrouping(grouping);
|
Grouping updated = groupingService.updateGrouping(grouping);
|
||||||
return ResponseEntity.ok(updated);
|
return R.success(updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "删除分组")
|
@Operation(summary = "删除分组")
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public ResponseEntity<Void> deleteGrouping(@PathVariable Long id) {
|
public R<Void> deleteGrouping(@PathVariable Long id) {
|
||||||
groupingService.deleteGrouping(id);
|
groupingService.deleteGrouping(id);
|
||||||
return ResponseEntity.noContent().build();
|
return R.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package com.test.bijihoudaun.controller;
|
package com.test.bijihoudaun.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.test.bijihoudaun.common.response.R;
|
||||||
import com.test.bijihoudaun.entity.Image;
|
import com.test.bijihoudaun.entity.Image;
|
||||||
import com.test.bijihoudaun.service.ImageService;
|
import com.test.bijihoudaun.service.ImageService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -29,15 +27,15 @@ public class ImageController {
|
|||||||
@Parameter(name = "file", description = "图片文件", required = true)
|
@Parameter(name = "file", description = "图片文件", required = true)
|
||||||
})
|
})
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<Image> uploadImage(
|
public R<Image> uploadImage(
|
||||||
@RequestParam(required = false) Long markdownId,
|
@RequestParam(required = false) Long markdownId,
|
||||||
@RequestParam("file") MultipartFile file) {
|
@RequestParam("file") MultipartFile file) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Image image = imageService.uploadImage(markdownId, file);
|
Image image = imageService.uploadImage(markdownId, file);
|
||||||
return ResponseEntity.ok(image);
|
return R.success(image);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return ResponseEntity.status(500).build();
|
return R.fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.test.bijihoudaun.entity;
|
|||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -12,6 +13,7 @@ import lombok.Data;
|
|||||||
public class Grouping {
|
public class Grouping {
|
||||||
@Schema(description = "分组id",implementation = Long.class)
|
@Schema(description = "分组id",implementation = Long.class)
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段
|
||||||
private Long id;
|
private Long id;
|
||||||
@Schema(description = "分组名称",implementation = String.class)
|
@Schema(description = "分组名称",implementation = String.class)
|
||||||
private String grouping;
|
private String grouping;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import java.util.Date;
|
|||||||
public class Image {
|
public class Image {
|
||||||
@Schema(description = "图片id",implementation = Long.class)
|
@Schema(description = "图片id",implementation = Long.class)
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段
|
||||||
private Long id;
|
private Long id;
|
||||||
@Schema(description = " 外键,关联Markdown文件ID,标识图片所属文档",implementation = Long.class )
|
@Schema(description = " 外键,关联Markdown文件ID,标识图片所属文档",implementation = Long.class )
|
||||||
private Long markdownId;
|
private Long markdownId;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import java.util.Date;
|
|||||||
public class MarkdownFile {
|
public class MarkdownFile {
|
||||||
@Schema(description = "文本id",implementation = Long.class)
|
@Schema(description = "文本id",implementation = Long.class)
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段
|
||||||
private Long id;
|
private Long id;
|
||||||
@Schema(description = "分组表id",implementation = Long.class)
|
@Schema(description = "分组表id",implementation = Long.class)
|
||||||
private Long groupingId;
|
private Long groupingId;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.test.bijihoudaun.entity;
|
|||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -14,6 +15,7 @@ import java.util.Date;
|
|||||||
public class User {
|
public class User {
|
||||||
@Schema(description = "用户id",implementation = Long.class)
|
@Schema(description = "用户id",implementation = Long.class)
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.STRING) // 仅作用于此字段
|
||||||
private Long id;
|
private Long id;
|
||||||
@Schema(description = "用户名",implementation = String.class)
|
@Schema(description = "用户名",implementation = String.class)
|
||||||
private String username;
|
private String username;
|
||||||
|
|||||||
1
biji-qianduan/.env.development
Normal file
1
biji-qianduan/.env.development
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_API_BASE_URL=/api
|
||||||
1
biji-qianduan/.env.production
Normal file
1
biji-qianduan/.env.production
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_API_BASE_URL=https://liu-pox.311169.xyz
|
||||||
232
biji-qianduan/package-lock.json
generated
232
biji-qianduan/package-lock.json
generated
@@ -8,7 +8,9 @@
|
|||||||
"name": "biji-qianduan",
|
"name": "biji-qianduan",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kangc/v-md-editor": "^2.3.18",
|
"@kangc/v-md-editor": "^2.2.4",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -77,6 +79,87 @@
|
|||||||
"integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==",
|
"integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/autocomplete": {
|
||||||
|
"version": "6.18.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||||
|
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/commands": {
|
||||||
|
"version": "6.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
||||||
|
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.27.0",
|
||||||
|
"@lezer/common": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/language": {
|
||||||
|
"version": "6.11.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
|
||||||
|
"integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/common": "^1.1.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0",
|
||||||
|
"style-mod": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lint": {
|
||||||
|
"version": "6.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
||||||
|
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.35.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/search": {
|
||||||
|
"version": "6.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
||||||
|
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/state": {
|
||||||
|
"version": "6.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/view": {
|
||||||
|
"version": "6.37.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz",
|
||||||
|
"integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.5.0",
|
||||||
|
"crelt": "^1.0.6",
|
||||||
|
"style-mod": "^4.1.0",
|
||||||
|
"w3c-keyname": "^2.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.25.5",
|
"version": "0.25.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
|
||||||
@@ -535,6 +618,51 @@
|
|||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@kangc/v-md-editor/node_modules/codemirror": {
|
||||||
|
"version": "5.65.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz",
|
||||||
|
"integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@kangc/v-md-editor/node_modules/highlight.js": {
|
||||||
|
"version": "10.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||||
|
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/common": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/highlight": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/lr": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@mrmlnc/readdir-enhanced": {
|
"node_modules/@mrmlnc/readdir-enhanced": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
|
||||||
@@ -1076,15 +1204,6 @@
|
|||||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
|
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
|
||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@vuepress/markdown/node_modules/linkify-it": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"uc.micro": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@vuepress/markdown/node_modules/markdown-it": {
|
"node_modules/@vuepress/markdown/node_modules/markdown-it": {
|
||||||
"version": "8.4.2",
|
"version": "8.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
|
||||||
@@ -1396,10 +1515,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "5.65.19",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||||
"integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==",
|
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/commands": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/lint": "^6.0.0",
|
||||||
|
"@codemirror/search": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/collection-visit": {
|
"node_modules/collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -1430,13 +1558,10 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/commander": {
|
"node_modules/commander": {
|
||||||
"version": "8.3.0",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"engines": {
|
|
||||||
"node": ">= 12"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/component-emitter": {
|
"node_modules/component-emitter": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
@@ -1480,6 +1605,12 @@
|
|||||||
"layout-base": "^1.0.0"
|
"layout-base": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/crelt": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/cssfilter": {
|
"node_modules/cssfilter": {
|
||||||
"version": "0.0.10",
|
"version": "0.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
|
||||||
@@ -2620,12 +2751,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/highlight.js": {
|
"node_modules/highlight.js": {
|
||||||
"version": "10.7.3",
|
"version": "11.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
||||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
@@ -2861,6 +2992,15 @@
|
|||||||
"katex": "cli.js"
|
"katex": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/katex/node_modules/commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/khroma": {
|
"node_modules/khroma": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
|
||||||
@@ -2891,9 +3031,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/linkify-it": {
|
"node_modules/linkify-it": {
|
||||||
"version": "3.0.3",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||||
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
|
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"uc.micro": "^1.0.1"
|
"uc.micro": "^1.0.1"
|
||||||
@@ -3023,6 +3163,15 @@
|
|||||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/markdown-it/node_modules/linkify-it": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"uc.micro": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mdast-util-from-markdown": {
|
"node_modules/mdast-util-from-markdown": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz",
|
||||||
@@ -3103,6 +3252,15 @@
|
|||||||
"web-worker": "^1.2.0"
|
"web-worker": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mermaid/node_modules/commander": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mermaid/node_modules/katex": {
|
"node_modules/mermaid/node_modules/katex": {
|
||||||
"version": "0.16.22",
|
"version": "0.16.22",
|
||||||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz",
|
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz",
|
||||||
@@ -4328,6 +4486,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/style-mod": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/stylis": {
|
"node_modules/stylis": {
|
||||||
"version": "4.3.6",
|
"version": "4.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
|
||||||
@@ -4709,6 +4873,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/w3c-keyname": {
|
||||||
|
"version": "2.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/web-worker": {
|
"node_modules/web-worker": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
|
||||||
@@ -4747,12 +4917,6 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"node_modules/xss/node_modules/commander": {
|
|
||||||
"version": "2.20.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kangc/v-md-editor": "^2.3.18",
|
"@kangc/v-md-editor": "^2.2.4",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
|
"highlight.js": "^11.11.1",
|
||||||
"vue": "^3.5.13"
|
"vue": "^3.5.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
47
biji-qianduan/src/api/CommonApi.js
Normal file
47
biji-qianduan/src/api/CommonApi.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import axiosApi from '@/utils/axios.js'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const groupingId = (data) => axiosApi.get(`/api/markdown/grouping/${data}`)
|
||||||
|
// 获取所有分组
|
||||||
|
export const groupingAll = () => axiosApi.get(`/api/groupings`)
|
||||||
|
// 获取所有Markdown文件
|
||||||
|
export const markdownAll = () => axiosApi.get(`/api/markdown`);
|
||||||
|
// 预览markdown文件
|
||||||
|
export const Preview = (id) => axiosApi.get(`/api/markdown/${id}`);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 创建分类分组
|
||||||
|
export const addGroupings = (name) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
if (name) formData.append('grouping', name)
|
||||||
|
return axiosApi.post('/api/groupings', formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MD5哈希
|
||||||
|
export const MD5 = (data, file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
if (data) formData.append('input', data)
|
||||||
|
if (file) formData.append('file', file)
|
||||||
|
return axiosApi.post('/api/common/md5', formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,153 +1,263 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="home-page">
|
<div class="home-page">
|
||||||
<el-container style="height: 100vh;">
|
<div class="container">
|
||||||
<!-- 左侧菜单栏 -->
|
<!-- 左侧菜单区域 -->
|
||||||
<el-aside :width="isCollapsed ? '64px' : '300px'" style="background-color: #f5f7fa; border-right: 1px solid #ebeef5; transition: width 0.3s;">
|
<div class="sidebar">
|
||||||
<div class="sidebar-header" :style="{ justifyContent: isCollapsed ? 'center' : 'space-between' }">
|
<div class="sidebar-header">
|
||||||
<h3 v-if="!isCollapsed">笔记分类</h3>
|
<span>笔记分类</span>
|
||||||
<el-button @click="isCollapsed = !isCollapsed" size="small" type="text">
|
<el-button type="primary" size="small" @click="showCreateGroupDialog = true">
|
||||||
<el-icon v-if="isCollapsed">
|
新建分类
|
||||||
<Expand />
|
|
||||||
</el-icon>
|
|
||||||
<span v-else>收起</span>
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-menu
|
<el-menu
|
||||||
v-show="!isCollapsed"
|
:default-active="activeMenu"
|
||||||
default-active="all"
|
|
||||||
class="el-menu-vertical-demo"
|
class="el-menu-vertical-demo"
|
||||||
|
:collapse="isCollapsed"
|
||||||
@select="handleMenuSelect"
|
@select="handleMenuSelect"
|
||||||
>
|
>
|
||||||
<el-menu-item index="all">
|
|
||||||
<span>全部文档</span>
|
|
||||||
</el-menu-item>
|
|
||||||
|
|
||||||
<el-submenu v-for="group in groupings" :key="group.id" :index="'group-'+group.id">
|
<!-- 分组分类 -->
|
||||||
|
<el-sub-menu v-for="group in groupings" :key="group.id" :index="`group-${group.id}`">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span>{{ group.grouping }}</span>
|
<span>{{ group.grouping }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 分组下的文件 -->
|
||||||
<el-menu-item
|
<el-menu-item
|
||||||
v-for="file in groupFiles[group.id] || []"
|
v-for="file in groupFiles[group.id] || []"
|
||||||
:key="file.id"
|
:key="file.id"
|
||||||
:index="'file-'+file.id"
|
:index="`file-${file.id}`"
|
||||||
>
|
>
|
||||||
{{ file.title }}
|
{{ file.title }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-submenu>
|
</el-sub-menu>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-aside>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧内容区 -->
|
<!-- 右侧内容区域 -->
|
||||||
<el-main style="padding: 20px;">
|
<div class="content">
|
||||||
<div class="header" v-if="!selectedFile">
|
<div v-if="selectedFile" class="file-preview">
|
||||||
|
<div class="preview-header">
|
||||||
|
<h2>{{ selectedFile.title }}</h2>
|
||||||
|
<div class="actions">
|
||||||
|
<el-button type="primary" @click="editNote(selectedFile)">编辑</el-button>
|
||||||
|
<el-button type="danger" @click="deleteNote(selectedFile)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<v-md-preview :text="selectedFile.content" class="markdown-preview"></v-md-preview>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="header">
|
||||||
<h1>我的笔记</h1>
|
<h1>我的笔记</h1>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<el-button type="primary" @click="showEditor = true">新建笔记</el-button>
|
<el-button type="primary" @click="showCreateNoteDialog = true">新建笔记</el-button>
|
||||||
<el-upload
|
<el-upload
|
||||||
|
class="upload-btn"
|
||||||
action=""
|
action=""
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:before-upload="handleMarkdownUpload"
|
:before-upload="handleMarkdownUpload"
|
||||||
accept=".md"
|
accept=".md"
|
||||||
class="upload-btn"
|
|
||||||
>
|
>
|
||||||
<el-button type="success">上传Markdown</el-button>
|
<el-button type="success">上传Markdown</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 文件列表 -->
|
<div v-if="markdownFiles.length > 0" class="file-list">
|
||||||
<div v-if="!selectedFile" class="file-list">
|
<div v-for="file in markdownFiles" :key="file.id" class="file-item">
|
||||||
<div v-for="group in groupings" :key="group.id" class="group-section">
|
<div @click="selectFile(file)" class="file-title">{{ file.title }}</div>
|
||||||
<h3>{{ group.grouping }}</h3>
|
</div>
|
||||||
<ul>
|
</div>
|
||||||
<li v-for="file in groupFiles[group.id]" :key="file.id" @click="selectFile(file)">
|
<div v-else class="empty-tip">暂无笔记,请创建或上传</div>
|
||||||
{{ file.title }}
|
</div>
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedFile" class="file-preview">
|
<!-- 分类创建对话框 -->
|
||||||
<div class="preview-header">
|
<el-dialog v-model="showCreateGroupDialog" title="新建分类" width="30%">
|
||||||
<h2>{{ selectedFile.title }}</h2>
|
<el-form :model="newGroupForm" label-width="80px">
|
||||||
<div>
|
<el-form-item label="分类名称">
|
||||||
<el-button type="primary" @click="editNote(selectedFile)">编辑</el-button>
|
<el-input v-model="newGroupForm.name" autocomplete="off"></el-input>
|
||||||
<el-button @click="selectedFile = null">返回列表</el-button>
|
</el-form-item>
|
||||||
</div>
|
</el-form>
|
||||||
</div>
|
<template #footer>
|
||||||
|
<el-button @click="showCreateGroupDialog = false">取消</el-button>
|
||||||
<div class="markdown-preview">
|
<el-button type="primary" @click="createGrouping">确定</el-button>
|
||||||
<v-md-preview :text="selectedFile.content"></v-md-preview>
|
</template>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-main>
|
|
||||||
</el-container>
|
|
||||||
|
|
||||||
<el-dialog v-model="showEditor" title="Markdown编辑器" width="80%">
|
|
||||||
<MarkdownEditor v-if="showEditor" :fileId="currentFileId" @close="showEditor = false" />
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 笔记创建对话框 -->
|
||||||
|
<el-dialog v-model="showCreateNoteDialog" title="新建笔记" width="30%">
|
||||||
|
<el-form :model="newNoteForm" label-width="80px">
|
||||||
|
<el-form-item label="笔记标题">
|
||||||
|
<el-input v-model="newNoteForm.title" autocomplete="off"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="选择分类">
|
||||||
|
<el-select v-model="newNoteForm.groupingId" placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="group in groupings"
|
||||||
|
:key="group.id"
|
||||||
|
:label="group.name"
|
||||||
|
:value="group.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showCreateNoteDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="createNote">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- Markdown编辑器 -->
|
||||||
|
<markdown-editor
|
||||||
|
v-if="showEditor"
|
||||||
|
:file-id="currentFileId"
|
||||||
|
@close="showEditor = false"
|
||||||
|
@saved="handleNoteSaved"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import axios from 'axios';
|
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { Expand } from '@element-plus/icons-vue';
|
import MarkdownEditor from '@/components/MarkdownEditor.vue';
|
||||||
import MarkdownEditor from './MarkdownEditor.vue';
|
|
||||||
import VMdPreview from '@kangc/v-md-editor/lib/preview';
|
import VMdPreview from '@kangc/v-md-editor/lib/preview';
|
||||||
import '@kangc/v-md-editor/lib/style/preview.css';
|
import '@kangc/v-md-editor/lib/style/preview.css';
|
||||||
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js';
|
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js';
|
||||||
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
||||||
|
import {groupingId, groupingAll, markdownAll, addGroupings, Preview} from '@/api/CommonApi.js'
|
||||||
|
|
||||||
VMdPreview.use(githubTheme);
|
VMdPreview.use(githubTheme);
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
MarkdownEditor,
|
|
||||||
[VMdPreview.name]: VMdPreview,
|
|
||||||
Expand
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
const API_BASE_URL = 'http://localhost:8084';
|
|
||||||
const markdownFiles = ref([]);
|
const markdownFiles = ref([]);
|
||||||
const groupings = ref([]);
|
const groupings = ref([]);
|
||||||
const groupFiles = ref({});
|
const groupFiles = ref({});
|
||||||
const showEditor = ref(false);
|
const showEditor = ref(false);
|
||||||
const currentFileId = ref(null);
|
const currentFileId = ref(null);
|
||||||
const selectedFile = ref(null);
|
const selectedFile = ref(null);
|
||||||
|
const activeMenu = ref('all');
|
||||||
const isCollapsed = ref(false);
|
const isCollapsed = ref(false);
|
||||||
|
const showCreateGroupDialog = ref(false);
|
||||||
|
const showCreateNoteDialog = ref(false);
|
||||||
|
const newGroupForm = ref({ name: '' });
|
||||||
|
const newNoteForm = ref({ title: '', groupingId: null });
|
||||||
|
|
||||||
// 获取所有分组
|
// 获取所有分组
|
||||||
const fetchGroupings = async () => {
|
const fetchGroupings = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${API_BASE_URL}/api/groupings`);
|
const response = await groupingAll()
|
||||||
groupings.value = response.data;
|
// 确保分组数据是数组
|
||||||
|
groupings.value = response.data
|
||||||
// 为每个分组获取文件
|
// 为每个分组获取文件
|
||||||
for (const group of groupings.value) {
|
for (const group of groupings.value) {
|
||||||
const filesRes = await axios.get(`${API_BASE_URL}/api/markdown/grouping/${group.id}`);
|
try {
|
||||||
groupFiles.value[group.id] = filesRes.data;
|
const filesRes = await groupingId(group.id);
|
||||||
|
// 确保文件ID为字符串
|
||||||
|
groupFiles.value[group.id] = (filesRes.data).map(file => ({
|
||||||
|
...file,
|
||||||
|
id: file.id
|
||||||
|
}));
|
||||||
|
} catch (fileError) {
|
||||||
|
console.error(`获取分组 ${group.id} 文件失败:`, fileError);
|
||||||
|
groupFiles.value[group.id] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加"全部"分类 (ID=1)
|
||||||
|
if (!groupings.value.some(g => g.id === 1)) {
|
||||||
|
// groupings.value.unshift({ id: 1, name: '全部' });
|
||||||
|
// 获取所有文件作为"全部"分类的内容
|
||||||
|
try {
|
||||||
|
const allFilesRes = await markdownAll()
|
||||||
|
groupFiles.value[1] = (allFilesRes.data).map(file => ({
|
||||||
|
...file,
|
||||||
|
id: file.id
|
||||||
|
}));
|
||||||
|
} catch (allFilesError) {
|
||||||
|
console.error('获取全部笔记失败:', allFilesError);
|
||||||
|
groupFiles.value[1] = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取分组失败: ' + error.message);
|
console.error('获取分组失败:', error);
|
||||||
|
ElMessage.error('获取分组失败: ' + (error.response?.data?.message || error.message));
|
||||||
|
groupings.value = [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取所有Markdown文件
|
// 获取所有Markdown文件(确保ID为字符串)
|
||||||
const fetchMarkdownFiles = async () => {
|
const fetchMarkdownFiles = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${API_BASE_URL}/api/markdown`);
|
const response = await markdownAll()
|
||||||
markdownFiles.value = response.data;
|
// 确保文件ID为字符串
|
||||||
|
markdownFiles.value = (response.data || []).map(file => ({
|
||||||
|
...file,
|
||||||
|
id: String(file.id)
|
||||||
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取笔记列表失败: ' + error.message);
|
ElMessage.error('获取笔记列表失败: ' + error.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 创建新分类
|
||||||
|
const createGrouping = async () => {
|
||||||
|
try {
|
||||||
|
const response = await addGroupings(newGroupForm.value.name)
|
||||||
|
ElMessage.success('分类创建成功');
|
||||||
|
showCreateGroupDialog.value = false;
|
||||||
|
newGroupForm.value.name = '';
|
||||||
|
fetchGroupings();
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('创建分类失败: ' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建新笔记
|
||||||
|
const createNote = async () => {
|
||||||
|
try {
|
||||||
|
await axios.post(`${API_BASE_URL}/api/markdown`, '# 新笔记内容', {
|
||||||
|
params: {
|
||||||
|
groupingId: newNoteForm.value.groupingId,
|
||||||
|
title: newNoteForm.value.title,
|
||||||
|
fileName: newNoteForm.value.title
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ElMessage.success('笔记创建成功');
|
||||||
|
showCreateNoteDialog.value = false;
|
||||||
|
newNoteForm.value = { title: '', groupingId: null };
|
||||||
|
await fetchMarkdownFiles();
|
||||||
|
await fetchGroupings();
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('创建笔记失败: ' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 选择文件预览
|
// 选择文件预览
|
||||||
const selectFile = (file) => {
|
const selectFile = async (file) => {
|
||||||
selectedFile.value = file;
|
try {
|
||||||
|
const response = await Preview(file.id)
|
||||||
|
|
||||||
|
// 确保内容为字符串
|
||||||
|
let content = response.data;
|
||||||
|
if (typeof content !== 'string') {
|
||||||
|
// 如果返回的是对象,尝试转换为字符串
|
||||||
|
if (content && typeof content === 'object') {
|
||||||
|
content = JSON.stringify(content);
|
||||||
|
} else {
|
||||||
|
content = String(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedFile.value = {
|
||||||
|
...file,
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取笔记内容失败: ' + error.message);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 编辑笔记
|
// 编辑笔记
|
||||||
@@ -156,13 +266,25 @@ export default {
|
|||||||
showEditor.value = true;
|
showEditor.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 笔记保存后处理
|
||||||
|
const handleNoteSaved = () => {
|
||||||
|
showEditor.value = false;
|
||||||
|
fetchMarkdownFiles();
|
||||||
|
fetchGroupings();
|
||||||
|
|
||||||
|
if (selectedFile.value) {
|
||||||
|
selectFile(selectedFile.value); // 刷新当前预览内容
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 删除笔记
|
// 删除笔记
|
||||||
const deleteNote = async (file) => {
|
const deleteNote = async (file) => {
|
||||||
try {
|
try {
|
||||||
await axios.delete(`${API_BASE_URL}/api/markdown/${file.id}`);
|
await axios.delete(`${API_BASE_URL}/api/markdown/${file.id}`);
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
|
selectedFile.value = null;
|
||||||
fetchMarkdownFiles();
|
fetchMarkdownFiles();
|
||||||
fetchGroupings(); // 重新加载分组和文件
|
fetchGroupings();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('删除失败: ' + error.message);
|
ElMessage.error('删除失败: ' + error.message);
|
||||||
}
|
}
|
||||||
@@ -172,13 +294,20 @@ export default {
|
|||||||
const handleMenuSelect = (index) => {
|
const handleMenuSelect = (index) => {
|
||||||
if (index === 'all') {
|
if (index === 'all') {
|
||||||
selectedFile.value = null;
|
selectedFile.value = null;
|
||||||
|
activeMenu.value = 'all';
|
||||||
} else if (index.startsWith('file-')) {
|
} else if (index.startsWith('file-')) {
|
||||||
const fileId = index.split('-')[1];
|
const fileId = index.split('-')[1];
|
||||||
const file = markdownFiles.value.find(f => f.id == fileId);
|
// 确保markdownFiles.value是数组
|
||||||
|
if (Array.isArray(markdownFiles.value)) {
|
||||||
|
const file = markdownFiles.value.find(f => f.id === fileId);
|
||||||
if (file) {
|
if (file) {
|
||||||
selectFile(file);
|
selectFile(file);
|
||||||
|
activeMenu.value = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (index.startsWith('group-')) {
|
||||||
|
activeMenu.value = index;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 上传Markdown文件处理
|
// 上传Markdown文件处理
|
||||||
@@ -189,13 +318,12 @@ export default {
|
|||||||
const fileName = file.name.replace('.md', '');
|
const fileName = file.name.replace('.md', '');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams();
|
|
||||||
params.append('userId', '1');
|
|
||||||
params.append('title', fileName);
|
|
||||||
params.append('fileName', fileName);
|
|
||||||
|
|
||||||
await axios.post(`${API_BASE_URL}/api/markdown`, content, {
|
await axios.post(`${API_BASE_URL}/api/markdown`, content, {
|
||||||
params: params,
|
params: {
|
||||||
|
groupingId: 1, // 默认放入"全部"分类
|
||||||
|
title: fileName,
|
||||||
|
fileName: fileName
|
||||||
|
},
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'text/plain'
|
'Content-Type': 'text/plain'
|
||||||
}
|
}
|
||||||
@@ -203,7 +331,7 @@ export default {
|
|||||||
|
|
||||||
ElMessage.success('上传成功');
|
ElMessage.success('上传成功');
|
||||||
fetchMarkdownFiles();
|
fetchMarkdownFiles();
|
||||||
fetchGroupings(); // 重新加载分组和文件
|
fetchGroupings();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('上传失败: ' + error.message);
|
ElMessage.error('上传失败: ' + error.message);
|
||||||
}
|
}
|
||||||
@@ -216,38 +344,42 @@ export default {
|
|||||||
fetchMarkdownFiles();
|
fetchMarkdownFiles();
|
||||||
fetchGroupings();
|
fetchGroupings();
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
markdownFiles,
|
|
||||||
groupings,
|
|
||||||
groupFiles,
|
|
||||||
showEditor,
|
|
||||||
currentFileId,
|
|
||||||
selectedFile,
|
|
||||||
isCollapsed,
|
|
||||||
selectFile,
|
|
||||||
editNote,
|
|
||||||
deleteNote,
|
|
||||||
handleMarkdownUpload,
|
|
||||||
handleMenuSelect
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.home-page {
|
.home-page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 280px;
|
||||||
|
background: #fff;
|
||||||
|
border-right: 1px solid #e6e6e6;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
|
padding: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 15px;
|
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
height: 100vh;
|
||||||
|
margin-left: 20px;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -262,68 +394,68 @@ export default {
|
|||||||
|
|
||||||
.upload-btn {
|
.upload-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-list {
|
.file-list {
|
||||||
margin-top: 20px;
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-section {
|
.file-item {
|
||||||
margin-bottom: 20px;
|
background: #fff;
|
||||||
}
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
.group-section h3 {
|
padding: 15px;
|
||||||
margin-bottom: 10px;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-section ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-section li {
|
|
||||||
padding: 8px 0;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-section li:hover {
|
.file-item:hover {
|
||||||
background-color: #f5f7fa;
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-tip {
|
||||||
|
text-align: center;
|
||||||
|
padding: 50px;
|
||||||
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-preview {
|
.file-preview {
|
||||||
|
height: 100vh;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-header {
|
.preview-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-preview {
|
.markdown-preview {
|
||||||
min-height: 500px;
|
flex: 1;
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修复菜单折叠样式 */
|
|
||||||
.el-menu-vertical-demo {
|
.el-menu-vertical-demo {
|
||||||
height: calc(100vh - 60px);
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.sidebar-header {
|
|
||||||
height: 60px;
|
.el-menu-vertical-demo:not(.el-menu--collapse) {
|
||||||
display: flex;
|
width: 100%;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,18 +1,33 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router/'
|
||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
|
|
||||||
import VMdEditor from '@kangc/v-md-editor';
|
import VMdEditor from '@kangc/v-md-editor';
|
||||||
import '@kangc/v-md-editor/lib/style/base-editor.css';
|
import '@kangc/v-md-editor/lib/style/base-editor.css';
|
||||||
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
|
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js';
|
||||||
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
|
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
||||||
|
|
||||||
|
import VMdPreview from '@kangc/v-md-editor/lib/preview';
|
||||||
|
import '@kangc/v-md-editor/lib/style/preview.css';
|
||||||
|
import '@kangc/v-md-editor/lib/theme/style/github.css';
|
||||||
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
// 配置Markdown编辑器
|
// highlightjs
|
||||||
VMdEditor.use(vuepressTheme);
|
import hljs from 'highlight.js';
|
||||||
|
VMdEditor.use(githubTheme, {
|
||||||
|
Hljs: hljs,
|
||||||
|
});
|
||||||
|
VMdPreview.use(githubTheme, {
|
||||||
|
Hljs: hljs,
|
||||||
|
});
|
||||||
|
|
||||||
|
// // 配置Markdown编辑器
|
||||||
app.use(VMdEditor);
|
app.use(VMdEditor);
|
||||||
|
app.use(VMdPreview);
|
||||||
|
|
||||||
// 使用Element Plus和路由
|
// 使用Element Plus和路由
|
||||||
app.use(ElementPlus)
|
app.use(ElementPlus)
|
||||||
|
|||||||
10
biji-qianduan/src/utils/URIComponent.js
Normal file
10
biji-qianduan/src/utils/URIComponent.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* 处理参数的其他处理逻辑,如编码、格式化等
|
||||||
|
* @param data
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const handleCopy =(data) =>{
|
||||||
|
return encodeURIComponent( data)
|
||||||
|
};
|
||||||
|
|
||||||
|
export default handleCopy;
|
||||||
32
biji-qianduan/src/utils/axios.js
Normal file
32
biji-qianduan/src/utils/axios.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||||
|
// 开发环境使用withCredentials,生产环境关闭
|
||||||
|
withCredentials: import.meta.env.DEV,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 请求拦截器
|
||||||
|
instance.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 响应拦截器
|
||||||
|
instance.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default instance
|
||||||
11
biji-qianduan/src/utils/deviceDetector.js
Normal file
11
biji-qianduan/src/utils/deviceDetector.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* 设备检测工具
|
||||||
|
*/
|
||||||
|
export function detectDeviceType() {
|
||||||
|
// 基础检测(User Agent)
|
||||||
|
const ua = navigator.userAgent;
|
||||||
|
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
|
||||||
|
|
||||||
|
|
||||||
|
return isMobile ? 'mobile' : 'desktop';
|
||||||
|
}
|
||||||
55
biji-qianduan/src/utils/handleCopy.js
Normal file
55
biji-qianduan/src/utils/handleCopy.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* 处理复制
|
||||||
|
* @param data
|
||||||
|
* @param message
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
const handleCopy = async (data, message) => {
|
||||||
|
// 检查是否在安全上下文中 (HTTPS 或 localhost)
|
||||||
|
const isSecureContext = window.isSecureContext || location.protocol === 'https:';
|
||||||
|
|
||||||
|
if (isSecureContext) {
|
||||||
|
try {
|
||||||
|
// 使用现代剪贴板 API
|
||||||
|
await navigator.clipboard.writeText(data);
|
||||||
|
message.success('已复制到剪贴板');
|
||||||
|
} catch (err) {
|
||||||
|
message.error('现代剪贴板API错误:', err);
|
||||||
|
useFallbackCopy(data, message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非安全上下文直接使用回退方法
|
||||||
|
useFallbackCopy(data, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回退复制方法
|
||||||
|
function useFallbackCopy(data, message) {
|
||||||
|
try {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = data;
|
||||||
|
|
||||||
|
// 设置样式确保元素在视口外但可交互
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.top = '0';
|
||||||
|
textarea.style.left = '0';
|
||||||
|
textarea.style.opacity = '0';
|
||||||
|
textarea.style.pointerEvents = 'none';
|
||||||
|
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
|
||||||
|
// 尝试执行复制
|
||||||
|
const success = document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
message.success('已复制');
|
||||||
|
} else {
|
||||||
|
throw new Error('回退复制方法失败');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
message.error('复制失败,请手动复制内容');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default handleCopy
|
||||||
@@ -1,7 +1,31 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:8084',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(/^\/api/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
minify: 'terser',
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
drop_console: true,
|
||||||
|
drop_debugger: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
BIN
mydatabase.db
BIN
mydatabase.db
Binary file not shown.
Reference in New Issue
Block a user