Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
yubinCloud
fairy-wiki
提交
0596afaf
F
fairy-wiki
项目概览
yubinCloud
/
fairy-wiki
通知
4
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
fairy-wiki
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
0596afaf
编写于
4月 23, 2021
作者:
yubinCloud
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8-3 从分类管理复制出文档管理的前后端代码
遗留问题:编辑表单时,只能选择一级文档作为父文档
上级
3ab76dbf
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
487 addition
and
0 deletion
+487
-0
src/main/java/io/github/yubincloud/fairywiki/controller/DocController.java
...github/yubincloud/fairywiki/controller/DocController.java
+57
-0
src/main/java/io/github/yubincloud/fairywiki/dto/req/DocQueryReqDto.java
...o/github/yubincloud/fairywiki/dto/req/DocQueryReqDto.java
+10
-0
src/main/java/io/github/yubincloud/fairywiki/dto/req/DocSaveReqDto.java
...io/github/yubincloud/fairywiki/dto/req/DocSaveReqDto.java
+29
-0
src/main/java/io/github/yubincloud/fairywiki/dto/resp/DocQueryRespDto.java
...github/yubincloud/fairywiki/dto/resp/DocQueryRespDto.java
+20
-0
src/main/java/io/github/yubincloud/fairywiki/service/DocService.java
...va/io/github/yubincloud/fairywiki/service/DocService.java
+83
-0
web/src/models.ts
web/src/models.ts
+21
-0
web/src/router/index.ts
web/src/router/index.ts
+6
-0
web/src/views/admin/admin-doc.vue
web/src/views/admin/admin-doc.vue
+256
-0
web/src/views/admin/admin-ebook.vue
web/src/views/admin/admin-ebook.vue
+5
-0
未找到文件。
src/main/java/io/github/yubincloud/fairywiki/controller/DocController.java
0 → 100644
浏览文件 @
0596afaf
package
io.github.yubincloud.fairywiki.controller
;
import
io.github.yubincloud.fairywiki.dto.req.DocQueryReqDto
;
import
io.github.yubincloud.fairywiki.dto.req.DocSaveReqDto
;
import
io.github.yubincloud.fairywiki.dto.resp.DocQueryRespDto
;
import
io.github.yubincloud.fairywiki.dto.resp.ErrorCode
;
import
io.github.yubincloud.fairywiki.dto.resp.PageRespDto
;
import
io.github.yubincloud.fairywiki.dto.resp.RestfulModel
;
import
io.github.yubincloud.fairywiki.service.DocService
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
javax.validation.Valid
;
import
java.util.List
;
@RestController
@RequestMapping
(
"/doc"
)
public
class
DocController
{
@Resource
private
DocService
docService
;
/**
* 获取全部 Doc 的接口
*/
@GetMapping
(
"/all"
)
public
RestfulModel
<
List
<
DocQueryRespDto
>>
allCategories
()
{
List
<
DocQueryRespDto
>
docList
=
docService
.
fetchAllCategories
();
return
new
RestfulModel
<>(
ErrorCode
.
SUCCESS
,
""
,
docList
);
}
/**
* 对 doc 进行查询的接口
* @param docQueryReqDto 查询条件的参数
* @return 查询到的所有doc
*/
@GetMapping
(
"/query"
)
public
RestfulModel
<
PageRespDto
<
DocQueryRespDto
>>
queryDocs
(
@Valid
DocQueryReqDto
docQueryReqDto
)
{
PageRespDto
<
DocQueryRespDto
>
bookList
=
docService
.
queryDocs
(
docQueryReqDto
);
return
new
RestfulModel
<>(
ErrorCode
.
SUCCESS
,
""
,
bookList
);
}
/**
* 根据请求的参数保存一个 doc,若id非空则为更新,否则为新增
*/
@PostMapping
(
"/save"
)
public
RestfulModel
<
Integer
>
saveDoc
(
@RequestBody
@Valid
DocSaveReqDto
docSaveReqDto
)
{
docService
.
save
(
docSaveReqDto
);
return
new
RestfulModel
<>(
ErrorCode
.
SUCCESS
,
""
,
0
);
}
@DeleteMapping
(
"/delete/{docId}"
)
public
RestfulModel
<
Integer
>
deleteDoc
(
@PathVariable
Long
docId
)
{
docService
.
deleteOneDoc
(
docId
);
return
new
RestfulModel
<>(
ErrorCode
.
SUCCESS
,
""
,
0
);
}
}
src/main/java/io/github/yubincloud/fairywiki/dto/req/DocQueryReqDto.java
0 → 100644
浏览文件 @
0596afaf
package
io.github.yubincloud.fairywiki.dto.req
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
@Data
@EqualsAndHashCode
(
callSuper
=
true
)
public
class
DocQueryReqDto
extends
PageReqDto
{
}
src/main/java/io/github/yubincloud/fairywiki/dto/req/DocSaveReqDto.java
0 → 100644
浏览文件 @
0596afaf
package
io.github.yubincloud.fairywiki.dto.req
;
import
lombok.Data
;
import
javax.validation.constraints.NotNull
;
@Data
public
class
DocSaveReqDto
{
private
Long
id
;
@NotNull
(
message
=
"【电子书】不能为空"
)
private
Long
ebookId
;
@NotNull
(
message
=
"【父文档】不能为空"
)
private
Long
parent
;
@NotNull
(
message
=
"【名称】不能为空"
)
private
String
name
;
@NotNull
(
message
=
"【顺序】不能为空"
)
private
Integer
sort
;
private
Integer
viewCount
;
private
Integer
voteCount
;
@NotNull
(
message
=
"【内容】不能为空"
)
private
String
content
;
}
src/main/java/io/github/yubincloud/fairywiki/dto/resp/DocQueryRespDto.java
0 → 100644
浏览文件 @
0596afaf
package
io.github.yubincloud.fairywiki.dto.resp
;
import
lombok.Data
;
@Data
public
class
DocQueryRespDto
{
private
Long
id
;
private
Long
ebookId
;
private
Long
parent
;
private
String
name
;
private
Integer
sort
;
private
Integer
viewCount
;
private
Integer
voteCount
;
}
src/main/java/io/github/yubincloud/fairywiki/service/DocService.java
0 → 100644
浏览文件 @
0596afaf
package
io.github.yubincloud.fairywiki.service
;
import
com.github.pagehelper.PageHelper
;
import
com.github.pagehelper.PageInfo
;
import
io.github.yubincloud.fairywiki.domain.Doc
;
import
io.github.yubincloud.fairywiki.domain.DocExample
;
import
io.github.yubincloud.fairywiki.dto.req.DocQueryReqDto
;
import
io.github.yubincloud.fairywiki.dto.req.DocSaveReqDto
;
import
io.github.yubincloud.fairywiki.dto.resp.DocQueryRespDto
;
import
io.github.yubincloud.fairywiki.dto.resp.PageRespDto
;
import
io.github.yubincloud.fairywiki.mapper.DocMapper
;
import
io.github.yubincloud.fairywiki.utils.CopyUtil
;
import
io.github.yubincloud.fairywiki.utils.SnowFlake
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.ObjectUtils
;
import
javax.annotation.Resource
;
import
java.util.List
;
@Service
public
class
DocService
{
private
static
final
Logger
LOG
=
LoggerFactory
.
getLogger
(
DocService
.
class
);
@Resource
private
DocMapper
docMapper
;
@Resource
private
SnowFlake
snowFlake
;
/**
* 获取全部 Doc
*/
public
List
<
DocQueryRespDto
>
fetchAllCategories
()
{
DocExample
docExample
=
new
DocExample
();
docExample
.
setOrderByClause
(
"sort asc"
);
List
<
Doc
>
docList
=
docMapper
.
selectByExample
(
docExample
);
return
CopyUtil
.
copyList
(
docList
,
DocQueryRespDto
.
class
);
}
/**
* 根据查询条件对数据库中的 doc 进行查询并返回查询到的 doc
*/
public
PageRespDto
<
DocQueryRespDto
>
queryDocs
(
DocQueryReqDto
reqDto
)
{
DocExample
docExample
=
new
DocExample
();
DocExample
.
Criteria
criteria
=
docExample
.
createCriteria
();
PageHelper
.
startPage
(
reqDto
.
getPageNum
(),
reqDto
.
getPageSize
());
List
<
Doc
>
docList
=
docMapper
.
selectByExample
(
docExample
);
PageInfo
<
Doc
>
pageInfo
=
new
PageInfo
<>(
docList
);
LOG
.
info
(
"总行数:{}"
,
pageInfo
.
getTotal
());
LOG
.
info
(
"总页数:{}"
,
pageInfo
.
getPages
());
// 列表复制
List
<
DocQueryRespDto
>
list
=
CopyUtil
.
copyList
(
docList
,
DocQueryRespDto
.
class
);
PageRespDto
<
DocQueryRespDto
>
pageRespDto
=
new
PageRespDto
<>();
pageRespDto
.
setTotal
(
pageInfo
.
getTotal
());
pageRespDto
.
setList
(
list
);
return
pageRespDto
;
}
/**
* 根据 DocSaveReqDto 来保存一个 doc 记录,若 id 为空则新增,不为空则更新
*/
public
void
save
(
DocSaveReqDto
reqDto
)
{
Doc
docRecord
=
CopyUtil
.
copy
(
reqDto
,
Doc
.
class
);
if
(
ObjectUtils
.
isEmpty
(
docRecord
.
getId
()))
{
// 判断 id 是否为空
docRecord
.
setId
(
snowFlake
.
nextId
());
docMapper
.
insertSelective
(
docRecord
);
}
else
{
docMapper
.
updateByPrimaryKey
(
docRecord
);
}
}
public
void
deleteOneDoc
(
Long
docId
)
{
docMapper
.
deleteByPrimaryKey
(
docId
);
}
}
web/src/models.ts
浏览文件 @
0596afaf
...
...
@@ -36,3 +36,24 @@ export interface Category {
export
interface
CategoryQueryForm
{
name
:
string
;
}
/**
* 文档类
*/
export
interface
Doc
{
id
:
string
;
ebookId
:
string
;
parent
:
string
;
name
:
string
;
sort
:
number
;
viewCount
:
number
;
voteCount
:
number
;
}
/**
* 文档的查询类
*/
export
interface
DocQueryForm
{
name
:
string
;
}
\ No newline at end of file
web/src/router/index.ts
浏览文件 @
0596afaf
...
...
@@ -3,6 +3,7 @@ import Home from '../views/home.vue'
import
About
from
'
../views/about.vue
'
import
AdminEbook
from
'
../views/admin/admin-ebook.vue
'
import
AdminCategory
from
'
../views/admin/admin-category.vue
'
import
AdminDoc
from
'
../views/admin/admin-doc.vue
'
const
routes
:
Array
<
RouteRecordRaw
>
=
[
{
...
...
@@ -24,6 +25,11 @@ const routes: Array<RouteRecordRaw> = [
path
:
'
/admin/category
'
,
name
:
'
AdminCategory
'
,
component
:
AdminCategory
},
{
path
:
'
/admin/doc
'
,
name
:
'
AdminDoc
'
,
component
:
AdminDoc
}
]
...
...
web/src/views/admin/admin-doc.vue
0 → 100644
浏览文件 @
0596afaf
<
template
>
<a-layout>
<a-layout-content
:style=
"
{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }"
>
<p>
<a-form
layout=
"inline"
:model=
"docQueryForm"
@
finish=
"handleQueryFormSubmit"
>
<a-form-item>
<a-button
type=
"primary"
html-type=
"submit"
size=
"large"
>
查询
</a-button>
</a-form-item>
<a-form-item>
<a-button
type=
"primary"
@
click=
"add()"
size=
"large"
>
新增
</a-button>
</a-form-item>
</a-form>
</p>
<a-table
:columns=
"columns"
:row-key=
"record => record.id"
:data-source=
"level1"
:pagination=
"false"
:loading=
"loading"
>
<template
#cover
="
{ text: cover }">
<img
v-if=
"cover"
:src=
"cover"
alt=
"avatar"
/>
</
template
>
<
template
v-slot:action=
"{ text, record }"
>
<a-space
size=
"small"
>
<a-button
type=
"primary"
@
click=
"edit(record)"
>
编辑
</a-button>
<a-popconfirm
title=
"确认删除?"
ok-text=
"Yes"
cancel-text=
"No"
@
confirm=
"handleDeleteDoc(record.id)"
>
<a-button
type=
"danger"
>
删除
</a-button>
</a-popconfirm>
</a-space>
</
template
>
</a-table>
</a-layout-content>
</a-layout>
<a-modal
title=
"文档表单"
v-model:visible=
"modalVisible"
:confirm-loading=
"modalLoading"
@
ok=
"handleModalOk"
>
<a-form
:model=
"doc"
:label-col=
"{ span: 6 }"
:wrapper-col=
"{ span: 18 }"
>
<a-form-item
label=
"名称"
>
<a-input
v-model:value=
"doc.name"
/>
</a-form-item>
<a-form-item
label=
"父文档"
>
<a-select
v-model:value=
"doc.parent"
style=
"width: 120px"
@
focus=
"focus"
ref=
"select"
>
<a-select-option
value=
"0"
>
无
</a-select-option>
<a-select-option
v-for=
"c in level1"
:key=
"c.id"
:value=
"c.id"
:disabled=
"doc.id === c.id"
>
{{ c.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label=
"顺序"
>
<a-input
v-model:value=
"doc.sort"
type=
"textarea"
/>
</a-form-item>
</a-form>
</a-modal>
</template>
<
script
lang=
"ts"
>
import
{
defineComponent
,
onMounted
,
ref
,
UnwrapRef
,
reactive
}
from
'
vue
'
;
import
axios
from
'
axios
'
;
import
{
message
}
from
'
ant-design-vue
'
import
{
Tool
}
from
"
@/util/tool
"
;
import
{
Doc
,
DocQueryForm
}
from
"
@/models
"
;
export
default
defineComponent
({
name
:
'
AdminDoc
'
,
setup
()
{
const
docQueryForm
:
UnwrapRef
<
DocQueryForm
>
=
reactive
({
name
:
''
});
const
docs
=
ref
<
Doc
[]
>
([]);
const
loading
=
ref
(
false
);
const
columns
=
[
{
title
:
'
名称
'
,
dataIndex
:
'
name
'
},
{
title
:
'
父文档
'
,
key
:
'
parent
'
,
dataIndex
:
'
parent
'
},
{
title
:
'
顺序
'
,
dataIndex
:
'
sort
'
},
{
title
:
'
Action
'
,
key
:
'
action
'
,
slots
:
{
customRender
:
'
action
'
}
}
];
/**
* 一级文档树,children属性就是二级文档
* [{
* id: "",
* name: "",
* children: [{
* id: "",
* name: "",
* }]
* }]
*/
const
level1
=
ref
();
// 一级文档树,children属性就是二级文档
/**
* 数据查询
**/
const
handleQuery
=
()
=>
{
loading
.
value
=
true
;
axios
.
get
(
"
/doc/all
"
).
then
((
response
)
=>
{
loading
.
value
=
false
;
const
respData
=
response
.
data
;
if
(
respData
.
code
==
0
)
{
docs
.
value
=
respData
.
data
;
console
.
log
(
"
原始数组:
"
,
docs
.
value
);
level1
.
value
=
[];
level1
.
value
=
Tool
.
array2Tree
(
docs
.
value
,
0
);
console
.
log
(
"
树形结构:
"
,
level1
);
}
else
{
message
.
error
(
respData
.
msg
);
}
});
};
/**
* 根据表单提交的数据进行查询
**/
const
handleQueryFormSubmit
=
()
=>
{
handleQuery
();
};
// -------- 表单 ---------
const
doc
=
ref
();
const
modalVisible
=
ref
(
false
);
const
modalLoading
=
ref
(
false
);
const
handleModalOk
=
()
=>
{
modalLoading
.
value
=
true
;
axios
.
post
(
"
/doc/save
"
,
doc
.
value
).
then
((
response
)
=>
{
const
respData
=
response
.
data
;
modalLoading
.
value
=
false
;
if
(
respData
.
code
==
0
)
{
modalVisible
.
value
=
false
;
}
else
{
message
.
error
(
respData
.
msg
);
}
handleQuery
();
})
};
/**
* 编辑
*/
const
edit
=
(
record
:
any
)
=>
{
modalVisible
.
value
=
true
;
doc
.
value
=
Tool
.
copy
(
record
);
};
/**
* 新增
*/
const
add
=
()
=>
{
modalVisible
.
value
=
true
;
doc
.
value
=
{};
}
/**
* 删除
*/
const
handleDeleteDoc
=
(
docId
:
string
)
=>
{
console
.
log
(
docId
);
axios
.
delete
(
"
/doc/delete/
"
+
docId
).
then
((
response
)
=>
{
const
respData
=
response
.
data
;
if
(
respData
.
code
==
0
)
{
handleQuery
();
}
});
}
onMounted
(()
=>
{
handleQuery
();
});
return
{
docQueryForm
,
level1
,
labelCol
:
{
span
:
4
},
wrapperCol
:
{
span
:
14
},
columns
,
loading
,
edit
,
add
,
handleDeleteDoc
,
handleQueryFormSubmit
,
doc
,
modalVisible
,
modalLoading
,
handleModalOk
}
}
});
</
script
>
<
style
scoped
>
img
{
width
:
50px
;
height
:
50px
;
}
</
style
>
web/src/views/admin/admin-ebook.vue
浏览文件 @
0596afaf
...
...
@@ -45,6 +45,11 @@
</
template
>
<
template
v-slot:action=
"{ text, record }"
>
<a-space
size=
"small"
>
<router-link
to=
"/admin/doc"
>
<a-button
type=
"primary"
>
文档管理
</a-button>
</router-link>
<a-button
type=
"primary"
@
click=
"edit(record)"
>
编辑
</a-button>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录