refactor: 简化授权管理添加/编辑页面为单卡类选择
- 移除卡类列表,改为单选卡类 - 选择代理 → 选择应用 → 选择卡类 → 设置价格 - 修复面包屑导航名称 - 优化预览卡片展示 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Check, CheckCircle, Eye, KeyRound, Loader2, Plus, Trash2 } from 'lucide-vue-next'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { Check, Eye, KeyRound, Loader2 } from 'lucide-vue-next'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { toast } from 'vue-sonner'
|
||||
@@ -29,13 +29,6 @@ interface CardType {
|
||||
price: number
|
||||
}
|
||||
|
||||
interface PermissionItem {
|
||||
card_type_id: number
|
||||
card_type_name: string
|
||||
billing_type: string
|
||||
price: number
|
||||
}
|
||||
|
||||
const agentAppId = computed(() => route.params.id as string)
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
@@ -47,12 +40,11 @@ const cardTypes = ref<CardType[]>([])
|
||||
const form = ref({
|
||||
agent_id: '',
|
||||
application_id: '',
|
||||
card_type_id: '',
|
||||
price: 0,
|
||||
remark: '',
|
||||
})
|
||||
|
||||
const selectedCardTypeId = ref<string>('')
|
||||
const permissions = ref<PermissionItem[]>([])
|
||||
|
||||
const selectedAgent = computed(() => {
|
||||
if (form.value.agent_id) {
|
||||
return agents.value.find(a => String(a.id) === form.value.agent_id)
|
||||
@@ -67,8 +59,11 @@ const selectedApplication = computed(() => {
|
||||
return null
|
||||
})
|
||||
|
||||
const availableCardTypes = computed(() => {
|
||||
return cardTypes.value.filter(c => !permissions.value.some(p => p.card_type_id === c.id))
|
||||
const selectedCardType = computed(() => {
|
||||
if (form.value.card_type_id) {
|
||||
return cardTypes.value.find(ct => String(ct.id) === form.value.card_type_id)
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
async function fetchAgents() {
|
||||
@@ -90,7 +85,10 @@ async function fetchApplications() {
|
||||
}
|
||||
|
||||
async function fetchCardTypes(appId: string) {
|
||||
if (!appId) return
|
||||
if (!appId) {
|
||||
cardTypes.value = []
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = await api.get<{ card_types: CardType[] }>(`/dev/card-types?application_id=${appId}`)
|
||||
cardTypes.value = data?.card_types || []
|
||||
@@ -115,15 +113,12 @@ async function fetchAgentApp() {
|
||||
|
||||
await fetchCardTypes(String(agentApp.application_id))
|
||||
|
||||
permissions.value = agentApp.card_types?.map((c: any) => {
|
||||
const cardType = cardTypes.value.find(ct => ct.id === c.card_type_id)
|
||||
return {
|
||||
card_type_id: c.card_type_id,
|
||||
card_type_name: cardType?.name || `卡类 #${c.card_type_id}`,
|
||||
billing_type: cardType?.billing_type || '',
|
||||
price: c.price || 0,
|
||||
}
|
||||
}) || []
|
||||
// 取第一个卡类权限
|
||||
if (agentApp.card_types && agentApp.card_types.length > 0) {
|
||||
const firstCardType = agentApp.card_types[0]
|
||||
form.value.card_type_id = String(firstCardType.card_type_id)
|
||||
form.value.price = firstCardType.price || 0
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
@@ -135,27 +130,11 @@ async function fetchAgentApp() {
|
||||
}
|
||||
}
|
||||
|
||||
function addPermission() {
|
||||
if (!selectedCardTypeId.value) {
|
||||
toast.error(t('admin.agentApps.createForm.selectCardType'))
|
||||
return
|
||||
watch(selectedCardType, (ct) => {
|
||||
if (ct && !loading.value) {
|
||||
form.value.price = ct.price
|
||||
}
|
||||
|
||||
const cardType = cardTypes.value.find(ct => String(ct.id) === selectedCardTypeId.value)
|
||||
if (!cardType) return
|
||||
|
||||
permissions.value.push({
|
||||
card_type_id: cardType.id,
|
||||
card_type_name: cardType.name,
|
||||
billing_type: cardType.billing_type,
|
||||
price: cardType.price,
|
||||
})
|
||||
selectedCardTypeId.value = ''
|
||||
}
|
||||
|
||||
function removePermission(index: number) {
|
||||
permissions.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
|
||||
async function handleSave() {
|
||||
if (!form.value.agent_id) {
|
||||
@@ -168,23 +147,21 @@ async function handleSave() {
|
||||
return
|
||||
}
|
||||
|
||||
if (permissions.value.length === 0) {
|
||||
if (!form.value.card_type_id) {
|
||||
toast.error(t('admin.agentApps.createForm.selectCardRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
const cardTypesPayload = permissions.value.map(p => ({
|
||||
card_type_id: p.card_type_id,
|
||||
can_generate: true,
|
||||
price: Number(p.price),
|
||||
}))
|
||||
|
||||
await api.put(`/dev/agent-apps/${agentAppId.value}`, {
|
||||
agent_id: Number(form.value.agent_id),
|
||||
application_id: Number(form.value.application_id),
|
||||
card_types: cardTypesPayload,
|
||||
card_types: [{
|
||||
card_type_id: Number(form.value.card_type_id),
|
||||
can_generate: true,
|
||||
price: Number(form.value.price),
|
||||
}],
|
||||
discount: 0,
|
||||
remark: form.value.remark,
|
||||
})
|
||||
@@ -232,83 +209,73 @@ onMounted(() => {
|
||||
<UiCardDescription>{{ t('admin.agentApps.createForm.authConfigDesc') }}</UiCardDescription>
|
||||
</UiCardHeader>
|
||||
<UiCardContent class="space-y-6">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectAgent') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.agent_id" :disabled="saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAgentPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="agent in agents"
|
||||
:key="agent.id"
|
||||
:value="String(agent.id)"
|
||||
>
|
||||
{{ agent.username }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectApp') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.application_id" :disabled="saving" @update:model-value="fetchCardTypes($event)">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAppPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="app in applications"
|
||||
:key="app.id"
|
||||
:value="String(app.id)"
|
||||
>
|
||||
{{ app.name }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectCardType') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<div class="flex gap-3">
|
||||
<div class="flex-1">
|
||||
<UiSelect v-model="selectedCardTypeId" :disabled="!form.application_id || saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectCardTypePlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem v-for="ct in availableCardTypes" :key="ct.id" :value="String(ct.id)">
|
||||
{{ ct.name }}<template v-if="ct.billing_type"> ({{ ct.billing_type }})</template>
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
<UiButton @click="addPermission" :disabled="!form.application_id || saving">
|
||||
<Plus class="mr-1 h-4 w-4" />
|
||||
{{ t('admin.agentApps.createForm.addCardType') }}
|
||||
</UiButton>
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectAgent') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.agent_id" :disabled="saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAgentPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="agent in agents"
|
||||
:key="agent.id"
|
||||
:value="String(agent.id)"
|
||||
>
|
||||
{{ agent.username }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div v-if="permissions.length > 0" class="border rounded-lg divide-y max-h-64 overflow-y-auto">
|
||||
<div v-for="(p, index) in permissions" :key="p.card_type_id" class="flex items-center justify-between p-3 gap-4">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-medium truncate">{{ p.card_type_name }}</div>
|
||||
<div v-if="p.billing_type" class="text-sm text-muted-foreground">{{ p.billing_type }}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-muted-foreground">¥</span>
|
||||
<UiInput class="w-20 text-right" v-model.number="p.price" :placeholder="t('admin.agentApps.createForm.pricePlaceholder')" />
|
||||
</div>
|
||||
<UiButton variant="ghost" size="icon" @click="removePermission(index)" :disabled="saving">
|
||||
<Trash2 class="h-4 w-4 text-destructive" />
|
||||
</UiButton>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectApp') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.application_id" :disabled="saving" @update:model-value="fetchCardTypes($event)">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAppPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="app in applications"
|
||||
:key="app.id"
|
||||
:value="String(app.id)"
|
||||
>
|
||||
{{ app.name }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectCardType') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.card_type_id" :disabled="!form.application_id || saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectCardTypePlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem v-for="ct in cardTypes" :key="ct.id" :value="String(ct.id)">
|
||||
{{ ct.name }}<template v-if="ct.billing_type"> ({{ ct.billing_type }})</template>
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel for="price">{{ t('admin.agentApps.createForm.price') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">¥</span>
|
||||
<UiInput
|
||||
id="price"
|
||||
v-model.number="form.price"
|
||||
type="number"
|
||||
class="pl-7"
|
||||
:placeholder="t('admin.agentApps.createForm.pricePlaceholder')"
|
||||
:disabled="saving"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="text-sm text-muted-foreground text-center py-4">
|
||||
{{ form.application_id ? t('admin.agentApps.createForm.noCardTypes') : t('admin.agentApps.createForm.selectAppFirst') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@@ -344,29 +311,18 @@ onMounted(() => {
|
||||
<span>{{ selectedApplication?.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewCardTypes') }}</span>
|
||||
<span>{{ t('admin.agentApps.createForm.cardCount', { count: permissions.length }) }}</span>
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewCardType') }}</span>
|
||||
<span>{{ selectedCardType?.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewPrice') }}</span>
|
||||
<span>¥{{ form.price || 0 }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewRemark') }}</span>
|
||||
<span class="truncate max-w-[120px]">{{ form.remark || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="permissions.length > 0" class="border-t pt-4 mt-4">
|
||||
<p class="text-sm text-muted-foreground mb-2">
|
||||
{{ t('admin.agentApps.createForm.cardTypeList') }}
|
||||
</p>
|
||||
<div class="rounded-lg bg-muted/50 p-3 space-y-2 max-h-[150px] overflow-auto">
|
||||
<div v-for="p in permissions" :key="p.card_type_id" class="flex items-center justify-between text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<CheckCircle class="size-4 text-green-600" />
|
||||
<span>{{ p.card_type_name }}</span>
|
||||
</div>
|
||||
<span class="text-muted-foreground">¥{{ p.price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
|
||||
@@ -376,7 +332,7 @@ onMounted(() => {
|
||||
<UiButton
|
||||
class="w-full"
|
||||
size="lg"
|
||||
:disabled="saving || !form.agent_id || !form.application_id || permissions.length === 0"
|
||||
:disabled="saving || !form.agent_id || !form.application_id || !form.card_type_id"
|
||||
@click="handleSave"
|
||||
>
|
||||
<Loader2 v-if="saving" class="mr-2 h-4 w-4 animate-spin" />
|
||||
@@ -397,4 +353,4 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</BasicPage>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { CheckCircle, Eye, KeyRound, Loader2, Plus, Rocket, Trash2 } from 'lucide-vue-next'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { Eye, KeyRound, Loader2, Rocket } from 'lucide-vue-next'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { toast } from 'vue-sonner'
|
||||
@@ -28,13 +28,6 @@ interface CardType {
|
||||
price: number
|
||||
}
|
||||
|
||||
interface PermissionItem {
|
||||
card_type_id: number
|
||||
card_type_name: string
|
||||
billing_type: string
|
||||
price: number
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const agents = ref<Agent[]>([])
|
||||
@@ -44,12 +37,11 @@ const cardTypes = ref<CardType[]>([])
|
||||
const form = ref({
|
||||
agent_id: '',
|
||||
application_id: '',
|
||||
card_type_id: '',
|
||||
price: 0,
|
||||
remark: '',
|
||||
})
|
||||
|
||||
const selectedCardTypeId = ref<string>('')
|
||||
const permissions = ref<PermissionItem[]>([])
|
||||
|
||||
const selectedAgent = computed(() => {
|
||||
if (form.value.agent_id) {
|
||||
return agents.value.find(a => String(a.id) === form.value.agent_id)
|
||||
@@ -64,8 +56,11 @@ const selectedApplication = computed(() => {
|
||||
return null
|
||||
})
|
||||
|
||||
const availableCardTypes = computed(() => {
|
||||
return cardTypes.value.filter(c => !permissions.value.some(p => p.card_type_id === c.id))
|
||||
const selectedCardType = computed(() => {
|
||||
if (form.value.card_type_id) {
|
||||
return cardTypes.value.find(ct => String(ct.id) === form.value.card_type_id)
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
async function fetchAgents() {
|
||||
@@ -93,37 +88,30 @@ async function fetchApplications() {
|
||||
}
|
||||
|
||||
async function fetchCardTypes(appId: string) {
|
||||
if (!appId) return
|
||||
if (!appId) {
|
||||
cardTypes.value = []
|
||||
form.value.card_type_id = ''
|
||||
form.value.price = 0
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = await api.get<{ card_types: CardType[] }>(`/dev/card-types?application_id=${appId}`)
|
||||
cardTypes.value = data?.card_types || []
|
||||
form.value.card_type_id = ''
|
||||
form.value.price = 0
|
||||
}
|
||||
catch {
|
||||
cardTypes.value = []
|
||||
form.value.card_type_id = ''
|
||||
form.value.price = 0
|
||||
}
|
||||
}
|
||||
|
||||
function addPermission() {
|
||||
if (!selectedCardTypeId.value) {
|
||||
toast.error(t('admin.agentApps.createForm.selectCardType'))
|
||||
return
|
||||
watch(selectedCardType, (ct) => {
|
||||
if (ct) {
|
||||
form.value.price = ct.price
|
||||
}
|
||||
|
||||
const cardType = cardTypes.value.find(ct => String(ct.id) === selectedCardTypeId.value)
|
||||
if (!cardType) return
|
||||
|
||||
permissions.value.push({
|
||||
card_type_id: cardType.id,
|
||||
card_type_name: cardType.name,
|
||||
billing_type: cardType.billing_type,
|
||||
price: cardType.price,
|
||||
})
|
||||
selectedCardTypeId.value = ''
|
||||
}
|
||||
|
||||
function removePermission(index: number) {
|
||||
permissions.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
|
||||
async function handleSave() {
|
||||
if (!form.value.agent_id) {
|
||||
@@ -136,23 +124,21 @@ async function handleSave() {
|
||||
return
|
||||
}
|
||||
|
||||
if (permissions.value.length === 0) {
|
||||
if (!form.value.card_type_id) {
|
||||
toast.error(t('admin.agentApps.createForm.selectCardRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
const cardTypesPayload = permissions.value.map(p => ({
|
||||
card_type_id: p.card_type_id,
|
||||
can_generate: true,
|
||||
price: Number(p.price),
|
||||
}))
|
||||
|
||||
await api.post('/dev/agent-apps', {
|
||||
agent_id: Number(form.value.agent_id),
|
||||
application_id: Number(form.value.application_id),
|
||||
card_types: cardTypesPayload,
|
||||
card_types: [{
|
||||
card_type_id: Number(form.value.card_type_id),
|
||||
can_generate: true,
|
||||
price: Number(form.value.price),
|
||||
}],
|
||||
discount: 0,
|
||||
remark: form.value.remark,
|
||||
})
|
||||
@@ -195,83 +181,73 @@ onMounted(() => {
|
||||
<UiCardDescription>{{ t('admin.agentApps.createForm.authConfigDesc') }}</UiCardDescription>
|
||||
</UiCardHeader>
|
||||
<UiCardContent class="space-y-6">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectAgent') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.agent_id" :disabled="saving || loading">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAgentPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="agent in agents"
|
||||
:key="agent.id"
|
||||
:value="String(agent.id)"
|
||||
>
|
||||
{{ agent.username }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectApp') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.application_id" :disabled="saving || loading" @update:model-value="fetchCardTypes($event)">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAppPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="app in applications"
|
||||
:key="app.id"
|
||||
:value="String(app.id)"
|
||||
>
|
||||
{{ app.name }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectCardType') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<div class="flex gap-3">
|
||||
<div class="flex-1">
|
||||
<UiSelect v-model="selectedCardTypeId" :disabled="!form.application_id || saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectCardTypePlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem v-for="ct in availableCardTypes" :key="ct.id" :value="String(ct.id)">
|
||||
{{ ct.name }}<template v-if="ct.billing_type"> ({{ ct.billing_type }})</template>
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
<UiButton @click="addPermission" :disabled="!form.application_id || saving">
|
||||
<Plus class="mr-1 h-4 w-4" />
|
||||
{{ t('admin.agentApps.createForm.addCardType') }}
|
||||
</UiButton>
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectAgent') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.agent_id" :disabled="saving || loading">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAgentPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="agent in agents"
|
||||
:key="agent.id"
|
||||
:value="String(agent.id)"
|
||||
>
|
||||
{{ agent.username }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div v-if="permissions.length > 0" class="border rounded-lg divide-y max-h-64 overflow-y-auto">
|
||||
<div v-for="(p, index) in permissions" :key="p.card_type_id" class="flex items-center justify-between p-3 gap-4">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-medium truncate">{{ p.card_type_name }}</div>
|
||||
<div v-if="p.billing_type" class="text-sm text-muted-foreground">{{ p.billing_type }}</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-muted-foreground">¥</span>
|
||||
<UiInput class="w-20 text-right" v-model.number="p.price" :placeholder="t('admin.agentApps.createForm.pricePlaceholder')" />
|
||||
</div>
|
||||
<UiButton variant="ghost" size="icon" @click="removePermission(index)" :disabled="saving">
|
||||
<Trash2 class="h-4 w-4 text-destructive" />
|
||||
</UiButton>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectApp') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.application_id" :disabled="saving || loading" @update:model-value="fetchCardTypes($event)">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectAppPlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem
|
||||
v-for="app in applications"
|
||||
:key="app.id"
|
||||
:value="String(app.id)"
|
||||
>
|
||||
{{ app.name }}
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<UiLabel>{{ t('admin.agentApps.createForm.selectCardType') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<UiSelect v-model="form.card_type_id" :disabled="!form.application_id || saving">
|
||||
<UiSelectTrigger>
|
||||
<UiSelectValue :placeholder="t('admin.agentApps.createForm.selectCardTypePlaceholder')" />
|
||||
</UiSelectTrigger>
|
||||
<UiSelectContent>
|
||||
<UiSelectItem v-for="ct in cardTypes" :key="ct.id" :value="String(ct.id)">
|
||||
{{ ct.name }}<template v-if="ct.billing_type"> ({{ ct.billing_type }})</template>
|
||||
</UiSelectItem>
|
||||
</UiSelectContent>
|
||||
</UiSelect>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<UiLabel for="price">{{ t('admin.agentApps.createForm.price') }} <span class="text-destructive">*</span></UiLabel>
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground">¥</span>
|
||||
<UiInput
|
||||
id="price"
|
||||
v-model.number="form.price"
|
||||
type="number"
|
||||
class="pl-7"
|
||||
:placeholder="t('admin.agentApps.createForm.pricePlaceholder')"
|
||||
:disabled="saving"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="text-sm text-muted-foreground text-center py-4">
|
||||
{{ form.application_id ? t('admin.agentApps.createForm.noCardTypes') : t('admin.agentApps.createForm.selectAppFirst') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@@ -307,29 +283,18 @@ onMounted(() => {
|
||||
<span>{{ selectedApplication?.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewCardTypes') }}</span>
|
||||
<span>{{ t('admin.agentApps.createForm.cardCount', { count: permissions.length }) }}</span>
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewCardType') }}</span>
|
||||
<span>{{ selectedCardType?.name || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewPrice') }}</span>
|
||||
<span>¥{{ form.price || 0 }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-muted-foreground">{{ t('admin.agentApps.createForm.previewRemark') }}</span>
|
||||
<span class="truncate max-w-[120px]">{{ form.remark || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="permissions.length > 0" class="border-t pt-4 mt-4">
|
||||
<p class="text-sm text-muted-foreground mb-2">
|
||||
{{ t('admin.agentApps.createForm.cardTypeList') }}
|
||||
</p>
|
||||
<div class="rounded-lg bg-muted/50 p-3 space-y-2 max-h-[150px] overflow-auto">
|
||||
<div v-for="p in permissions" :key="p.card_type_id" class="flex items-center justify-between text-sm">
|
||||
<div class="flex items-center gap-2">
|
||||
<CheckCircle class="size-4 text-green-600" />
|
||||
<span>{{ p.card_type_name }}</span>
|
||||
</div>
|
||||
<span class="text-muted-foreground">¥{{ p.price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UiCardContent>
|
||||
</UiCard>
|
||||
|
||||
@@ -339,7 +304,7 @@ onMounted(() => {
|
||||
<UiButton
|
||||
class="w-full"
|
||||
size="lg"
|
||||
:disabled="saving || !form.agent_id || !form.application_id || permissions.length === 0"
|
||||
:disabled="saving || !form.agent_id || !form.application_id || !form.card_type_id"
|
||||
@click="handleSave"
|
||||
>
|
||||
<Loader2 v-if="saving" class="mr-2 h-4 w-4 animate-spin" />
|
||||
|
||||
@@ -1706,32 +1706,26 @@
|
||||
"remove": "Remove",
|
||||
"createForm": {
|
||||
"title": "Add Authorization",
|
||||
"description": "Add new application authorization for agent",
|
||||
"description": "Add application card type authorization for agent",
|
||||
"editTitle": "Edit Authorization",
|
||||
"editDescription": "Modify agent's application authorization configuration",
|
||||
"editDescription": "Modify agent's application card type authorization",
|
||||
"authConfig": "Authorization Configuration",
|
||||
"authConfigDesc": "Select agent, application and configure card type permissions",
|
||||
"authConfigDesc": "Select agent, application and card type",
|
||||
"selectAgent": "Select Agent",
|
||||
"selectAgentPlaceholder": "Please select an agent",
|
||||
"selectApp": "Select Application",
|
||||
"selectAppPlaceholder": "Please select an application",
|
||||
"cardPermission": "Card Type Permissions",
|
||||
"selectCardType": "Select Card Type",
|
||||
"selectCardTypePlaceholder": "Please select a card type",
|
||||
"addCardType": "Add",
|
||||
"cardTypeList": "Authorized Card Types",
|
||||
"cardTypeName": "Card Type Name",
|
||||
"billingType": "Billing Type",
|
||||
"price": "Price",
|
||||
"pricePlaceholder": "Enter price",
|
||||
"noCardTypes": "Please select card types to add to authorization list",
|
||||
"selectAppFirst": "Please select an application first",
|
||||
"remark": "Remark",
|
||||
"remarkPlaceholder": "Enter remark (optional)",
|
||||
"preview": "Preview",
|
||||
"previewAgent": "Agent",
|
||||
"previewApp": "Application",
|
||||
"previewCardTypes": "Card Types",
|
||||
"previewCardType": "Card Type",
|
||||
"previewPrice": "Price",
|
||||
"previewRemark": "Remark",
|
||||
"confirmAuth": "Confirm Authorization",
|
||||
"updateAuth": "Save Changes",
|
||||
@@ -1742,8 +1736,7 @@
|
||||
"fetchFailed": "Failed to fetch authorization information",
|
||||
"selectAgentRequired": "Please select an agent",
|
||||
"selectAppRequired": "Please select an application",
|
||||
"selectCardRequired": "Please add at least one card type",
|
||||
"cardCount": "{count} items"
|
||||
"selectCardRequired": "Please select a card type"
|
||||
}
|
||||
},
|
||||
"finance": {
|
||||
|
||||
@@ -1695,32 +1695,26 @@
|
||||
"remove": "移除",
|
||||
"createForm": {
|
||||
"title": "添加授权",
|
||||
"description": "为代理添加新的应用授权",
|
||||
"description": "为代理添加应用卡类授权",
|
||||
"editTitle": "编辑授权",
|
||||
"editDescription": "修改代理的应用授权配置",
|
||||
"editDescription": "修改代理的应用卡类授权配置",
|
||||
"authConfig": "授权配置",
|
||||
"authConfigDesc": "选择代理、应用和配置卡类权限",
|
||||
"authConfigDesc": "选择代理、应用和卡类",
|
||||
"selectAgent": "选择代理",
|
||||
"selectAgentPlaceholder": "请选择代理",
|
||||
"selectApp": "选择应用",
|
||||
"selectAppPlaceholder": "请选择应用",
|
||||
"cardPermission": "卡类权限",
|
||||
"selectCardType": "选择卡类",
|
||||
"selectCardTypePlaceholder": "请选择卡类",
|
||||
"addCardType": "添加",
|
||||
"cardTypeList": "已授权卡类",
|
||||
"cardTypeName": "卡类名称",
|
||||
"billingType": "计费类型",
|
||||
"price": "价格",
|
||||
"pricePlaceholder": "输入价格",
|
||||
"noCardTypes": "请选择卡类添加到授权列表",
|
||||
"selectAppFirst": "请先选择应用",
|
||||
"remark": "备注",
|
||||
"remarkPlaceholder": "输入备注信息(可选)",
|
||||
"preview": "预览",
|
||||
"previewAgent": "代理",
|
||||
"previewApp": "应用",
|
||||
"previewCardTypes": "授权卡类",
|
||||
"previewCardType": "卡类",
|
||||
"previewPrice": "价格",
|
||||
"previewRemark": "备注",
|
||||
"confirmAuth": "确认授权",
|
||||
"updateAuth": "保存修改",
|
||||
@@ -1731,8 +1725,7 @@
|
||||
"fetchFailed": "获取授权信息失败",
|
||||
"selectAgentRequired": "请选择代理",
|
||||
"selectAppRequired": "请选择应用",
|
||||
"selectCardRequired": "请至少添加一个卡类",
|
||||
"cardCount": "{count} 个"
|
||||
"selectCardRequired": "请选择卡类"
|
||||
}
|
||||
},
|
||||
"finance": {
|
||||
|
||||
Reference in New Issue
Block a user