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