Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
S
saas-learn
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
saas-learn
Commits
b1b50306
提交
b1b50306
authored
10月 24, 2022
作者:
王鹏飞
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
chore(bbs): 完善bbs功能
上级
e0e5fd07
显示空白字符变更
内嵌
并排
正在显示
18 个修改的文件
包含
429 行增加
和
116 行删除
+429
-116
base.ts
src/api/base.ts
+2
-2
ResourceIcon.vue
src/components/ResourceIcon.vue
+5
-3
AppEditor.vue
src/components/base/AppEditor.vue
+6
-0
useGetCourseList.ts
src/composables/useGetCourseList.ts
+5
-6
DiscussForm.vue
src/modules/bbs/components/DiscussForm.vue
+8
-2
DiscussItem.vue
src/modules/bbs/components/DiscussItem.vue
+74
-9
DiscussItemCommentList.vue
src/modules/bbs/components/DiscussItemCommentList.vue
+45
-12
FileItem.vue
src/modules/bbs/components/FileItem.vue
+0
-31
FileList.vue
src/modules/bbs/components/FileList.vue
+86
-0
PostForm.vue
src/modules/bbs/components/PostForm.vue
+19
-6
PostItem.vue
src/modules/bbs/components/PostItem.vue
+27
-5
PostPinned.vue
src/modules/bbs/components/PostPinned.vue
+20
-5
types.ts
src/modules/bbs/types.ts
+9
-1
Index.vue
src/modules/bbs/views/Index.vue
+48
-27
View.vue
src/modules/bbs/views/View.vue
+44
-3
CourseViewBBS.vue
src/modules/course/components/CourseViewBBS.vue
+9
-2
types.ts
src/modules/favorites/types.ts
+21
-1
Index.vue
src/modules/favorites/views/Index.vue
+1
-1
没有找到文件。
src/api/base.ts
浏览文件 @
b1b50306
...
@@ -67,8 +67,8 @@ export function getQuestionCategory(params: { project_tag: string }) {
...
@@ -67,8 +67,8 @@ export function getQuestionCategory(params: { project_tag: string }) {
export
function
collectionResource
(
data
:
{
export
function
collectionResource
(
data
:
{
course_id
:
string
course_id
:
string
semester_id
:
string
semester_id
:
string
chapter_id
:
string
chapter_id
?
:
string
section_id
:
string
section_id
?
:
string
source_id
:
string
source_id
:
string
type
:
number
type
:
number
status
:
number
status
:
number
...
...
src/components/ResourceIcon.vue
浏览文件 @
b1b50306
...
@@ -6,14 +6,16 @@ interface Props {
...
@@ -6,14 +6,16 @@ interface Props {
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
function
show
(
fileType
:
string
)
{
function
show
(
fileType
:
string
)
{
return
props
.
info
?.
type
?.
includes
(
fileType
)
const
type
=
props
.
info
?.
type
||
''
if
(
typeof
type
===
'string'
)
type
.
includes
(
fileType
)
return
false
}
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"icon-resource"
>
<div
class=
"icon-resource"
>
<img
src=
"@/assets/images/icon_mp4.png"
v-if=
"resourceType === 2
|| show('mp4')
"
/>
<img
src=
"@/assets/images/icon_mp4.png"
v-if=
"resourceType === 2"
/>
<img
src=
"@/assets/images/icon_work.png"
v-else-if=
"resourceType === 3"
/>
<img
src=
"@/assets/images/icon_work.png"
v-else-if=
"resourceType === 3
|| resourceType === 12
"
/>
<img
src=
"@/assets/images/icon_live.png"
v-else-if=
"resourceType === 6"
/>
<img
src=
"@/assets/images/icon_live.png"
v-else-if=
"resourceType === 6"
/>
<img
src=
"@/assets/images/icon_exam.png"
v-else-if=
"resourceType === 9"
/>
<img
src=
"@/assets/images/icon_exam.png"
v-else-if=
"resourceType === 9"
/>
<img
src=
"@/assets/images/icon_ppt.png"
v-else-if=
"show('pptx')"
/>
<img
src=
"@/assets/images/icon_ppt.png"
v-else-if=
"show('pptx')"
/>
...
...
src/components/base/AppEditor.vue
浏览文件 @
b1b50306
...
@@ -63,3 +63,9 @@ const init = {
...
@@ -63,3 +63,9 @@ const init = {
<
template
>
<
template
>
<editor
:init=
"init"
v-bind=
"$attrs"
style=
"width: 100%"
/>
<editor
:init=
"init"
v-bind=
"$attrs"
style=
"width: 100%"
/>
</
template
>
</
template
>
<
style
lang=
"scss"
>
.tox-tinymce-aux
{
z-index
:
3000
!
important
;
}
</
style
>
src/composables/useGetCourseList.ts
浏览文件 @
b1b50306
import
{
getCourseList
,
getCourseChapterList
}
from
'@/api/base'
import
{
getCourseList
,
getCourseChapterList
}
from
'@/api/base'
import
{
val
}
from
'dom7'
interface
Semester
{
interface
Semester
{
id
:
string
id
:
string
...
@@ -21,7 +20,7 @@ interface Chapter {
...
@@ -21,7 +20,7 @@ interface Chapter {
}
}
export
function
useGetCourseList
()
{
export
function
useGetCourseList
()
{
const
course
Id
=
ref
(
''
)
const
course
Value
=
ref
(
''
)
const
courses
=
ref
<
Course
[]
>
([])
const
courses
=
ref
<
Course
[]
>
([])
const
chapters
=
ref
<
Chapter
[]
>
([])
const
chapters
=
ref
<
Chapter
[]
>
([])
// 获取课程列表
// 获取课程列表
...
@@ -32,20 +31,20 @@ export function useGetCourseList() {
...
@@ -32,20 +31,20 @@ export function useGetCourseList() {
}
}
// 获取章节列表
// 获取章节列表
function
getChapters
()
{
function
getChapters
()
{
if
(
!
course
Id
.
value
)
{
if
(
!
course
Value
.
value
)
{
chapters
.
value
=
[]
chapters
.
value
=
[]
return
return
}
}
getCourseChapterList
({
course_id
:
course
Id
.
value
}).
then
(
res
=>
{
getCourseChapterList
({
course_id
:
course
Value
.
value
}).
then
(
res
=>
{
chapters
.
value
=
res
.
data
.
items
chapters
.
value
=
res
.
data
.
items
})
})
}
}
getCourses
()
getCourses
()
watch
(
course
Id
,
()
=>
{
watch
(
course
Value
,
()
=>
{
getChapters
()
getChapters
()
})
})
return
{
courses
,
course
Id
,
chapters
}
return
{
courses
,
course
Value
,
chapters
}
}
}
src/modules/bbs/components/DiscussForm.vue
浏览文件 @
b1b50306
...
@@ -34,7 +34,7 @@ function handleSubmit() {
...
@@ -34,7 +34,7 @@ function handleSubmit() {
const
create
=
()
=>
{
const
create
=
()
=>
{
const
params
=
Object
.
assign
({},
form
,
{
files
:
form
.
files
.
length
?
JSON
.
stringify
(
form
.
files
)
:
''
})
const
params
=
Object
.
assign
({},
form
,
{
files
:
form
.
files
.
length
?
JSON
.
stringify
(
form
.
files
)
:
''
})
replyToPost
(
params
).
then
(()
=>
{
replyToPost
(
params
).
then
(()
=>
{
ElMessage
({
message
:
'发
布
成功'
,
type
:
'success'
})
ElMessage
({
message
:
'发
表
成功'
,
type
:
'success'
})
emit
(
'update'
)
emit
(
'update'
)
emit
(
'update:modelValue'
,
false
)
emit
(
'update:modelValue'
,
false
)
})
})
...
@@ -42,7 +42,13 @@ const create = () => {
...
@@ -42,7 +42,13 @@ const create = () => {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
title=
"发表回复"
width=
"800px"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-dialog
append-to-body
align-center
title=
"发表回复"
width=
"800px"
:close-on-click-modal=
"false"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
label-position=
"top"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
label-position=
"top"
>
<el-form-item
prop=
"content"
>
<el-form-item
prop=
"content"
>
<AppEditor
v-model=
"form.content"
:height=
"300"
/>
<AppEditor
v-model=
"form.content"
:height=
"300"
/>
...
...
src/modules/bbs/components/DiscussItem.vue
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
DiscussItem
}
from
'../types'
import
type
{
DiscussItem
}
from
'../types'
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
,
ElInput
}
from
'element-plus'
import
DiscussItemCommentList
from
'./DiscussItemCommentList.vue'
import
DiscussItemCommentList
from
'./DiscussItemCommentList.vue'
import
File
Item
from
'./FileItem
.vue'
import
File
List
from
'./FileList
.vue'
import
{
replyToPost
}
from
'../api'
import
{
replyToPost
}
from
'../api'
interface
Props
{
interface
Props
{
landlordId
:
string
data
:
DiscussItem
data
:
DiscussItem
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
...
@@ -16,7 +17,8 @@ const username = $computed(() => {
...
@@ -16,7 +17,8 @@ const username = $computed(() => {
return
user
.
realname
||
user
.
nickname
||
user
.
username
return
user
.
realname
||
user
.
nickname
||
user
.
username
})
})
const
formVisible
=
$ref
(
false
)
const
commentListRef
=
$ref
<
InstanceType
<
typeof
DiscussItemCommentList
>
|
null
>
(
null
)
const
formRef
=
$ref
<
FormInstance
>
()
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
({
const
form
=
reactive
({
content
:
''
,
content
:
''
,
...
@@ -25,6 +27,15 @@ const form = reactive({
...
@@ -25,6 +27,15 @@ const form = reactive({
const
rules
=
ref
<
FormRules
>
({
const
rules
=
ref
<
FormRules
>
({
content
:
[{
required
:
true
,
message
:
'请输入回复内容'
,
trigger
:
'blur'
}]
content
:
[{
required
:
true
,
message
:
'请输入回复内容'
,
trigger
:
'blur'
}]
})
})
let
formVisible
=
$ref
(
false
)
const
inputRef
=
$ref
<
InstanceType
<
typeof
ElInput
>
|
null
>
(
null
)
function
handleReply
()
{
formVisible
=
!
formVisible
nextTick
(()
=>
{
formVisible
&&
inputRef
?.
focus
()
})
}
// 发布回复
// 发布回复
function
handleSubmit
()
{
function
handleSubmit
()
{
formRef
?.
validate
().
then
(()
=>
{
formRef
?.
validate
().
then
(()
=>
{
...
@@ -35,6 +46,9 @@ function handleSubmit() {
...
@@ -35,6 +46,9 @@ function handleSubmit() {
reply_id
:
props
.
data
.
id
,
reply_id
:
props
.
data
.
id
,
content
:
form
.
content
content
:
form
.
content
}).
then
(()
=>
{
}).
then
(()
=>
{
formVisible
=
false
form
.
content
=
''
commentListRef
?.
refresh
()
ElMessage
({
message
:
'回复成功'
,
type
:
'success'
})
ElMessage
({
message
:
'回复成功'
,
type
:
'success'
})
})
})
})
})
...
@@ -44,32 +58,61 @@ function handleSubmit() {
...
@@ -44,32 +58,61 @@ function handleSubmit() {
<
template
>
<
template
>
<section
class=
"discuss-item"
>
<section
class=
"discuss-item"
>
<div
class=
"discuss-item__left"
>
<div
class=
"discuss-item__left"
>
<div
class=
"discuss-item__landlord"
v-if=
"data.sso_id === landlordId"
><span>
楼主
</span></div>
<div
class=
"discuss-item__avatar"
>
<div
class=
"discuss-item__avatar"
>
<img
:src=
"data.sso_user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/default.jpg'"
/>
<img
:src=
"data.sso_user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/default.jpg'"
/>
</div>
</div>
<p
class=
"discuss-item__username"
>
{{
username
}}
</p>
<p
class=
"discuss-item__username"
>
{{
username
}}
</p>
<template
v-if=
"data.sso_type === 2"
>
<el-button
round
plain
size=
"small"
type=
"primary"
>
老师
</el-button>
</
template
>
<
template
v-else
>
<img
src=
"@/assets/images/icon_bbs_level_1.png"
width=
"40"
title=
"学徒"
v-if=
"data.sso_user.discussion_level === 0"
/>
<img
src=
"@/assets/images/icon_bbs_level_2.png"
width=
"40"
title=
"学者"
v-if=
"data.sso_user.discussion_level === 1"
/>
<img
src=
"@/assets/images/icon_bbs_level_3.png"
width=
"40"
title=
"大师"
v-if=
"data.sso_user.discussion_level === 2"
/>
<img
src=
"@/assets/images/icon_bbs_level_4.png"
width=
"40"
title=
"智者"
v-if=
"data.sso_user.discussion_level === 3"
/>
</
template
>
</div>
</div>
<div
class=
"discuss-item__right"
>
<div
class=
"discuss-item__right"
>
<div
class=
"discuss-item__main"
>
<div
class=
"discuss-item__main"
>
<div
class=
"discuss-item__content"
v-html=
"data.content"
></div>
<div
class=
"discuss-item__content"
v-html=
"data.content"
></div>
<ul
class=
"discuss-item__files"
v-if=
"data.files.length"
>
<FileList
preview
:data=
"data.files"
v-if=
"data.files.length"
/>
<li
v-for=
"(item, index) in data.files"
:key=
"index"
><FileItem
:data=
"item"
/></li>
</ul>
</div>
</div>
<p
class=
"discuss-item__time"
>
{{ data.updated_time }}
</p>
<p
class=
"discuss-item__time"
>
{{ data.updated_time }}
</p>
<div
class=
"discuss-item__comment"
><p
@
click=
"
formVisible = !formVisible
"
>
回复
</p></div>
<div
class=
"discuss-item__comment"
><p
@
click=
"
handleReply
"
>
回复
</p></div>
<div
class=
"discuss-item-form"
v-if=
"formVisible"
>
<div
class=
"discuss-item-form"
v-if=
"formVisible"
>
<p
class=
"discuss-item-form__title"
>
回复本楼
</p>
<p
class=
"discuss-item-form__title"
>
回复本楼
</p>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
>
<el-form-item
prop=
"content"
>
<el-form-item
prop=
"content"
>
<el-input
type=
"textarea"
:autosize=
"
{ minRows: 6, maxRows: 6 }" v-model="form.content" />
<el-input
type=
"textarea"
:autosize=
"{ minRows: 6, maxRows: 6 }"
:maxlength=
"100"
v-model=
"form.content"
ref=
"inputRef"
/>
</el-form-item>
</el-form-item>
<el-row
justify=
"end"
>
<el-row
justify=
"end"
>
<el-button
round
type=
"primary"
@
click=
"handleSubmit"
>
发表回复
</el-button>
<el-button
round
type=
"primary"
@
click=
"handleSubmit"
>
发表回复
</el-button>
</el-row>
</el-row>
</el-form>
</el-form>
</div>
</div>
<DiscussItemCommentList
:data=
"data"
/>
<DiscussItemCommentList
:data=
"data"
ref=
"commentListRef"
/>
</div>
</div>
</section>
</section>
</template>
</template>
...
@@ -80,12 +123,30 @@ function handleSubmit() {
...
@@ -80,12 +123,30 @@ function handleSubmit() {
border-bottom
:
4px
solid
#e8e8e8
;
border-bottom
:
4px
solid
#e8e8e8
;
}
}
.discuss-item__left
{
.discuss-item__left
{
position
:
relative
;
width
:
240px
;
width
:
240px
;
padding
:
40px
;
padding
:
40px
;
text-align
:
center
;
text-align
:
center
;
background-color
:
#f9f9fc
;
background-color
:
#f9f9fc
;
box-sizing
:
border-box
;
box-sizing
:
border-box
;
}
}
.discuss-item__landlord
{
position
:
absolute
;
left
:
0
;
top
:
0
;
width
:
60px
;
height
:
60px
;
color
:
#fff
;
background-color
:
var
(
--
main-color
);
z-index
:
2000
;
clip-path
:
polygon
(
0
0
,
100%
0
,
0%
100%
);
span
{
position
:
absolute
;
left
:
5px
;
top
:
10px
;
transform
:
rotate
(
-45deg
);
}
}
.discuss-item__avatar
{
.discuss-item__avatar
{
width
:
100px
;
width
:
100px
;
height
:
100px
;
height
:
100px
;
...
@@ -98,6 +159,7 @@ function handleSubmit() {
...
@@ -98,6 +159,7 @@ function handleSubmit() {
}
}
.discuss-item__username
{
.discuss-item__username
{
margin-top
:
14px
;
margin-top
:
14px
;
margin-bottom
:
10px
;
font-size
:
16px
;
font-size
:
16px
;
color
:
#333
;
color
:
#333
;
}
}
...
@@ -116,6 +178,9 @@ function handleSubmit() {
...
@@ -116,6 +178,9 @@ function handleSubmit() {
.discuss-item__content
{
.discuss-item__content
{
font-size
:
16px
;
font-size
:
16px
;
color
:
#666
;
color
:
#666
;
img
{
max-width
:
100%
;
}
}
}
.discuss-item__time
{
.discuss-item__time
{
margin-top
:
20px
;
margin-top
:
20px
;
...
...
src/modules/bbs/components/DiscussItemCommentList.vue
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
DiscussItem
,
DiscussCommentItem
,
User
}
from
'../types'
import
type
{
DiscussItem
,
DiscussCommentItem
,
User
}
from
'../types'
import
{
ElMessage
}
from
'element-plus'
import
{
ElMessage
,
ElInput
}
from
'element-plus'
import
{
getCommitList
,
replyToPost
}
from
'../api'
import
{
getCommitList
,
replyToPost
}
from
'../api'
interface
Props
{
interface
Props
{
...
@@ -9,21 +9,34 @@ interface Props {
...
@@ -9,21 +9,34 @@ interface Props {
}
}
const
props
=
defineProps
<
Props
>
()
const
props
=
defineProps
<
Props
>
()
let
page
=
$ref
(
1
)
const
params
=
reactive
({
page
:
1
,
limit
:
3
,
floor_id
:
props
.
data
.
id
}
)
let
list
=
$ref
<
DiscussCommentItem
[]
>
([])
let
list
=
$ref
<
DiscussCommentItem
[]
>
([])
let
hasMore
=
$ref
(
true
)
let
loading
=
$ref
(
false
)
function
fetchList
()
{
function
fetchList
()
{
getCommitList
({
floor_id
:
props
.
data
.
id
,
page
}).
then
(
res
=>
{
if
(
loading
)
return
list
=
page
===
1
?
res
.
data
.
data
:
list
.
concat
(
res
.
data
.
data
)
loading
=
true
page
++
getCommitList
(
params
)
.
then
(
res
=>
{
list
=
params
.
page
===
1
?
res
.
data
.
data
:
list
.
concat
(
res
.
data
.
data
)
hasMore
=
res
.
data
.
data
.
length
>=
params
.
limit
params
.
page
++
})
.
finally
(()
=>
{
loading
=
false
})
})
}
}
function
ref
etc
h
()
{
function
ref
res
h
()
{
page
=
1
pa
rams
.
pa
ge
=
1
fetchList
()
fetchList
()
}
}
// 加载更多
// 加载更多
function
loadMore
()
{
function
loadMore
()
{
if
(
params
.
limit
===
3
)
{
params
.
page
=
1
}
params
.
limit
=
20
fetchList
()
fetchList
()
}
}
...
@@ -32,11 +45,23 @@ const currentList = $computed(() => {
...
@@ -32,11 +45,23 @@ const currentList = $computed(() => {
return
props
.
data
.
child_replies
return
props
.
data
.
child_replies
})
})
onMounted
(()
=>
{
hasMore
=
props
.
data
.
child_replies
.
length
>=
3
})
const
inputRef
=
$ref
<
InstanceType
<
typeof
ElInput
>
|
null
>
(
null
)
let
activeComment
=
$ref
<
DiscussCommentItem
>
()
let
activeComment
=
$ref
<
DiscussCommentItem
>
()
function
handleReply
(
data
:
DiscussCommentItem
)
{
function
handleReply
(
data
:
DiscussCommentItem
)
{
if
(
data
.
id
===
activeComment
?.
id
&&
formVisible
)
{
formVisible
=
false
return
}
activeComment
=
data
activeComment
=
data
formVisible
=
true
formVisible
=
true
form
.
content
=
`回复@
${
getUsername
(
data
.
sso_user
)}
:`
form
.
content
=
`回复@
${
getUsername
(
data
.
sso_user
)}
:`
nextTick
(()
=>
{
inputRef
?.
focus
()
})
}
}
let
formVisible
=
$ref
(
false
)
let
formVisible
=
$ref
(
false
)
...
@@ -58,7 +83,8 @@ function handleSubmit() {
...
@@ -58,7 +83,8 @@ function handleSubmit() {
reply_id
:
activeComment
.
id
,
reply_id
:
activeComment
.
id
,
content
:
form
.
content
.
replace
(
`回复@
${
getUsername
(
activeComment
.
sso_user
)}
:`
,
''
)
content
:
form
.
content
.
replace
(
`回复@
${
getUsername
(
activeComment
.
sso_user
)}
:`
,
''
)
}).
then
(()
=>
{
}).
then
(()
=>
{
refetch
()
formVisible
=
false
refresh
()
ElMessage
({
message
:
'回复成功'
,
type
:
'success'
})
ElMessage
({
message
:
'回复成功'
,
type
:
'success'
})
})
})
})
})
...
@@ -66,10 +92,12 @@ function handleSubmit() {
...
@@ -66,10 +92,12 @@ function handleSubmit() {
function
getUsername
(
data
:
User
)
{
function
getUsername
(
data
:
User
)
{
return
data
.
realname
||
data
.
username
||
data
.
nickname
return
data
.
realname
||
data
.
username
||
data
.
nickname
}
}
defineExpose
({
refresh
})
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"discuss-comment-list"
>
<div
class=
"discuss-comment-list"
v-if=
"currentList.length"
>
<div
class=
"discuss-comment-item"
v-for=
"item in currentList"
:key=
"item.id"
>
<div
class=
"discuss-comment-item"
v-for=
"item in currentList"
:key=
"item.id"
>
<img
<img
:src=
"item.sso_user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/default.jpg'"
:src=
"item.sso_user.avatar || 'https://webapp-pub.ezijing.com/website/base/images/default.jpg'"
...
@@ -89,14 +117,19 @@ function getUsername(data: User) {
...
@@ -89,14 +117,19 @@ function getUsername(data: User) {
</div>
</div>
</div>
</div>
</div>
</div>
<p
class=
"more"
><span
@
click=
"loadMore"
>
查看更多
</span></p>
<p
class=
"more"
v-if=
"hasMore"
><span
@
click=
"loadMore"
>
查看更多
</span></p>
<div
class=
"discuss-item-form"
v-if=
"formVisible"
>
<div
class=
"discuss-item-form"
v-if=
"formVisible"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
>
<el-form-item
prop=
"content"
>
<el-form-item
prop=
"content"
>
<el-input
type=
"textarea"
:autosize=
"
{ minRows: 6, maxRows: 6 }" v-model="form.content" />
<el-input
type=
"textarea"
:autosize=
"
{ minRows: 6, maxRows: 6 }"
:maxlength="100"
v-model="form.content"
ref="inputRef" />
</el-form-item>
</el-form-item>
<el-row
justify=
"end"
>
<el-row
justify=
"end"
>
<el-button
round
type=
"primary"
auto-insert-space
@
click=
"handleSubmit"
>
发表
</el-button>
<el-button
round
type=
"primary"
@
click=
"handleSubmit"
>
发表回复
</el-button>
</el-row>
</el-row>
</el-form>
</el-form>
</div>
</div>
...
...
src/modules/bbs/components/FileItem.vue
deleted
100644 → 0
浏览文件 @
e0e5fd07
<
script
setup
lang=
"ts"
>
import
type
{
File
}
from
'../types'
interface
Props
{
data
:
File
}
const
props
=
defineProps
<
Props
>
()
const
isVideo
=
$computed
(()
=>
{
return
props
.
data
.
url
.
includes
(
'.mp4'
)
})
</
script
>
<
template
>
<div
class=
"file-item"
>
<video
:src=
"data.url"
controls
v-if=
"isVideo"
></video>
<img
:src=
"data.url"
v-else
/>
</div>
</
template
>
<
style
lang=
"scss"
>
.file-item
{
img
{
width
:
160px
;
height
:
90px
;
object-fit
:
cover
;
}
video
{
width
:
400px
;
}
}
</
style
>
src/modules/bbs/components/FileList.vue
0 → 100644
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
import
type
{
File
}
from
'../types'
import
{
VideoPlay
}
from
'@element-plus/icons-vue'
interface
Props
{
preview
?:
boolean
data
:
File
[]
|
Record
<
string
,
File
[]
>
}
const
props
=
defineProps
<
Props
>
()
const
images
=
$computed
(()
=>
{
if
(
!
Array
.
isArray
(
props
.
data
))
return
[]
return
props
.
data
.
filter
(
item
=>
!
isVideo
(
item
.
url
))
})
const
currentImages
=
$computed
(()
=>
{
if
(
props
.
preview
)
return
images
return
images
.
filter
((
item
,
index
)
=>
index
<
3
)
})
const
imageSrcList
=
$computed
(()
=>
{
return
props
.
preview
?
images
.
map
(
item
=>
item
.
url
)
:
[]
})
const
videos
=
$computed
(()
=>
{
if
(
!
Array
.
isArray
(
props
.
data
))
return
[]
return
props
.
data
.
filter
(
item
=>
isVideo
(
item
.
url
))
})
function
isVideo
(
url
:
string
)
{
return
url
.
includes
(
'.mp4'
)
}
</
script
>
<
template
>
<div
class=
"file-list"
>
<div
class=
"file-item"
v-for=
"(item, index) in currentImages"
:key=
"index"
>
<p
class=
"file-item__count"
v-if=
"images.length > 3 && index === 0"
>
共
{{
images
.
length
}}
张
</p>
<el-image
style=
"width: 100%; height: 100%"
:src=
"item.url + '?x-oss-process=image/resize,m_fill,h_90,w_160'"
:initial-index=
"index"
:preview-src-list=
"imageSrcList"
fit=
"cover"
/>
</div>
<div
class=
"file-item"
v-for=
"(item, index) in videos"
:key=
"index"
>
<video
:src=
"item.url"
/>
<el-icon
class=
"icon-video-play"
><VideoPlay
/></el-icon>
</div>
</div>
</
template
>
<
style
lang=
"scss"
>
.file-list
{
margin-top
:
20px
;
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
20px
;
}
.file-item
{
position
:
relative
;
width
:
160px
;
height
:
90px
;
video
{
width
:
160px
;
height
:
90px
;
}
.icon-video-play
{
position
:
absolute
;
left
:
50%
;
top
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
font-size
:
30px
;
color
:
#fff
;
}
}
.file-item__count
{
position
:
absolute
;
left
:
0
;
top
:
10px
;
padding
:
0
10px
;
height
:
18px
;
font-size
:
12px
;
color
:
#fff
;
line-height
:
18px
;
text-align
:
center
;
background
:
rgba
(
0
,
0
,
0
,
0
.8
);
z-index
:
1000
;
}
</
style
>
src/modules/bbs/components/PostForm.vue
浏览文件 @
b1b50306
...
@@ -7,18 +7,25 @@ import { createPost } from '../api'
...
@@ -7,18 +7,25 @@ import { createPost } from '../api'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useGetCourseList
}
from
'@/composables/useGetCourseList'
import
{
useGetCourseList
}
from
'@/composables/useGetCourseList'
interface
Props
{
courseId
?:
string
semesterId
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
(
e
:
'update'
):
void
(
e
:
'update'
):
void
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
(
e
:
'update:modelValue'
,
visible
:
boolean
):
void
}
>
()
}
>
()
const
{
courses
,
course
Id
,
chapters
}
=
useGetCourseList
()
const
{
courses
,
course
Value
,
chapters
}
=
useGetCourseList
()
const
types
=
useMapStore
().
getMapValuesByKey
(
'learning_discussion_type'
)
const
types
=
useMapStore
().
getMapValuesByKey
(
'learning_discussion_type'
)
const
formRef
=
$ref
<
FormInstance
>
()
const
formRef
=
$ref
<
FormInstance
>
()
const
form
=
reactive
({
const
form
=
reactive
({
semester_id
:
''
,
semester_id
:
props
.
semesterId
||
''
,
course_id
:
''
,
course_id
:
props
.
courseId
||
''
,
chapter_id
:
''
,
chapter_id
:
''
,
type
:
''
,
type
:
''
,
title
:
''
,
title
:
''
,
...
@@ -33,7 +40,7 @@ const rules = ref<FormRules>({
...
@@ -33,7 +40,7 @@ const rules = ref<FormRules>({
content
:
[{
required
:
true
,
message
:
'请输入正文内容'
,
trigger
:
'blur'
}]
content
:
[{
required
:
true
,
message
:
'请输入正文内容'
,
trigger
:
'blur'
}]
})
})
watchEffect
(()
=>
{
watchEffect
(()
=>
{
course
Id
.
value
=
form
.
course_id
course
Value
.
value
=
form
.
course_id
const
course
=
courses
.
value
.
find
(
item
=>
item
.
course_id
===
form
.
course_id
)
const
course
=
courses
.
value
.
find
(
item
=>
item
.
course_id
===
form
.
course_id
)
form
.
semester_id
=
course
?
course
.
semester
.
id
:
''
form
.
semester_id
=
course
?
course
.
semester
.
id
:
''
})
})
...
@@ -53,10 +60,16 @@ const create = () => {
...
@@ -53,10 +60,16 @@ const create = () => {
</
script
>
</
script
>
<
template
>
<
template
>
<el-dialog
title=
"发帖"
width=
"800px"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-dialog
append-to-body
align-center
title=
"发帖"
width=
"800px"
:close-on-click-modal=
"false"
@
update:modelValue=
"$emit('update:modelValue')"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
label-position=
"top"
>
<el-form
ref=
"formRef"
:model=
"form"
:rules=
"rules"
hide-required-asterisk
label-position=
"top"
>
<el-row
justify=
"space-between"
>
<el-row
justify=
"space-between"
>
<el-form-item
label=
"相关课程"
prop=
"course_id"
>
<el-form-item
label=
"相关课程"
prop=
"course_id"
v-if=
"!courseId"
>
<el-select
filterable
v-model=
"form.course_id"
>
<el-select
filterable
v-model=
"form.course_id"
>
<el-option
v-for=
"item in courses"
:key=
"item.id"
:label=
"item.name"
:value=
"item.course_id"
></el-option>
<el-option
v-for=
"item in courses"
:key=
"item.id"
:label=
"item.name"
:value=
"item.course_id"
></el-option>
</el-select>
</el-select>
...
...
src/modules/bbs/components/PostItem.vue
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
PostItem
}
from
'../types'
import
type
{
PostItem
}
from
'../types'
import
File
Item
from
'./FileItem
.vue'
import
File
List
from
'./FileList
.vue'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
interface
Props
{
interface
Props
{
...
@@ -24,20 +24,20 @@ const username = $computed(() => {
...
@@ -24,20 +24,20 @@ const username = $computed(() => {
<
template
>
<
template
>
<section
class=
"post-item"
>
<section
class=
"post-item"
>
<router-link
:to=
"`/bbs/$
{data.id}`" target="_blank">
<div
class=
"post-item-hd"
>
<div
class=
"post-item-hd"
>
<p
class=
"post-item__type"
:class=
"`type-$
{data.type}`">
{{
typeText
}}
</p>
<p
class=
"post-item__type"
:class=
"`type-$
{data.type}`">
{{
typeText
}}
</p>
<h2
class=
"post-item__title"
>
{{
data
.
title
}}
</h2>
<h2
class=
"post-item__title"
>
{{
data
.
title
}}
<span
class=
"is-hot"
v-if=
"data.is_hot"
>
热
</span>
</h2>
<p
class=
"post-item__reply_count"
>
{{
data
.
reply_count
}}
回帖
</p>
<p
class=
"post-item__reply_count"
>
{{
data
.
reply_count
}}
回帖
</p>
</div>
</div>
<div
class=
"post-item-bd"
>
<div
class=
"post-item-bd"
>
<ul
class=
"post-item__files"
v-if=
"data.reply?.files.length"
>
<FileList
:data=
"data.reply?.files"
/>
<li
v-for=
"(item, index) in data.reply.files"
:key=
"index"
><FileItem
:data=
"item"
/></li>
</ul>
</div>
</div>
<div
class=
"post-item-ft"
>
<div
class=
"post-item-ft"
>
<p
class=
"post-item__username"
>
{{
username
}}
</p>
<p
class=
"post-item__username"
>
{{
username
}}
</p>
<p
class=
"post-item__time"
>
{{
data
.
updated_time
}}
</p>
<p
class=
"post-item__time"
>
{{
data
.
updated_time
}}
</p>
</div>
</div>
</router-link>
</section>
</section>
</
template
>
</
template
>
...
@@ -45,7 +45,17 @@ const username = $computed(() => {
...
@@ -45,7 +45,17 @@ const username = $computed(() => {
.post-item
{
.post-item
{
padding
:
30px
0
;
padding
:
30px
0
;
border-bottom
:
1px
solid
#e6e6e6
;
border-bottom
:
1px
solid
#e6e6e6
;
border-top
:
1px
solid
#e6e6e6
;
&
:hover
{
.post-item__title
{
color
:
var
(
--
main-color
);
}
}
}
}
.post-item
+
.post-item
{
border-top
:
none
;
}
.post-item-hd
{
.post-item-hd
{
display
:
flex
;
display
:
flex
;
}
}
...
@@ -67,6 +77,18 @@ const username = $computed(() => {
...
@@ -67,6 +77,18 @@ const username = $computed(() => {
font-weight
:
400
;
font-weight
:
400
;
line-height
:
20px
;
line-height
:
20px
;
color
:
#666
;
color
:
#666
;
.is-hot
{
display
:
inline-block
;
margin-left
:
14px
;
width
:
20px
;
height
:
20px
;
font-size
:
14px
;
line-height
:
20px
;
color
:
#fff
;
background-color
:
#ff8923
;
text-align
:
center
;
border-radius
:
2px
;
}
}
}
.post-item__reply_count
{
.post-item__reply_count
{
font-size
:
14px
;
font-size
:
14px
;
...
...
src/modules/bbs/components/PostPinned.vue
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
TopPostItem
}
from
'../types'
import
type
{
TopPostItem
}
from
'../types'
import
{
getTopPostList
}
from
'../api'
import
{
getTopPostList
}
from
'../api'
interface
Props
{
courseId
?:
string
semesterId
?:
string
}
const
props
=
defineProps
<
Props
>
()
let
list
=
$ref
<
TopPostItem
[]
>
([])
let
list
=
$ref
<
TopPostItem
[]
>
([])
function
fetchList
()
{
function
fetchList
()
{
getTopPostList
().
then
(
res
=>
{
getTopPostList
(
{
course_id
:
props
.
courseId
,
semester_id
:
props
.
semesterId
}
).
then
(
res
=>
{
list
=
res
.
data
.
list
list
=
res
.
data
.
list
})
})
}
}
...
@@ -15,12 +21,14 @@ onMounted(fetchList)
...
@@ -15,12 +21,14 @@ onMounted(fetchList)
<
template
>
<
template
>
<section
class=
"pined-post"
v-if=
"list.length"
>
<section
class=
"pined-post"
v-if=
"list.length"
>
<section
class=
"pined-post-item"
v-for=
"item in list"
:key=
"item.id"
>
<section
class=
"pined-post-item"
v-for=
"item in list"
:key=
"item.id"
>
<router-link
:to=
"`/bbs/$
{item.id}`" target="_blank" class="pined-post-item__inner">
<p
class=
"t1"
>
置顶
</p>
<p
class=
"t1"
>
置顶
</p>
<p
class=
"t2"
>
{{
item
.
title
}}
</p>
<p
class=
"t2"
>
{{
item
.
title
}}
</p>
<p
class=
"t3"
>
<p
class=
"t3"
>
<span>
{{
item
.
typ
e
}}
</span>
<span>
{{
item
.
course
.
nam
e
}}
</span>
</p>
</p>
<p
class=
"t4"
>
{{
item
.
updated_time
}}
</p>
<p
class=
"t4"
>
{{
item
.
updated_time
}}
</p>
</router-link>
</section>
</section>
</section>
</section>
</
template
>
</
template
>
...
@@ -28,12 +36,18 @@ onMounted(fetchList)
...
@@ -28,12 +36,18 @@ onMounted(fetchList)
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
.pined-post
{
.pined-post
{
padding-bottom
:
16px
;
padding-bottom
:
16px
;
border-bottom
:
1px
solid
#e6e6e6
;
}
}
.pined-post-item
{
.pined-post-item
__inner
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
}
.pined-post-item
{
padding
:
14px
0
;
padding
:
14px
0
;
&
:hover
{
.t2
{
color
:
var
(
--
main-color
);
}
}
.t1
{
.t1
{
padding
:
0
4px
;
padding
:
0
4px
;
height
:
20px
;
height
:
20px
;
...
@@ -56,6 +70,7 @@ onMounted(fetchList)
...
@@ -56,6 +70,7 @@ onMounted(fetchList)
text-align
:
center
;
text-align
:
center
;
span
{
span
{
display
:
inline-block
;
display
:
inline-block
;
padding
:
0
20px
;
min-width
:
90px
;
min-width
:
90px
;
height
:
30px
;
height
:
30px
;
line-height
:
30px
;
line-height
:
30px
;
...
...
src/modules/bbs/types.ts
浏览文件 @
b1b50306
...
@@ -31,7 +31,9 @@ export interface PostItem extends Post {
...
@@ -31,7 +31,9 @@ export interface PostItem extends Post {
sso_user
:
User
sso_user
:
User
}
}
export
type
TopPostItem
=
Pick
<
Post
,
'id'
|
'title'
|
'type'
|
'created_time'
|
'updated_time'
|
'top_time'
>
export
type
TopPostItem
=
Pick
<
Post
,
'id'
|
'title'
|
'type'
|
'created_time'
|
'updated_time'
|
'top_time'
>
&
{
course
:
Course
}
export
interface
DiscussItem
{
export
interface
DiscussItem
{
id
:
string
id
:
string
...
@@ -89,3 +91,9 @@ export interface File {
...
@@ -89,3 +91,9 @@ export interface File {
size
:
string
size
:
string
upload_time
:
string
upload_time
:
string
}
}
export
interface
Course
{
id
:
string
name
:
string
cover
:
string
}
src/modules/bbs/views/Index.vue
浏览文件 @
b1b50306
...
@@ -7,9 +7,16 @@ import { getPostList } from '../api'
...
@@ -7,9 +7,16 @@ import { getPostList } from '../api'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useMapStore
}
from
'@/stores/map'
import
{
useGetCourseList
}
from
'@/composables/useGetCourseList'
import
{
useGetCourseList
}
from
'@/composables/useGetCourseList'
interface
Props
{
courseId
?:
string
semesterId
?:
string
}
const
props
=
defineProps
<
Props
>
()
const
PostForm
=
defineAsyncComponent
(()
=>
import
(
'../components/PostForm.vue'
))
const
PostForm
=
defineAsyncComponent
(()
=>
import
(
'../components/PostForm.vue'
))
const
{
courses
,
course
Id
,
chapters
}
=
useGetCourseList
()
const
{
courses
,
course
Value
,
chapters
}
=
useGetCourseList
()
const
courseList
=
$computed
(()
=>
{
const
courseList
=
$computed
(()
=>
{
return
[{
value
:
''
,
label
:
'全部课程'
},
...
courses
.
value
]
return
[{
value
:
''
,
label
:
'全部课程'
},
...
courses
.
value
]
})
})
...
@@ -24,9 +31,38 @@ const currentTypes = $computed(() => {
...
@@ -24,9 +31,38 @@ const currentTypes = $computed(() => {
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
const
appList
=
$ref
<
InstanceType
<
typeof
AppList
>
|
null
>
(
null
)
const
params
=
reactive
({
search_by
:
0
,
order_by
:
0
,
course_id
:
''
,
semester_id
:
''
,
chapter_id
:
''
,
type
:
''
})
const
params
=
reactive
({
search_by
:
0
,
order_by
:
0
,
course_id
:
props
.
courseId
||
''
,
semester_id
:
props
.
semesterId
||
''
,
chapter_id
:
''
,
type
:
''
})
// 列表配置
// 列表配置
const
listOptions
=
computed
(()
=>
{
const
listOptions
=
computed
(()
=>
{
const
filters
=
[
{
type
:
'select'
,
prop
:
'chapter_id'
,
placeholder
:
'请选择'
,
options
:
chapterList
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'select'
,
prop
:
'search_by'
,
placeholder
:
'请选择'
,
options
:
bbsSearchByList
},
{
type
:
'select'
,
prop
:
'type'
,
placeholder
:
'请选择'
,
options
:
currentTypes
},
{
type
:
'select'
,
prop
:
'order_by'
,
placeholder
:
'请选择'
,
options
:
bbsOrderByList
}
]
!
props
.
courseId
&&
filters
.
unshift
({
type
:
'select'
,
prop
:
'course_id'
,
placeholder
:
'请选择'
,
options
:
courseList
,
labelKey
:
'name'
,
valueKey
:
'course_id'
})
return
{
return
{
hasFilterButton
:
false
,
hasFilterButton
:
false
,
remote
:
{
remote
:
{
...
@@ -37,34 +73,14 @@ const listOptions = computed(() => {
...
@@ -37,34 +73,14 @@ const listOptions = computed(() => {
requestParams
.
chapter_id
=
''
requestParams
.
chapter_id
=
''
}
}
params
.
course_id
=
requestParams
.
course_id
||
''
params
.
course_id
=
requestParams
.
course_id
||
''
course
Id
.
value
=
params
.
course_id
course
Value
.
value
=
params
.
course_id
return
requestParams
return
requestParams
},
},
callback
(
res
:
{
total
:
number
;
data
:
any
})
{
callback
(
res
:
{
total
:
number
;
data
:
any
})
{
return
{
total
:
res
.
total
,
list
:
res
.
data
}
return
{
total
:
res
.
total
,
list
:
res
.
data
}
}
}
},
},
filters
:
[
filters
{
type
:
'select'
,
prop
:
'course_id'
,
placeholder
:
'请选择'
,
options
:
courseList
,
labelKey
:
'name'
,
valueKey
:
'course_id'
},
{
type
:
'select'
,
prop
:
'chapter_id'
,
placeholder
:
'请选择'
,
options
:
chapterList
,
labelKey
:
'name'
,
valueKey
:
'id'
},
{
type
:
'select'
,
prop
:
'search_by'
,
placeholder
:
'请选择'
,
options
:
bbsSearchByList
},
{
type
:
'select'
,
prop
:
'type'
,
placeholder
:
'请选择'
,
options
:
currentTypes
},
{
type
:
'select'
,
prop
:
'order_by'
,
placeholder
:
'请选择'
,
options
:
bbsOrderByList
}
]
}
}
})
})
// 刷新
// 刷新
...
@@ -77,18 +93,23 @@ const postFormVisible = $ref(false)
...
@@ -77,18 +93,23 @@ const postFormVisible = $ref(false)
<
template
>
<
template
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
header-prepend
>
<template
#
header-prepend
>
<el-button
round
type=
"primary"
@
click=
"postFormVisible = true"
>
我要发帖
</el-button>
<el-button
round
type=
"primary"
@
click=
"postFormVisible = true"
style=
"margin-right: 30px"
>
我要发帖
</el-button>
</
template
>
</
template
>
<
template
#
body=
"{ data }"
>
<
template
#
body=
"{ data }"
>
<!-- 置顶帖子 -->
<!-- 置顶帖子 -->
<PostPinned></PostPinned>
<PostPinned
:courseId=
"courseId"
:semesterId=
"semesterId"
></PostPinned>
<template
v-if=
"data.length"
>
<template
v-if=
"data.length"
>
<PostItem
:data=
"item"
v-for=
"item in data"
:key=
"item.id"
></PostItem>
<PostItem
:data=
"item"
v-for=
"item in data"
:key=
"item.id"
></PostItem>
</
template
>
</
template
>
<el-empty
description=
"暂无数据"
v-else
/>
<el-empty
description=
"暂无数据"
v-else
/>
</template>
</template>
</AppList>
</AppList>
<PostForm
v-model=
"postFormVisible"
@
update=
"handleRefetch"
v-if=
"postFormVisible"
></PostForm>
<PostForm
:courseId=
"courseId"
:semesterId=
"semesterId"
v-model=
"postFormVisible"
@
update=
"handleRefetch"
v-if=
"postFormVisible"
></PostForm>
</template>
</template>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
...
...
src/modules/bbs/views/View.vue
浏览文件 @
b1b50306
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
import
type
{
Post
}
from
'../types'
import
type
{
Post
}
from
'../types'
import
{
ArrowUp
}
from
'@element-plus/icons-vue'
import
AppList
from
'@/components/base/AppList.vue'
import
AppList
from
'@/components/base/AppList.vue'
import
DiscussItem
from
'../components/DiscussItem.vue'
import
DiscussItem
from
'../components/DiscussItem.vue'
import
{
getPostAndDiscussList
}
from
'../api'
import
{
getPostAndDiscussList
}
from
'../api'
import
{
collectionResource
}
from
'@/api/base'
const
DiscussForm
=
defineAsyncComponent
(()
=>
import
(
'../components/DiscussForm.vue'
))
const
DiscussForm
=
defineAsyncComponent
(()
=>
import
(
'../components/DiscussForm.vue'
))
...
@@ -35,22 +36,40 @@ function handleRefetch() {
...
@@ -35,22 +36,40 @@ function handleRefetch() {
appList
?.
refetch
()
appList
?.
refetch
()
}
}
const
discussFormVisible
=
$ref
(
false
)
const
discussFormVisible
=
$ref
(
false
)
// 收藏/取消收藏
function
toggleCollection
()
{
collectionResource
({
course_id
:
detail
.
course_id
,
semester_id
:
detail
.
semester_id
,
chapter_id
:
detail
.
chapter_id
,
source_id
:
detail
.
id
,
type
:
6
,
status
:
1
}).
then
(()
=>
{
// data.collection_count = data.collection_count ? 0 : 1
})
}
</
script
>
</
script
>
<
template
>
<
template
>
<div
class=
"bbs"
>
<div
class=
"bbs"
>
<div
class=
"bbs-hd"
v-if=
"detail"
>
<div
class=
"bbs-hd"
v-if=
"detail"
>
<h1>
{{
detail
.
title
}}
</h1>
<h1>
{{
detail
.
title
}}
</h1>
<el-button
round
auto-insert-space
>
收藏
</el-button>
<el-button
round
auto-insert-space
@
click=
"toggleCollection"
>
收藏
</el-button>
<el-button
round
type=
"primary"
auto-insert-space
@
click=
"discussFormVisible = true"
>
回复
</el-button>
<el-button
round
type=
"primary"
auto-insert-space
@
click=
"discussFormVisible = true"
>
回复
</el-button>
</div>
</div>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<AppList
v-bind=
"listOptions"
ref=
"appList"
>
<template
#
body=
"
{ data }">
<template
#
body=
"
{ data }">
<DiscussItem
:data=
"item"
v-for=
"item in data"
:key=
"item.id"
></DiscussItem>
<DiscussItem
:
landlordId=
"detail.sso_id"
:
data=
"item"
v-for=
"item in data"
:key=
"item.id"
></DiscussItem>
</
template
>
</
template
>
</AppList>
</AppList>
</div>
</div>
<DiscussForm
v-model=
"discussFormVisible"
:id=
"id"
@
update=
"handleRefetch"
v-if=
"discussFormVisible"
></DiscussForm>
<DiscussForm
v-model=
"discussFormVisible"
:id=
"id"
@
update=
"handleRefetch"
v-if=
"discussFormVisible"
></DiscussForm>
<el-backtop
:right=
"22"
:bottom=
"100"
>
<el-icon><ArrowUp
/></el-icon>
<span
class=
"t1"
>
返回
<br
/>
顶部
</span>
</el-backtop>
</template>
</template>
<
style
lang=
"scss"
>
<
style
lang=
"scss"
>
...
@@ -63,12 +82,34 @@ const discussFormVisible = $ref(false)
...
@@ -63,12 +82,34 @@ const discussFormVisible = $ref(false)
}
}
}
}
.bbs-hd
{
.bbs-hd
{
position
:
relative
;
padding
:
20px
;
padding
:
20px
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
border-bottom
:
1px
solid
#e4e4e4
;
border-bottom
:
1px
solid
#e4e4e4
;
box-shadow
:
#e4e4e4
0px
5px
10px
;
z-index
:
10
;
h1
{
h1
{
flex
:
1
;
flex
:
1
;
}
}
}
}
.el-backtop
{
width
:
60px
;
height
:
60px
;
color
:
#000
;
.t1
{
display
:
none
;
font-size
:
14px
;
color
:
#fff
;
}
&
:hover
{
background-color
:
var
(
--
main-color
);
.el-icon
{
display
:
none
;
}
.t1
{
display
:
inline-block
;
}
}
}
</
style
>
</
style
>
src/modules/course/components/CourseViewBBS.vue
浏览文件 @
b1b50306
<!-- 论坛 -->
<!-- 论坛 -->
<
script
setup
lang=
"ts"
></
script
>
<
script
setup
lang=
"ts"
>
import
BBSIndex
from
'@/modules/bbs/views/Index.vue'
const
route
=
useRoute
()
const
courseId
=
route
.
query
.
course_id
as
string
const
semesterId
=
route
.
query
.
semester_id
as
string
</
script
>
<
template
>
<
template
>
<el-empty
description=
"暂无数据"
/>
<div
style=
"margin: 0 -20px"
>
<BBSIndex
:courseId=
"courseId"
:semesterId=
"semesterId"
></BBSIndex>
</div>
</
template
>
</
template
>
src/modules/favorites/types.ts
浏览文件 @
b1b50306
import
type
{
CourseType
,
ChapterType
,
ResourceType
}
from
'@/types'
import
type
{
CourseType
,
ChapterType
,
ResourceType
}
from
'@/types'
type
CollectionInfo
=
ResourceType
&
{
id
:
string
sso_id
:
string
sso_type
:
number
title
:
string
semester_id
:
string
class_id
:
string
course_id
:
string
chapter_id
:
string
type
:
number
is_top
:
number
top_time
:
null
is_hot
:
number
pv
:
number
uv
:
number
reply_count
:
number
created_time
:
string
updated_time
:
string
delete_time
:
number
}
export
interface
CollectionType
{
export
interface
CollectionType
{
chapter_id
:
string
chapter_id
:
string
course_id
:
string
course_id
:
string
id
:
string
id
:
string
info
:
ResourceType
info
:
CollectionInfo
section_id
:
string
section_id
:
string
semester_id
:
string
semester_id
:
string
semester
:
CollectionSemesterType
semester
:
CollectionSemesterType
...
...
src/modules/favorites/views/Index.vue
浏览文件 @
b1b50306
...
@@ -148,7 +148,7 @@ function targetUrl2(item: CollectionType) {
...
@@ -148,7 +148,7 @@ function targetUrl2(item: CollectionType) {
<p>
<p>
<router-link
:to=
"targetUrl(item)"
target=
"_blank"
>
<router-link
:to=
"targetUrl(item)"
target=
"_blank"
>
<ResourceIcon
:resourceType=
"item.resource_type"
:info=
"item.info"
/>
<ResourceIcon
:resourceType=
"item.resource_type"
:info=
"item.info"
/>
{{
item
.
info
.
name
||
item
.
info
.
paper_title
}}
{{
item
.
info
.
name
||
item
.
info
.
title
||
item
.
info
.
paper_title
}}
</router-link>
</router-link>
</p>
</p>
<p>
<p>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论