zzw
23 小时以前 f651ad5716aa86afafc16e8abe342ed7ddd9d986
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<template>
  <div class="page">
    <div class="page-title">
      <div><h2>角色管理</h2><p>维护角色信息,并可按角色设置所属用户和菜单按钮权限</p></div>
      <el-button type="primary" icon="el-icon-plus" v-permission="'system:roles:add'" @click="openCreate">新增角色</el-button>
    </div>
    <div class="table-panel">
      <el-table :data="rows" border stripe height="calc(100vh - 190px)">
        <el-table-column prop="sortNo" label="排序" width="80" align="center"></el-table-column>
        <el-table-column prop="name" label="角色名称" min-width="180"></el-table-column>
        <el-table-column prop="code" label="角色编码" width="170"></el-table-column>
        <el-table-column prop="roleType" label="角色类型" width="170"></el-table-column>
        <el-table-column prop="remark" label="备注" min-width="220" show-overflow-tooltip></el-table-column>
        <el-table-column label="操作" width="300" fixed="right">
          <template slot-scope="{ row }">
            <el-button type="text" v-permission="'system:roles:assign'" @click="openUserSetting(row)">用户设置</el-button>
            <el-button type="text" v-permission="'system:roles:permission'" @click="openPermissionSetting(row)">权限设置</el-button>
            <el-button type="text" v-permission="'system:roles:edit'" @click="openEdit(row)">编辑</el-button>
            <el-button type="text" class="danger-link" v-permission="'system:roles:delete'" @click="remove(row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
 
    <el-dialog :title="form.id ? '编辑角色' : '新增角色'" :visible.sync="dialogVisible" width="560px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="95px">
        <el-form-item label="角色名称" prop="name"><el-input v-model="form.name"></el-input></el-form-item>
        <el-form-item label="角色编码" prop="code"><el-input v-model="form.code"></el-input></el-form-item>
        <el-form-item label="角色类型">
          <el-select v-model="form.roleType" style="width:100%">
            <el-option label="业务角色" value="BUSINESS"></el-option>
            <el-option label="系统管理员" value="SYSTEM_ADMIN"></el-option>
            <el-option label="安全保密管理员" value="SECURITY_ADMIN"></el-option>
            <el-option label="安全审计管理员" value="AUDIT_ADMIN"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="排序"><el-input-number v-model="form.sortNo" :min="1" style="width:160px"></el-input-number></el-form-item>
        <el-form-item label="备注"><el-input v-model="form.remark" type="textarea" :rows="3"></el-input></el-form-item>
      </el-form>
      <template slot="footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">保存</el-button></template>
    </el-dialog>
 
    <el-dialog title="角色用户设置" :visible.sync="userDialogVisible" width="820px" append-to-body :close-on-click-modal="false">
      <div class="user-setting-head">
        <div>
          <span class="role-label">当前角色</span>
          <strong>{{ currentRole.name }}</strong>
          <span class="role-code">{{ currentRole.code }}</span>
        </div>
        <span class="selected-total">已选择 {{ selectedUserIds.length }} 人</span>
      </div>
      <div class="user-setting-toolbar">
        <el-radio-group v-model="userScope" size="small">
          <el-radio-button label="all">全部</el-radio-button>
          <el-radio-button label="assigned">已设置</el-radio-button>
        </el-radio-group>
        <el-input v-model="userKeyword" clearable prefix-icon="el-icon-search" placeholder="用户名 / 账户名 / 部门" style="width: 280px"></el-input>
      </div>
      <el-table
        ref="roleUserTable"
        v-loading="userLoading"
        :data="filteredUsers"
        row-key="userId"
        height="430"
        border
        stripe
        @selection-change="handleUserSelectionChange"
      >
        <el-table-column type="selection" reserve-selection width="48" align="center"></el-table-column>
        <el-table-column prop="nickName" label="用户名" min-width="120"></el-table-column>
        <el-table-column prop="userName" label="账户名" min-width="140"></el-table-column>
        <el-table-column prop="deptName" label="所属部门" min-width="180" show-overflow-tooltip></el-table-column>
        <el-table-column label="状态" width="80" align="center">
          <template slot-scope="{ row }">
            <el-tag size="mini" :type="row.status === '1' ? 'info' : 'success'">{{ row.status === '1' ? '停用' : '正常' }}</el-tag>
          </template>
        </el-table-column>
      </el-table>
      <template slot="footer">
        <el-button @click="userDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="userSaving" v-permission="'system:roles:assign'" @click="saveRoleUsers">保存</el-button>
      </template>
    </el-dialog>
 
    <role-permission-dialog :visible.sync="permissionDialogVisible" :role="currentRole"></role-permission-dialog>
  </div>
</template>
<script>
import api from '@/api'
import RolePermissionDialog from './RolePermissionDialog.vue'
export default {
  name: 'RoleManage',
  components: { RolePermissionDialog },
  data() {
    return {
      rows: [],
      dialogVisible: false,
      permissionDialogVisible: false,
      saving: false,
      userDialogVisible: false,
      userLoading: false,
      userSaving: false,
      userKeyword: '',
      userScope: 'all',
      roleUsers: [],
      selectedUserIds: [],
      currentRole: {},
      form: {},
      rules: {
        name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
        code: [{ required: true, message: '请输入角色编码', trigger: 'blur' }]
      }
    }
  },
  computed: {
    filteredUsers() {
      const assigned = new Set(this.selectedUserIds.map(String))
      const users = this.userScope === 'assigned'
        ? this.roleUsers.filter(item => assigned.has(String(item.userId)))
        : this.roleUsers
      const keyword = this.userKeyword.trim().toLowerCase()
      if (!keyword) return users
      return users.filter(item => [item.nickName, item.userName, item.deptName]
        .some(value => String(value || '').toLowerCase().includes(keyword)))
    }
  },
  created() { this.load() },
  methods: {
    load() {
      api.get('/system/roles').then(res => { this.rows = res.data || [] })
    },
    openCreate() {
      this.form = { name: '', code: '', roleType: 'BUSINESS', sortNo: this.rows.length + 1, remark: '' }
      this.dialogVisible = true
    },
    openEdit(row) {
      this.form = { ...row }
      this.dialogVisible = true
    },
    save() {
      this.$refs.form.validate(valid => {
        if (!valid) return
        this.saving = true
        const request = this.form.id ? api.put('/system/roles/' + this.form.id, this.form) : api.post('/system/roles', this.form)
        request.then(() => {
          this.$message.success('保存成功')
          this.dialogVisible = false
          this.load()
        }).finally(() => { this.saving = false })
      })
    },
    remove(row) {
      this.$confirm(`确定删除角色“${row.name}”吗?`, '删除确认', { type: 'warning' })
        .then(() => api.delete('/system/roles/' + row.id))
        .then(() => { this.$message.success('删除成功'); this.load() })
        .catch(() => {})
    },
    openUserSetting(row) {
      this.currentRole = { ...row }
      this.userKeyword = ''
      this.userScope = 'all'
      this.selectedUserIds = []
      this.roleUsers = []
      this.userDialogVisible = true
      this.userLoading = true
      api.get('/system/roles/' + row.id + '/users').then(res => {
        const data = res.data || {}
        this.roleUsers = data.records || []
        this.selectedUserIds = (data.userIds || []).map(String)
        this.$nextTick(this.restoreUserSelection)
      }).finally(() => { this.userLoading = false })
    },
    openPermissionSetting(row) {
      this.currentRole = { ...row }
      this.permissionDialogVisible = true
    },
    restoreUserSelection() {
      const table = this.$refs.roleUserTable
      if (!table) return
      table.clearSelection()
      const selected = new Set(this.selectedUserIds)
      this.roleUsers.forEach(row => {
        if (selected.has(String(row.userId))) table.toggleRowSelection(row, true)
      })
      this.$nextTick(() => {
        table.clearSelection()
        this.roleUsers.forEach(row => {
          if (selected.has(String(row.userId))) table.toggleRowSelection(row, true)
        })
        this.selectedUserIds = Array.from(selected)
      })
    },
    handleUserSelectionChange(selection) {
      this.selectedUserIds = (selection || []).map(item => String(item.userId))
    },
    saveRoleUsers() {
      const userIds = this.selectedUserIds.slice()
      const message = userIds.length
        ? `确定将“${this.currentRole.name}”角色设置为选中的 ${userIds.length} 个用户吗?`
        : `未选择用户,将清空“${this.currentRole.name}”角色的全部用户,是否继续?`
      this.$confirm(message, '角色用户设置', { type: 'warning' }).then(() => {
        this.userSaving = true
        api.put('/system/roles/' + this.currentRole.id + '/users', { userIds }).then(() => {
          this.$message.success('角色用户设置已保存')
          this.userDialogVisible = false
        }).finally(() => { this.userSaving = false })
      }).catch(() => {})
    }
  }
}
</script>
<style scoped>
.danger-link { color: #d9534f; }
.user-setting-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; color: #31465d; }
.role-label { margin-right: 10px; color: #7b8b9c; font-size: 13px; }
.role-code { margin-left: 8px; color: #93a2b1; font-size: 12px; }
.selected-total { color: #2f658f; font-size: 13px; }
.user-setting-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
</style>