2.3权限管理,可添加运行

This commit is contained in:
YueL1331
2026-01-09 15:18:24 +08:00
parent 9c73e25937
commit c416c8ad07
14 changed files with 835 additions and 424 deletions

View File

@ -0,0 +1,192 @@
<template>
<div class="user-manage-container">
<el-card shadow="never" class="main-card">
<template #header>
<div class="header-row">
<div class="left-panel">
<h2 class="sys-title">👤 客户权限管理</h2>
</div>
<div class="header-actions">
<el-button @click="router.push('/dashboard')" icon="Back">返回监控</el-button>
<el-button type="primary" icon="Plus" @click="showCreateModal = true">新建客户</el-button>
</div>
</div>
</template>
<el-table :data="users" border style="width: 100%" v-loading="loading">
<el-table-column prop="id" label="ID" width="80" align="center" />
<el-table-column prop="username" label="客户名称" min-width="150" />
<el-table-column prop="created_at" label="创建时间" min-width="180">
<template #default="{ row }">
{{ new Date(row.created_at).toLocaleString() }}
</template>
</el-table-column>
<el-table-column label="可见设备" min-width="120">
<template #default="{ row }">
<el-tag>{{ row.allowed_device_ids?.length || 0 }} </el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center" fixed="right">
<template #default="{ row }">
<el-button type="primary" link icon="Setting" @click="openPermissionModal(row)">分配权限</el-button>
<el-popconfirm title="确定删除该客户吗?" @confirm="deleteUser(row.id)">
<template #reference>
<el-button type="danger" link icon="Delete">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="showCreateModal" title="新建客户账号" width="400px">
<el-form :model="newUser" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="newUser.username" placeholder="请输入客户登录名" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="newUser.password" type="password" placeholder="设置初始密码" show-password />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="showCreateModal = false">取消</el-button>
<el-button type="primary" @click="createClient">确认创建</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="showPermissionModal" :title="`给 ${currentUser?.username} 分配设备`" width="600px">
<div class="permission-transfer">
<el-transfer
v-model="selectedDeviceIds"
:data="allDevices"
:titles="['可选设备', '已授权设备']"
:props="{ key: 'id', label: 'label' }"
filterable
filter-placeholder="搜索设备"
/>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showPermissionModal = false">取消</el-button>
<el-button type="primary" @click="savePermissions">保存设置</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
// 🔴 修改 1: 引入 request
import request from '../utils/request'
import { ElMessage } from 'element-plus'
import { Back, Plus, Setting, Delete } from '@element-plus/icons-vue'
const router = useRouter()
// 🔴 修改 2: 删除 API_BASE
const loading = ref(false)
const users = ref([])
const rawDevices = ref([]) // 原始设备列表
const showCreateModal = ref(false)
const showPermissionModal = ref(false)
const newUser = ref({ username: '', password: '' })
const currentUser = ref(null)
const selectedDeviceIds = ref([])
// 转换设备数据供穿梭框使用
const allDevices = computed(() => {
return rawDevices.value.map(d => ({
id: d.id,
label: `${d.name} (${d.install_site || '未命名'})`
}))
})
onMounted(async () => {
await fetchUsers()
await fetchAllDevices()
})
const fetchUsers = async () => {
loading.value = true
try {
// 🔴 修改 3: 使用 request.get移除 headers
const res = await request.get('/api/admin/users')
users.value = res.data
} catch (e) {
// 拦截器已处理 401/403这里只处理通用错误提示
console.error(e)
} finally {
loading.value = false
}
}
const fetchAllDevices = async () => {
try {
// 🔴 修改 4: 使用 request.get复用 dashboard 接口
const res = await request.get('/api/devices_overview')
const list = res.data.data || res.data
rawDevices.value = list
} catch (e) {
console.error(e)
}
}
const createClient = async () => {
if (!newUser.value.username || !newUser.value.password) return ElMessage.warning('请填写完整')
try {
// 🔴 修改 5: 使用 request.post
await request.post('/api/admin/create_client', newUser.value)
ElMessage.success('创建成功')
showCreateModal.value = false
newUser.value = { username: '', password: '' }
fetchUsers()
} catch (e) {
ElMessage.error(e.response?.data?.msg || '创建失败')
}
}
const openPermissionModal = (user) => {
currentUser.value = user
// 回显已选权限
selectedDeviceIds.value = user.allowed_device_ids || []
showPermissionModal.value = true
}
const savePermissions = async () => {
try {
// 🔴 修改 6: 使用 request.post
await request.post('/api/admin/assign_devices', {
user_id: currentUser.value.id,
device_ids: selectedDeviceIds.value
})
ElMessage.success('权限已更新')
showPermissionModal.value = false
fetchUsers() // 刷新列表查看数量变化
} catch (e) {
ElMessage.error('保存失败')
}
}
const deleteUser = async (id) => {
ElMessage.info('删除功能暂需后端接口支持')
}
</script>
<style scoped>
.user-manage-container { padding: 10px; background: #f5f7fa; min-height: 100vh; box-sizing: border-box; }
.main-card { border-radius: 8px; min-height: 80vh; }
.header-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
.sys-title { margin: 0; font-size: 20px; color: #303133; font-weight: 700; }
.header-actions { display: flex; gap: 10px; }
:deep(.el-transfer-panel) { width: 220px; }
@media screen and (max-width: 768px) {
:deep(.el-transfer-panel) { width: 100%; margin-bottom: 10px; }
.permission-transfer { display: flex; flex-direction: column; }
}
</style>