refactor: Fix UI/UX issues across admin pages
- App.vue: max-w-4xl → max-w-6xl(讓表格不被截斷) - 新增 AdminCredsCard.vue 共用元件,消除兩個頁面的重複認證卡片 - PermissionAdminPage / PermissionGroupsPage 改用 AdminCredsCard - 所有 el-table 的 slot="empty" 換成 <template #empty>(Vue 3 正確用法) - 4 個管理頁 Dialog 補 el-form rules + formRef.validate()(取代手動 if 檢查) - MembersPage: authentik_sub / email 欄位加 show-overflow-tooltip - PermissionGroupsPage: 成功/失敗訊息由 <p> 改為 el-alert(統一樣式) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<el-button v-if="authStore.isLoggedIn" size="small" @click="logout">登出</el-button>
|
<el-button v-if="authStore.isLoggedIn" size="small" @click="logout">登出</el-button>
|
||||||
</nav>
|
</nav>
|
||||||
<main class="p-6 max-w-4xl mx-auto">
|
<main class="p-6 max-w-6xl mx-auto">
|
||||||
<router-view />
|
<router-view />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
64
frontend/src/components/AdminCredsCard.vue
Normal file
64
frontend/src/components/AdminCredsCard.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<el-card class="mb-6 shadow-sm">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="font-medium text-gray-700">管理員認證</span>
|
||||||
|
<el-tag v-if="credsSaved" type="success" size="small">已儲存(session)</el-tag>
|
||||||
|
<el-tag v-else type="warning" size="small">未設定</el-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-form :model="credsForm" inline>
|
||||||
|
<el-form-item label="X-Client-Key">
|
||||||
|
<el-input
|
||||||
|
v-model="credsForm.clientKey"
|
||||||
|
placeholder="client key"
|
||||||
|
style="width: 220px"
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="X-API-Key">
|
||||||
|
<el-input
|
||||||
|
v-model="credsForm.apiKey"
|
||||||
|
placeholder="api key"
|
||||||
|
style="width: 220px"
|
||||||
|
show-password
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="saveCreds">儲存認證</el-button>
|
||||||
|
<el-button v-if="credsSaved" @click="clearCreds" class="ml-2">清除</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, computed } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { usePermissionStore } from '@/stores/permission'
|
||||||
|
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
const credsForm = reactive({
|
||||||
|
clientKey: permissionStore.adminClientKey,
|
||||||
|
apiKey: permissionStore.adminApiKey
|
||||||
|
})
|
||||||
|
|
||||||
|
const credsSaved = computed(() => permissionStore.hasAdminCreds())
|
||||||
|
|
||||||
|
function saveCreds() {
|
||||||
|
if (!credsForm.clientKey || !credsForm.apiKey) {
|
||||||
|
ElMessage.warning('請填寫完整認證')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
permissionStore.setAdminCreds(credsForm.clientKey, credsForm.apiKey)
|
||||||
|
ElMessage.success('認證已儲存(session)')
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCreds() {
|
||||||
|
permissionStore.clearAdminCreds()
|
||||||
|
credsForm.clientKey = ''
|
||||||
|
credsForm.apiKey = ''
|
||||||
|
ElMessage.info('認證已清除')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -17,18 +17,18 @@
|
|||||||
<el-skeleton v-if="loading" :rows="4" animated />
|
<el-skeleton v-if="loading" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="companies" stripe border class="w-full shadow-sm">
|
<el-table v-else :data="companies" stripe border class="w-full shadow-sm">
|
||||||
<el-empty v-if="companies.length === 0" slot="empty" description="目前無公司" />
|
<template #empty><el-empty description="目前無公司" /></template>
|
||||||
<el-table-column prop="company_key" label="Company Key" width="200" />
|
<el-table-column prop="company_key" label="Company Key" width="200" />
|
||||||
<el-table-column prop="name" label="名稱" min-width="180" />
|
<el-table-column prop="name" label="名稱" min-width="180" />
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 新增 Dialog -->
|
<!-- 新增 Dialog -->
|
||||||
<el-dialog v-model="showDialog" title="新增公司" @close="resetForm">
|
<el-dialog v-model="showDialog" title="新增公司" @close="resetForm">
|
||||||
<el-form :model="form" label-width="100px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="Company Key">
|
<el-form-item label="Company Key" prop="company_key">
|
||||||
<el-input v-model="form.company_key" placeholder="company-001" />
|
<el-input v-model="form.company_key" placeholder="company-001" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="名稱">
|
<el-form-item label="名稱" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="公司名稱" />
|
<el-input v-model="form.name" placeholder="公司名稱" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -52,8 +52,13 @@ const error = ref(false)
|
|||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
const form = ref({ company_key: '', name: '' })
|
const form = ref({ company_key: '', name: '' })
|
||||||
|
const rules = {
|
||||||
|
company_key: [{ required: true, message: '請輸入 Company Key', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '請輸入名稱', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -74,10 +79,8 @@ function resetForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
if (!form.value.company_key || !form.value.name) {
|
const valid = await formRef.value.validate().catch(() => false)
|
||||||
ElMessage.warning('請填寫完整資訊')
|
if (!valid) return
|
||||||
return
|
|
||||||
}
|
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await createCompany(form.value)
|
await createCompany(form.value)
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
<el-skeleton v-if="loading" :rows="4" animated />
|
<el-skeleton v-if="loading" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="members" stripe border class="w-full shadow-sm">
|
<el-table v-else :data="members" stripe border class="w-full shadow-sm">
|
||||||
<el-empty v-if="members.length === 0" slot="empty" description="目前無會員" />
|
<template #empty><el-empty description="目前無會員" /></template>
|
||||||
<el-table-column prop="authentik_sub" label="Authentik Sub" min-width="200" />
|
<el-table-column prop="authentik_sub" label="Authentik Sub" min-width="240" show-overflow-tooltip />
|
||||||
<el-table-column prop="email" label="Email" min-width="200" />
|
<el-table-column prop="email" label="Email" min-width="200" show-overflow-tooltip />
|
||||||
<el-table-column prop="display_name" label="顯示名稱" width="150" />
|
<el-table-column prop="display_name" label="顯示名稱" width="150" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<el-skeleton v-if="loading" :rows="4" animated />
|
<el-skeleton v-if="loading" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="modules" stripe border class="w-full shadow-sm">
|
<el-table v-else :data="modules" stripe border class="w-full shadow-sm">
|
||||||
<el-empty v-if="modules.length === 0" slot="empty" description="目前無模組" />
|
<template #empty><el-empty description="目前無模組" /></template>
|
||||||
<el-table-column prop="system_key" label="System Key" width="140" />
|
<el-table-column prop="system_key" label="System Key" width="140" />
|
||||||
<el-table-column prop="module_key" label="Module Key" width="160" />
|
<el-table-column prop="module_key" label="Module Key" width="160" />
|
||||||
<el-table-column prop="name" label="名稱" min-width="180" />
|
<el-table-column prop="name" label="名稱" min-width="180" />
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
|
|
||||||
<!-- 新增 Dialog -->
|
<!-- 新增 Dialog -->
|
||||||
<el-dialog v-model="showDialog" title="新增模組" @close="resetForm">
|
<el-dialog v-model="showDialog" title="新增模組" @close="resetForm">
|
||||||
<el-form :model="form" label-width="120px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-form-item label="System Key">
|
<el-form-item label="System Key" prop="system_key">
|
||||||
<el-input v-model="form.system_key" placeholder="mkt" />
|
<el-input v-model="form.system_key" placeholder="mkt" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Module Key">
|
<el-form-item label="Module Key" prop="module_key">
|
||||||
<el-input v-model="form.module_key" placeholder="campaign" />
|
<el-input v-model="form.module_key" placeholder="campaign" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="名稱">
|
<el-form-item label="名稱" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="行銷活動" />
|
<el-input v-model="form.name" placeholder="行銷活動" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -56,8 +56,14 @@ const error = ref(false)
|
|||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
const form = ref({ system_key: '', module_key: '', name: '' })
|
const form = ref({ system_key: '', module_key: '', name: '' })
|
||||||
|
const rules = {
|
||||||
|
system_key: [{ required: true, message: '請輸入 System Key', trigger: 'blur' }],
|
||||||
|
module_key: [{ required: true, message: '請輸入 Module Key', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '請輸入名稱', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -78,10 +84,8 @@ function resetForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
if (!form.value.system_key || !form.value.module_key || !form.value.name) {
|
const valid = await formRef.value.validate().catch(() => false)
|
||||||
ElMessage.warning('請填寫完整資訊')
|
if (!valid) return
|
||||||
return
|
|
||||||
}
|
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await createModule(form.value)
|
await createModule(form.value)
|
||||||
|
|||||||
@@ -2,28 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-bold text-gray-800 mb-6">權限群組管理</h2>
|
<h2 class="text-xl font-bold text-gray-800 mb-6">權限群組管理</h2>
|
||||||
|
|
||||||
<!-- 認證 -->
|
<AdminCredsCard />
|
||||||
<el-card class="mb-6 shadow-sm">
|
|
||||||
<template #header>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="font-medium text-gray-700">管理員認證</span>
|
|
||||||
<el-tag v-if="credsSaved" type="success" size="small">已儲存(session)</el-tag>
|
|
||||||
<el-tag v-else type="warning" size="small">未設定</el-tag>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-form :model="credsForm" inline>
|
|
||||||
<el-form-item label="X-Client-Key">
|
|
||||||
<el-input v-model="credsForm.clientKey" placeholder="client key" style="width: 220px" show-password />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="X-API-Key">
|
|
||||||
<el-input v-model="credsForm.apiKey" placeholder="api key" style="width: 220px" show-password />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="saveCreds">儲存認證</el-button>
|
|
||||||
<el-button v-if="credsSaved" @click="clearCreds" class="ml-2">清除</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<el-tabs v-model="activeTab" type="border-card" class="shadow-sm">
|
<el-tabs v-model="activeTab" type="border-card" class="shadow-sm">
|
||||||
<!-- Groups Tab -->
|
<!-- Groups Tab -->
|
||||||
@@ -37,7 +16,7 @@
|
|||||||
<el-skeleton v-if="loadingGroups" :rows="4" animated />
|
<el-skeleton v-if="loadingGroups" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="groups" stripe border class="w-full">
|
<el-table v-else :data="groups" stripe border class="w-full">
|
||||||
<el-empty v-if="groups.length === 0" slot="empty" description="目前無群組" />
|
<template #empty><el-empty description="目前無群組" /></template>
|
||||||
<el-table-column prop="group_key" label="Group Key" width="180" />
|
<el-table-column prop="group_key" label="Group Key" width="180" />
|
||||||
<el-table-column prop="name" label="群組名稱" min-width="200" />
|
<el-table-column prop="name" label="群組名稱" min-width="200" />
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -63,8 +42,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<p v-if="memberError" class="text-red-600 text-sm mb-2">{{ memberError }}</p>
|
<el-alert v-if="memberError" :title="memberError" type="error" show-icon :closable="false" class="mt-3" />
|
||||||
<p v-if="memberSuccess" class="text-green-600 text-sm mb-2">{{ memberSuccess }}</p>
|
<el-alert v-if="memberSuccess" :title="memberSuccess" type="success" show-icon :closable="false" class="mt-3" />
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|
||||||
@@ -116,8 +95,8 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<p v-if="groupPermError" class="text-red-600 text-sm mb-2">{{ groupPermError }}</p>
|
<el-alert v-if="groupPermError" :title="groupPermError" type="error" show-icon :closable="false" class="mt-3" />
|
||||||
<p v-if="groupPermSuccess" class="text-green-600 text-sm mb-2">{{ groupPermSuccess }}</p>
|
<el-alert v-if="groupPermSuccess" :title="groupPermSuccess" type="success" show-icon :closable="false" class="mt-3" />
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
@@ -152,34 +131,12 @@ import {
|
|||||||
groupGrant,
|
groupGrant,
|
||||||
groupRevoke
|
groupRevoke
|
||||||
} from '@/api/permission-groups'
|
} from '@/api/permission-groups'
|
||||||
|
import AdminCredsCard from '@/components/AdminCredsCard.vue'
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
const activeTab = ref('groups')
|
const activeTab = ref('groups')
|
||||||
|
|
||||||
// 認證
|
|
||||||
const credsForm = reactive({
|
|
||||||
clientKey: permissionStore.adminClientKey,
|
|
||||||
apiKey: permissionStore.adminApiKey
|
|
||||||
})
|
|
||||||
|
|
||||||
const credsSaved = computed(() => permissionStore.hasAdminCreds())
|
const credsSaved = computed(() => permissionStore.hasAdminCreds())
|
||||||
|
|
||||||
function saveCreds() {
|
|
||||||
if (!credsForm.clientKey || !credsForm.apiKey) {
|
|
||||||
ElMessage.warning('請填寫完整認證')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
permissionStore.setAdminCreds(credsForm.clientKey, credsForm.apiKey)
|
|
||||||
ElMessage.success('認證已儲存(session)')
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearCreds() {
|
|
||||||
permissionStore.clearAdminCreds()
|
|
||||||
credsForm.clientKey = ''
|
|
||||||
credsForm.apiKey = ''
|
|
||||||
ElMessage.info('認證已清除')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Groups
|
// Groups
|
||||||
const groups = ref([])
|
const groups = ref([])
|
||||||
const loadingGroups = ref(false)
|
const loadingGroups = ref(false)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<el-skeleton v-if="loading" :rows="4" animated />
|
<el-skeleton v-if="loading" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="sites" stripe border class="w-full shadow-sm">
|
<el-table v-else :data="sites" stripe border class="w-full shadow-sm">
|
||||||
<el-empty v-if="sites.length === 0" slot="empty" description="目前無站台" />
|
<template #empty><el-empty description="目前無站台" /></template>
|
||||||
<el-table-column prop="site_key" label="Site Key" width="160" />
|
<el-table-column prop="site_key" label="Site Key" width="160" />
|
||||||
<el-table-column prop="company_key" label="Company Key" width="160" />
|
<el-table-column prop="company_key" label="Company Key" width="160" />
|
||||||
<el-table-column prop="name" label="名稱" min-width="180" />
|
<el-table-column prop="name" label="名稱" min-width="180" />
|
||||||
@@ -25,14 +25,14 @@
|
|||||||
|
|
||||||
<!-- 新增 Dialog -->
|
<!-- 新增 Dialog -->
|
||||||
<el-dialog v-model="showDialog" title="新增站台" @close="resetForm">
|
<el-dialog v-model="showDialog" title="新增站台" @close="resetForm">
|
||||||
<el-form :model="form" label-width="120px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||||
<el-form-item label="Site Key">
|
<el-form-item label="Site Key" prop="site_key">
|
||||||
<el-input v-model="form.site_key" placeholder="site-001" />
|
<el-input v-model="form.site_key" placeholder="site-001" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Company Key">
|
<el-form-item label="Company Key" prop="company_key">
|
||||||
<el-input v-model="form.company_key" placeholder="company-001" />
|
<el-input v-model="form.company_key" placeholder="company-001" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="名稱">
|
<el-form-item label="名稱" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="站台名稱" />
|
<el-input v-model="form.name" placeholder="站台名稱" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -56,8 +56,14 @@ const error = ref(false)
|
|||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
const form = ref({ site_key: '', company_key: '', name: '' })
|
const form = ref({ site_key: '', company_key: '', name: '' })
|
||||||
|
const rules = {
|
||||||
|
site_key: [{ required: true, message: '請輸入 Site Key', trigger: 'blur' }],
|
||||||
|
company_key: [{ required: true, message: '請輸入 Company Key', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '請輸入名稱', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -78,10 +84,8 @@ function resetForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
if (!form.value.site_key || !form.value.company_key || !form.value.name) {
|
const valid = await formRef.value.validate().catch(() => false)
|
||||||
ElMessage.warning('請填寫完整資訊')
|
if (!valid) return
|
||||||
return
|
|
||||||
}
|
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await createSite(form.value)
|
await createSite(form.value)
|
||||||
|
|||||||
@@ -17,18 +17,18 @@
|
|||||||
<el-skeleton v-if="loading" :rows="4" animated />
|
<el-skeleton v-if="loading" :rows="4" animated />
|
||||||
|
|
||||||
<el-table v-else :data="systems" stripe border class="w-full shadow-sm">
|
<el-table v-else :data="systems" stripe border class="w-full shadow-sm">
|
||||||
<el-empty v-if="systems.length === 0" slot="empty" description="目前無系統" />
|
<template #empty><el-empty description="目前無系統" /></template>
|
||||||
<el-table-column prop="system_key" label="System Key" width="200" />
|
<el-table-column prop="system_key" label="System Key" width="200" />
|
||||||
<el-table-column prop="name" label="名稱" min-width="180" />
|
<el-table-column prop="name" label="名稱" min-width="180" />
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 新增 Dialog -->
|
<!-- 新增 Dialog -->
|
||||||
<el-dialog v-model="showDialog" title="新增系統" @close="resetForm">
|
<el-dialog v-model="showDialog" title="新增系統" @close="resetForm">
|
||||||
<el-form :model="form" label-width="100px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="System Key">
|
<el-form-item label="System Key" prop="system_key">
|
||||||
<el-input v-model="form.system_key" placeholder="mkt" />
|
<el-input v-model="form.system_key" placeholder="mkt" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="名稱">
|
<el-form-item label="名稱" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="行銷平台" />
|
<el-input v-model="form.name" placeholder="行銷平台" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -52,8 +52,13 @@ const error = ref(false)
|
|||||||
const errorMsg = ref('')
|
const errorMsg = ref('')
|
||||||
const showDialog = ref(false)
|
const showDialog = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
const form = ref({ system_key: '', name: '' })
|
const form = ref({ system_key: '', name: '' })
|
||||||
|
const rules = {
|
||||||
|
system_key: [{ required: true, message: '請輸入 System Key', trigger: 'blur' }],
|
||||||
|
name: [{ required: true, message: '請輸入名稱', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -74,10 +79,8 @@ function resetForm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleCreate() {
|
async function handleCreate() {
|
||||||
if (!form.value.system_key || !form.value.name) {
|
const valid = await formRef.value.validate().catch(() => false)
|
||||||
ElMessage.warning('請填寫完整資訊')
|
if (!valid) return
|
||||||
return
|
|
||||||
}
|
|
||||||
submitting.value = true
|
submitting.value = true
|
||||||
try {
|
try {
|
||||||
await createSystem(form.value)
|
await createSystem(form.value)
|
||||||
|
|||||||
@@ -2,38 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-bold text-gray-800 mb-6">權限管理</h2>
|
<h2 class="text-xl font-bold text-gray-800 mb-6">權限管理</h2>
|
||||||
|
|
||||||
<!-- 認證設定 -->
|
<AdminCredsCard />
|
||||||
<el-card class="mb-6 shadow-sm">
|
|
||||||
<template #header>
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="font-medium text-gray-700">管理員認證</span>
|
|
||||||
<el-tag v-if="credsSaved" type="success" size="small">已儲存(session)</el-tag>
|
|
||||||
<el-tag v-else type="warning" size="small">未設定</el-tag>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<el-form :model="credsForm" inline>
|
|
||||||
<el-form-item label="X-Client-Key">
|
|
||||||
<el-input
|
|
||||||
v-model="credsForm.clientKey"
|
|
||||||
placeholder="client key"
|
|
||||||
style="width: 220px"
|
|
||||||
show-password
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="X-API-Key">
|
|
||||||
<el-input
|
|
||||||
v-model="credsForm.apiKey"
|
|
||||||
placeholder="api key"
|
|
||||||
style="width: 220px"
|
|
||||||
show-password
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
|
||||||
<el-button type="primary" @click="saveCreds">儲存認證</el-button>
|
|
||||||
<el-button v-if="credsSaved" @click="clearCreds" class="ml-2">清除</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
<!-- Grant / Revoke -->
|
<!-- Grant / Revoke -->
|
||||||
<el-tabs v-model="activeTab" type="border-card" class="shadow-sm">
|
<el-tabs v-model="activeTab" type="border-card" class="shadow-sm">
|
||||||
@@ -178,35 +147,13 @@
|
|||||||
import { ref, reactive, computed } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { usePermissionStore } from '@/stores/permission'
|
import { usePermissionStore } from '@/stores/permission'
|
||||||
|
import AdminCredsCard from '@/components/AdminCredsCard.vue'
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const activeTab = ref('grant')
|
const activeTab = ref('grant')
|
||||||
|
|
||||||
// 認證
|
|
||||||
const credsForm = reactive({
|
|
||||||
clientKey: permissionStore.adminClientKey,
|
|
||||||
apiKey: permissionStore.adminApiKey
|
|
||||||
})
|
|
||||||
|
|
||||||
const credsSaved = computed(() => permissionStore.hasAdminCreds())
|
const credsSaved = computed(() => permissionStore.hasAdminCreds())
|
||||||
|
|
||||||
function saveCreds() {
|
|
||||||
if (!credsForm.clientKey || !credsForm.apiKey) {
|
|
||||||
ElMessage.warning('請填寫完整認證')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
permissionStore.setAdminCreds(credsForm.clientKey, credsForm.apiKey)
|
|
||||||
ElMessage.success('認證已儲存(session)')
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearCreds() {
|
|
||||||
permissionStore.clearAdminCreds()
|
|
||||||
credsForm.clientKey = ''
|
|
||||||
credsForm.apiKey = ''
|
|
||||||
ElMessage.info('認證已清除')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grant
|
// Grant
|
||||||
const grantFormRef = ref()
|
const grantFormRef = ref()
|
||||||
const grantLoading = ref(false)
|
const grantLoading = ref(false)
|
||||||
|
|||||||
Reference in New Issue
Block a user