增加编辑用户弹窗分组管理并同步保存后的成员版本
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-25 23:34:49 +08:00
parent 32c378445f
commit 7bcbfe7288
5 changed files with 91 additions and 4 deletions

View File

@ -122,7 +122,10 @@ func SetAccountGroupMembership(ctx *context.Context, w http.ResponseWriter, req
return
}
InvalidateSecurityRuntimeUser(user.ID, user.Account)
response.NewSuccessResponse(map[string]any{"user_id": user.ID}).FPrint(w)
response.NewSuccessResponse(map[string]any{
"user_id": user.ID,
"membership_version": user.SecurityVersion + 1,
}).FPrint(w)
}
func writeAccountGroupError(w http.ResponseWriter, err error) {

View File

@ -3,7 +3,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { http } from '@/utils/axios'
import { isRecentAuthenticationCancelled, requestWithRecentAuthentication } from '@/utils/recentAuthentication'
export function useAccountGroups(globalStatus) {
export function useAccountGroups(globalStatus, onMembershipSaved = () => {}) {
const accountGroups = ref([])
const groupsLoading = ref(false)
const groupsError = ref('')
@ -125,6 +125,13 @@ export function useAccountGroups(globalStatus) {
group_ids: [...membershipSelection.value]
}))
if (response?.errorNo !== 0) throw new Error(response?.errorMsg || '保存成员分组失败')
const updatedUser = {
...membershipUser.value,
GroupIDs: [...membershipSelection.value],
MembershipVersion: response.data.membership_version
}
membershipUser.value = updatedUser
onMembershipSaved(updatedUser)
membershipVisible.value = false
ElMessage.success('成员分组已更新,目标账号需重新登录')
await refreshGroups()

View File

@ -217,3 +217,32 @@
.membership-select {
width: 100%;
}
.membership-summary {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
width: 100%;
}
.membership-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
min-width: 0;
}
.membership-tags :deep(.el-tag) {
height: auto;
white-space: normal;
overflow-wrap: anywhere;
}
.membership-hint {
margin: 8px 0 0;
color: var(--pm-text-secondary);
font-size: 12px;
line-height: 1.6;
}

View File

@ -48,7 +48,9 @@ export function canManageRecoveryCode(user) {
export function usePage() {
const globalStatus = useGlobalStatusStore()
const groups = useAccountGroups(globalStatus)
const groups = useAccountGroups(globalStatus, user => {
if (selectedUser.value?.ID === user.ID) selectedUser.value = user
})
const userInfoDialog = ref(false)
@ -56,6 +58,21 @@ export function usePage() {
const selectedUser = ref(null)
const selectedMembershipGroups = computed(() => {
const user = selectedUser.value
if (!user) return []
return groups.accountGroups.value.filter(group =>
groups.canManageGroups.value
? (user.GroupIDs || [0]).includes(group.id)
: group.rows.some(member => member.ID === user.ID)
)
})
const openMembershipDialog = () => {
if (submitting.value || !selectedUser.value) return
groups.editMembership(selectedUser.value)
}
const recoveryCodeDialogVisible = ref(false)
const externalEmailDialogVisible = ref(false)
@ -219,6 +236,8 @@ export function usePage() {
roleChanged,
submitting,
selectedUser,
selectedMembershipGroups,
openMembershipDialog,
editingCurrentUser,
recoveryCodeWebManaged,
recoveryCodeDialogVisible,

View File

@ -119,7 +119,7 @@
</div>
</section>
<el-dialog v-model="membershipVisible" title="设置账号所属分组" width="450px" :close-on-click-modal="!groupSaving" :close-on-press-escape="!groupSaving" :show-close="!groupSaving">
<el-dialog v-model="membershipVisible" title="设置账号所属分组" width="450px" :close-on-click-modal="!groupSaving" :close-on-press-escape="!groupSaving" :show-close="!groupSaving" append-to-body>
<p>账号:{{ membershipUser?.Account }}</p>
<el-form label-position="top">
<el-form-item label="所属分组">
@ -188,6 +188,33 @@
</span>
</el-form-item>
<el-form-item v-if="editModel === 'edit'" label="所属分组">
<div class="membership-summary">
<div class="membership-tags">
<el-tag
v-for="group in selectedMembershipGroups"
:key="group.id"
effect="plain"
>
{{ group.name }}
</el-tag>
</div>
<el-button
v-if="canManageGroups"
:disabled="submitting || groupSaving || groupsLoading || Boolean(groupsError)"
@click="openMembershipDialog"
>
分组管理
</el-button>
</div>
<p v-if="canManageGroups" class="membership-hint">
分组单独保存,不会提交本窗口其他修改;选择数量按账号已保存的权限级别校验。
</p>
<p v-else class="membership-hint">
仅显示你有权查看的分组,成员归属由超级管理员维护。
</p>
</el-form-item>
<div v-if="editModel === 'edit'" class="security-edit-grid">
<div class="security-edit-item">
<div>
@ -301,6 +328,8 @@ const {
roleChanged,
submitting,
selectedUser,
selectedMembershipGroups,
openMembershipDialog,
editingCurrentUser,
recoveryCodeWebManaged,
recoveryCodeDialogVisible,