Files
member-frontend/src/pages/admin/RolesPage.vue

259 lines
8.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div class="flex items-center justify-between mb-6">
<h2 class="text-xl font-bold text-gray-800">角色管理</h2>
<el-button type="primary" @click="showCreateDialog = true" :icon="Plus">新增角色</el-button>
</div>
<el-alert v-if="error" :title="errorMsg" type="error" show-icon :closable="false" class="mb-4" />
<el-skeleton v-if="loading" :rows="4" animated />
<el-table v-else :data="roles" stripe border class="w-full shadow-sm">
<template #empty><el-empty description="目前無角色" /></template>
<el-table-column prop="role_key" label="Role Key" width="200" />
<el-table-column prop="system_name" label="系統" min-width="150" />
<el-table-column prop="name" label="角色名稱" min-width="180" />
<el-table-column prop="status" label="狀態" width="110" />
<el-table-column label="操作" width="280">
<template #default="{ row }">
<el-button size="small" @click="openEdit(row)">編輯</el-button>
<el-button size="small" @click="openSites(row)">站台</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">刪除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="showCreateDialog" title="新增角色" width="660px" @close="resetCreateForm">
<el-form ref="createFormRef" :model="createForm" :rules="rules" label-width="150px">
<el-form-item label="系統" prop="system_key">
<el-select v-model="createForm.system_key" filterable style="width: 100%">
<el-option
v-for="system in systems"
:key="system.system_key"
:label="`${system.name} (${system.system_key})`"
:value="system.system_key"
/>
</el-select>
</el-form-item>
<el-form-item label="角色名稱" prop="name"><el-input v-model="createForm.name" /></el-form-item>
<el-form-item label="描述"><el-input v-model="createForm.description" type="textarea" :rows="2" /></el-form-item>
<el-form-item label="狀態">
<el-select v-model="createForm.status" style="width: 100%">
<el-option label="active" value="active" />
<el-option label="inactive" value="inactive" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showCreateDialog = false">取消</el-button>
<el-button type="primary" :loading="creating" @click="handleCreate">建立</el-button>
</template>
</el-dialog>
<el-dialog v-model="showEditDialog" title="編輯角色" width="660px" @close="resetEditForm">
<el-form :model="editForm" label-width="150px">
<el-form-item label="Role Key"><el-input :model-value="editForm.role_key" disabled /></el-form-item>
<el-form-item label="系統">
<el-select v-model="editForm.system_key" filterable style="width: 100%">
<el-option
v-for="system in systems"
:key="system.system_key"
:label="`${system.name} (${system.system_key})`"
:value="system.system_key"
/>
</el-select>
</el-form-item>
<el-form-item label="角色名稱"><el-input v-model="editForm.name" /></el-form-item>
<el-form-item label="描述"><el-input v-model="editForm.description" type="textarea" :rows="2" /></el-form-item>
<el-form-item label="狀態">
<el-select v-model="editForm.status" style="width: 100%">
<el-option label="active" value="active" />
<el-option label="inactive" value="inactive" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showEditDialog = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="handleEdit">儲存</el-button>
</template>
</el-dialog>
<el-dialog v-model="showSitesDialog" :title="`角色綁定站台:${selectedRoleLabel}`" width="980px">
<el-table :data="roleSites" border stripe v-loading="sitesLoading">
<template #empty><el-empty description="此角色尚未綁定站台" /></template>
<el-table-column prop="company_display_name" label="公司" min-width="160" />
<el-table-column prop="site_display_name" label="站台" min-width="170" />
<el-table-column prop="site_key" label="Site Key" min-width="180" />
</el-table>
<template #footer>
<el-button @click="showSitesDialog = false">關閉</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { getRoles, createRole, updateRole, deleteRole, getRoleSites } from '@/api/roles'
import { getSystems } from '@/api/systems'
const roles = ref([])
const systems = ref([])
const loading = ref(false)
const error = ref(false)
const errorMsg = ref('')
const showCreateDialog = ref(false)
const showEditDialog = ref(false)
const creating = ref(false)
const saving = ref(false)
const createFormRef = ref()
const createForm = ref({
system_key: '',
name: '',
description: '',
status: 'active'
})
const editForm = ref({
role_key: '',
system_key: '',
name: '',
description: '',
status: 'active'
})
const rules = {
system_key: [{ required: true, message: '請選擇系統', trigger: 'change' }],
name: [{ required: true, message: '請輸入角色名稱', trigger: 'blur' }]
}
const showSitesDialog = ref(false)
const selectedRoleLabel = ref('')
const roleSites = ref([])
const sitesLoading = ref(false)
async function load() {
loading.value = true
error.value = false
try {
const [rolesRes, systemsRes] = await Promise.all([
getRoles({ limit: 500, offset: 0 }),
getSystems({ limit: 500, offset: 0 })
])
roles.value = rolesRes.data?.items || []
systems.value = systemsRes.data?.items || []
} catch (err) {
error.value = true
errorMsg.value = err.response?.data?.detail || '載入角色失敗'
} finally {
loading.value = false
}
}
function resetCreateForm() {
createForm.value = {
system_key: '',
name: '',
description: '',
status: 'active'
}
}
function openEdit(row) {
editForm.value = {
role_key: row.role_key,
system_key: row.system_key,
name: row.name,
description: row.description || '',
status: row.status || 'active'
}
showEditDialog.value = true
}
function resetEditForm() {
editForm.value = {
role_key: '',
system_key: '',
name: '',
description: '',
status: 'active'
}
}
async function handleCreate() {
const valid = await createFormRef.value.validate().catch(() => false)
if (!valid) return
creating.value = true
try {
await createRole({
system_key: createForm.value.system_key,
name: createForm.value.name,
description: createForm.value.description || null,
status: createForm.value.status
})
ElMessage.success('新增角色成功')
showCreateDialog.value = false
resetCreateForm()
await load()
} catch (err) {
ElMessage.error(err.response?.data?.detail || '新增角色失敗')
} finally {
creating.value = false
}
}
async function handleEdit() {
saving.value = true
try {
await updateRole(editForm.value.role_key, {
system_key: editForm.value.system_key,
name: editForm.value.name,
description: editForm.value.description || null,
status: editForm.value.status
})
ElMessage.success('更新成功')
showEditDialog.value = false
await load()
} catch (err) {
ElMessage.error(err.response?.data?.detail || '更新角色失敗')
} finally {
saving.value = false
}
}
async function handleDelete(row) {
try {
await ElMessageBox.confirm(
`確認刪除角色 ${row.name}${row.role_key}`,
'刪除確認',
{ type: 'warning' }
)
await deleteRole(row.role_key)
ElMessage.success('刪除成功')
await load()
} catch (err) {
if (err === 'cancel') return
ElMessage.error(err.response?.data?.detail || '刪除角色失敗')
}
}
async function openSites(row) {
selectedRoleLabel.value = `${row.system_name} / ${row.name}`
showSitesDialog.value = true
sitesLoading.value = true
try {
const res = await getRoleSites(row.role_key)
roleSites.value = res.data?.sites || []
} catch (_err) {
ElMessage.error('載入角色站台失敗')
roleSites.value = []
} finally {
sitesLoading.value = false
}
}
onMounted(load)
</script>