Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
corporate-culture-qd
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王立鹏
corporate-culture-qd
Commits
cf9ae590
Commit
cf9ae590
authored
Oct 08, 2026
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 25171】fix: 实践查看权限保存字段改为 finalPermissions,并显式传各类型避免旧的公开权限残留
parent
3cf73794
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
63 additions
and
67 deletions
+63
-67
types.ts
src/api/article/types.ts
+4
-5
types.ts
src/api/practice/types.ts
+5
-4
index.vue
src/components/common/PublishBox/index.vue
+3
-11
practicePermission.ts
src/utils/practicePermission.ts
+43
-0
index.vue
src/views/backend/contentsMenu/practiceManage/index.vue
+4
-21
PracticeForm.vue
src/views/publishLongArticle/components/PracticeForm.vue
+4
-26
No files found.
src/api/article/types.ts
View file @
cf9ae590
...
...
@@ -265,8 +265,7 @@ export interface ArticleItemDto {
publishTime
:
number
// 官方账号推送的文章才有这个字段,列表接口直接带出来,不用再单独查一次推送状态
pushInfo
?:
ArticlePushInfoDto
// 实践的查看权限回显(详情接口才有)。跟保存时传的 valueList(纯 id 数组)不一样,
// 这里是 finalPermissions(带 valueName),方便直接拿来回显名字,不用再反查一次。
// 实践的查看权限回显(详情接口才有),结构跟 addOrUpdatePractice 保存时传的一样
typeUpdates
?:
ArticleTypeUpdateEchoDto
[]
// 视频分类,只有视频类型才有;categoryIdList/categoryNameList 按下标一一对应,
// 详情接口回显的分类里可能包含已被设为不公开的分类,前端需要把它们并进下拉选项里
...
...
@@ -275,11 +274,11 @@ export interface ArticleItemDto {
}
/**
* 实践查看权限的回显(getArticleDetail 返回),
跟保存时的 PracticeTypeUpdateDto 结构不同:
*
保存传 valueList(纯 id 数组),这里返回 finalPermissions(带 valueName,方便直接回显)。
* 实践查看权限的回显(getArticleDetail 返回),
结构跟保存时的 PracticeTypeUpdateDto 一样,
*
只是多了 valueType=0 的「公开」这一组(没选范围时后端存的默认值),回显时要跳过它
*/
export
interface
ArticleTypeUpdateEchoDto
{
/** 1 部门 / 2 人员 */
/**
0 公开 /
1 部门 / 2 人员 */
valueType
:
number
finalPermissions
:
{
valueId
:
string
;
valueName
:
string
}[]
}
...
...
src/api/practice/types.ts
View file @
cf9ae590
...
...
@@ -2,12 +2,13 @@ import { ArticleTypeEnum, ReleaseStatusTypeEnum, BooleanFlag, SendTypeEnum } fro
import
type
{
PageSearchParams
}
from
'@/utils/request/types'
/**
* 保存查看权限时传的一组:valueType 1 部门 / 2 人员,valueList 是纯 id 数组
* (valueType=2 时 valueId 存的是 user_id,不是企微账号)。
* 保存查看权限时传的一组:valueType 0 公开 / 1 部门 / 2 人员(valueType=2 时 valueId 存的是 user_id,不是企微账号)。
* 字段名必须是 finalPermissions,跟详情接口返回的结构完全一致——后端不认识的字段会被直接忽略,
* 传错了后端会当成「没选范围」,按默认规则存(官方账号就是公开)。finalPermissions 传空数组表示删掉这一类
*/
export
interface
PracticeTypeUpdateDto
{
valueType
:
1
|
2
valueList
:
string
[]
valueType
:
0
|
1
|
2
finalPermissions
:
{
valueId
:
string
;
valueName
:
string
}
[]
}
/**
...
...
src/components/common/PublishBox/index.vue
View file @
cf9ae590
...
...
@@ -214,6 +214,7 @@ import {
import
{
useTagsStore
}
from
'@/stores'
import
{
addOrUpdatePractice
,
addOrUpdateArticle
}
from
'@/api'
import
type
{
AddOrUpdatePracticeDto
}
from
'@/api'
import
{
buildPracticeTypeUpdates
}
from
'@/utils/practicePermission'
import
type
{
ElButton
}
from
'element-plus'
import
{
useAnimate
}
from
'@vueuse/core'
import
RichTextarea
from
'../RichTextarea/index.vue'
...
...
@@ -348,18 +349,9 @@ const validateForm = () => {
return
true
}
// 把选中的部门/人员按 valueType 分组,一个都没选就不传 typeUpdates(不要传空数组硬凑)
const
buildTypeUpdates
=
()
=>
{
const
depts
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
1
)
const
users
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
2
)
const
typeUpdates
:
{
valueType
:
1
|
2
;
valueList
:
string
[]
}[]
=
[]
if
(
depts
.
length
)
typeUpdates
.
push
({
valueType
:
1
,
valueList
:
depts
.
map
((
item
)
=>
item
.
valueId
)
})
if
(
users
.
length
)
typeUpdates
.
push
({
valueType
:
2
,
valueList
:
users
.
map
((
item
)
=>
item
.
valueId
)
})
return
typeUpdates
}
const
transformForm
=
(
releaseStatus
:
ReleaseStatusTypeEnum
):
AddOrUpdatePracticeDto
=>
{
const
typeUpdates
=
buildTypeUpdates
()
// 一个都没选就不传 typeUpdates,由后端按默认规则处理
const
typeUpdates
=
buildPracticeTypeUpdates
(
permissionSelection
.
value
)
return
{
...
form
.
value
,
releaseStatus
,
...
...
src/utils/practicePermission.ts
0 → 100644
View file @
cf9ae590
import
type
{
DepartmentUserSelection
}
from
'@/components/common/DepartmentUserModal/types'
import
type
{
ArticleTypeUpdateEchoDto
}
from
'@/api/article/types'
import
type
{
PracticeTypeUpdateDto
}
from
'@/api/practice/types'
/**
* 实践「查看权限」选中的部门/人员 → addOrUpdatePractice 的 typeUpdates。
*
* - 一个都没选:返回空数组,调用方不传 typeUpdates,由后端按默认规则处理(不要传空数组硬凑)。
* - 选了:0 公开 / 1 部门 / 2 人员 三组都显式传。后端是按类型逐个比对增删的,没传的类型
* 原样保留——比如原来是公开(有一条 valueType=0)、现在改成指定部门,不显式传一个空的公开组,
* 那条公开记录就删不掉,文章照样所有人可见。
*/
export
const
buildPracticeTypeUpdates
=
(
selection
:
DepartmentUserSelection
[],
):
PracticeTypeUpdateDto
[]
=>
{
if
(
!
selection
.
some
((
item
)
=>
item
.
valueType
===
1
||
item
.
valueType
===
2
))
return
[]
const
pick
=
(
valueType
:
1
|
2
)
=>
selection
.
filter
((
item
)
=>
item
.
valueType
===
valueType
)
.
map
((
item
)
=>
({
valueId
:
item
.
valueId
,
valueName
:
item
.
valueName
}))
return
[
{
valueType
:
0
,
finalPermissions
:
[]
},
{
valueType
:
1
,
finalPermissions
:
pick
(
1
)
},
{
valueType
:
2
,
finalPermissions
:
pick
(
2
)
},
]
}
/**
* 详情接口回显的 typeUpdates → DeptUserPicker 认的选中项。
* 没设过范围时后端返回的是 valueType=0 的「公开」,不是部门也不是人,要跳过
*/
export
const
toPracticeSelection
=
(
typeUpdates
?:
ArticleTypeUpdateEchoDto
[],
):
DepartmentUserSelection
[]
=>
(
typeUpdates
??
[])
.
filter
((
group
)
=>
group
.
valueType
===
1
||
group
.
valueType
===
2
)
.
flatMap
((
group
)
=>
group
.
finalPermissions
.
map
((
item
)
=>
({
valueType
:
group
.
valueType
as
1
|
2
,
valueId
:
item
.
valueId
,
valueName
:
item
.
valueName
,
})),
)
src/views/backend/contentsMenu/practiceManage/index.vue
View file @
cf9ae590
...
...
@@ -7,7 +7,8 @@ import type { FormInstance, FormRules } from 'element-plus'
import
type
{
BackendColumnListItemDto
,
AddOrUpdateColumnDto
}
from
'@/api/backend'
import
dayjs
from
'dayjs'
import
{
ArticleTypeEnum
,
BooleanFlag
}
from
'@/constants'
import
type
{
ArticleItemDto
,
ArticleTypeUpdateEchoDto
}
from
'@/api/article/types'
import
type
{
ArticleItemDto
}
from
'@/api/article/types'
import
{
buildPracticeTypeUpdates
,
toPracticeSelection
}
from
'@/utils/practicePermission'
import
{
push
}
from
'notivue'
import
{
useMessageBox
}
from
'@/hooks'
import
ArticleContentDialog
from
'@/components/common/ArticleContentDialog/index.vue'
...
...
@@ -116,24 +117,10 @@ const permissionDeptIds = ref<string[]>([])
const
permissionUserIds
=
ref
<
string
[]
>
([])
const
permissionSelection
=
ref
<
DepartmentUserSelection
[]
>
([])
// 详情接口回显的查看权限是 finalPermissions(带名字),转成 DeptUserPicker 认的 DepartmentUserSelection
const
toSelectionFromTypeUpdates
=
(
typeUpdates
?:
ArticleTypeUpdateEchoDto
[],
):
DepartmentUserSelection
[]
=>
{
if
(
!
typeUpdates
)
return
[]
return
typeUpdates
.
flatMap
((
group
)
=>
group
.
finalPermissions
.
map
((
item
)
=>
({
valueType
:
group
.
valueType
as
1
|
2
,
valueId
:
item
.
valueId
,
valueName
:
item
.
valueName
,
})),
)
}
const
handleEditPermission
=
async
(
row
:
ArticleItemDto
)
=>
{
const
{
data
}
=
await
getArticleDetail
(
row
.
id
)
permissionDetail
.
value
=
data
const
items
=
to
SelectionFromTypeUpdates
(
data
.
typeUpdates
)
const
items
=
to
PracticeSelection
(
data
.
typeUpdates
)
permissionDeptIds
.
value
=
items
.
filter
((
item
)
=>
item
.
valueType
===
1
).
map
((
item
)
=>
item
.
valueId
)
permissionUserIds
.
value
=
items
.
filter
((
item
)
=>
item
.
valueType
===
2
).
map
((
item
)
=>
item
.
valueId
)
permissionSelection
.
value
=
items
...
...
@@ -143,11 +130,7 @@ const handleEditPermission = async (row: ArticleItemDto) => {
const
handleSubmitPermission
=
async
()
=>
{
if
(
!
permissionDetail
.
value
)
return
const
depts
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
1
)
const
users
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
2
)
const
typeUpdates
:
{
valueType
:
1
|
2
;
valueList
:
string
[]
}[]
=
[]
if
(
depts
.
length
)
typeUpdates
.
push
({
valueType
:
1
,
valueList
:
depts
.
map
((
item
)
=>
item
.
valueId
)
})
if
(
users
.
length
)
typeUpdates
.
push
({
valueType
:
2
,
valueList
:
users
.
map
((
item
)
=>
item
.
valueId
)
})
const
typeUpdates
=
buildPracticeTypeUpdates
(
permissionSelection
.
value
)
const
detail
=
permissionDetail
.
value
permissionSubmitting
.
value
=
true
...
...
src/views/publishLongArticle/components/PracticeForm.vue
View file @
cf9ae590
...
...
@@ -100,7 +100,8 @@ import UploadFile from '@/components/common/UploadFile/index.vue'
import
SelectTags
from
'@/components/common/SelectTags/index.vue'
import
DeptUserPicker
from
'@/components/common/DeptUserPicker/index.vue'
import
type
{
DepartmentUserSelection
}
from
'@/components/common/DepartmentUserModal/types'
import
type
{
ArticleItemDto
,
ArticleTypeUpdateEchoDto
}
from
'@/api/article/types'
import
type
{
ArticleItemDto
}
from
'@/api/article/types'
import
{
buildPracticeTypeUpdates
,
toPracticeSelection
}
from
'@/utils/practicePermission'
import
{
useResetData
}
from
'@/hooks'
import
{
useUserStore
}
from
'@/stores/user'
import
{
storeToRefs
}
from
'pinia'
...
...
@@ -151,34 +152,11 @@ const rules: Record<string, FormItemRule[]> = {
regionHide
:
[{
required
:
true
,
message
:
'请选择是否隐藏IP信息'
,
trigger
:
'trigger'
}],
}
// 把选中的部门/人员按 valueType 分组,一个都没选就不传 typeUpdates(不要传空数组硬凑)
const
buildTypeUpdates
=
()
=>
{
const
depts
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
1
)
const
users
=
permissionSelection
.
value
.
filter
((
item
)
=>
item
.
valueType
===
2
)
const
typeUpdates
:
{
valueType
:
1
|
2
;
valueList
:
string
[]
}[]
=
[]
if
(
depts
.
length
)
typeUpdates
.
push
({
valueType
:
1
,
valueList
:
depts
.
map
((
item
)
=>
item
.
valueId
)
})
if
(
users
.
length
)
typeUpdates
.
push
({
valueType
:
2
,
valueList
:
users
.
map
((
item
)
=>
item
.
valueId
)
})
return
typeUpdates
}
// 详情接口回显的查看权限是 finalPermissions(带名字),转成 DeptUserPicker 认的 DepartmentUserSelection
const
toSelectionFromTypeUpdates
=
(
typeUpdates
?:
ArticleTypeUpdateEchoDto
[],
):
DepartmentUserSelection
[]
=>
{
if
(
!
typeUpdates
)
return
[]
return
typeUpdates
.
flatMap
((
group
)
=>
group
.
finalPermissions
.
map
((
item
)
=>
({
valueType
:
group
.
valueType
as
1
|
2
,
valueId
:
item
.
valueId
,
valueName
:
item
.
valueName
,
})),
)
}
defineExpose
({
validate
:
()
=>
formRef
.
value
!
.
validate
(),
getSubmitData
:
()
=>
{
const
typeUpdates
=
build
TypeUpdates
(
)
const
typeUpdates
=
build
PracticeTypeUpdates
(
permissionSelection
.
value
)
return
{
imgUrl
:
form
.
value
.
imgUrl
,
faceUrl
:
form
.
value
.
imgUrl
?
form
.
value
.
imgUrl
.
split
(
','
)[
0
]
||
''
:
''
,
...
...
@@ -205,7 +183,7 @@ defineExpose({
form
.
value
.
deptId
=
data
.
deptId
===
'0'
?
''
:
data
.
deptId
}
const
items
=
to
SelectionFromTypeUpdates
(
data
.
typeUpdates
)
const
items
=
to
PracticeSelection
(
data
.
typeUpdates
)
permissionDeptIds
.
value
=
items
.
filter
((
item
)
=>
item
.
valueType
===
1
)
.
map
((
item
)
=>
item
.
valueId
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment