refactor: 移除佣金比例字段,将developer统一为admin

This commit is contained in:
2026-05-01 08:08:11 +08:00
parent c5d1dc4b04
commit 4ed00f29e2
235 changed files with 9082 additions and 8952 deletions
@@ -259,7 +259,7 @@ onMounted(() => {
title="邮箱设置"
description="配置应用的邮箱验证相关设置"
:breadcrumbs="[
{ title: '应用管理', href: '/developer/applications' },
{ title: '应用管理', href: '/admin/applications' },
{ title: '邮箱设置' },
]"
sticky
@@ -140,7 +140,7 @@ onMounted(() => {
title="安全设置"
description="配置应用的安全相关设置,包括加密方式和登录策略"
:breadcrumbs="[
{ title: '应用管理', href: '/developer/applications' },
{ title: '应用管理', href: '/admin/applications' },
{ title: '安全设置' },
]"
sticky
@@ -251,7 +251,7 @@ function toggleWeekday(index: number) {
title="基本设置"
description="修改应用的基本信息,包括名称、描述和图标等"
:breadcrumbs="[
{ title: '应用管理', href: '/developer/applications' },
{ title: '应用管理', href: '/admin/applications' },
{ title: '基本设置' },
]"
sticky
@@ -193,7 +193,7 @@ export function getColumns(actions: {
h(DropdownMenuSeparator),
h(DropdownMenuItem, { class: 'text-destructive', onClick: () => actions.onDelete(app) }, () => [
h(Trash2, { class: 'mr-2 h-4 w-4' }),
t('developer.applications.delete'),
t('admin.applications.delete'),
]),
],
),
@@ -5,13 +5,13 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import type { DataTableProps } from '@/components/data-table/types'
import type { App } from '@/pages/developer/applications/data/schema'
import type { App } from '@/pages/admin/applications/data/schema'
import DataTable from '@/components/data-table/data-table.vue'
import { SelectColumn } from '@/components/data-table/table-columns'
import { generateVueTable } from '@/components/data-table/use-generate-vue-table'
import DataTableViewOptions from '@/components/data-table/view-options.vue'
import { getColumns } from '@/pages/developer/applications/components/columns'
import { getColumns } from '@/pages/admin/applications/components/columns'
const props = defineProps<Omit<DataTableProps<App>, 'columns'> & {
searchFilter?: string
@@ -47,14 +47,14 @@ const table = generateVueTable<App>({
}, columns.value)
const columnLabels: Record<string, string> = {
select: 'developer.applications.select',
name: 'developer.applications.columns.name',
app_key: 'developer.applications.columns.appKey',
billing_type: 'developer.applications.columns.billingType',
login_policy: 'developer.applications.columns.loginPolicy',
enable_trial: 'developer.applications.columns.trial',
status: 'developer.applications.columns.status',
created_at: 'developer.applications.columns.createdAt',
select: 'admin.applications.select',
name: 'admin.applications.columns.name',
app_key: 'admin.applications.columns.appKey',
billing_type: 'admin.applications.columns.billingType',
login_policy: 'admin.applications.columns.loginPolicy',
enable_trial: 'admin.applications.columns.trial',
status: 'admin.applications.columns.status',
created_at: 'admin.applications.columns.createdAt',
}
defineExpose({
@@ -69,7 +69,7 @@ defineExpose({
<div class="flex flex-wrap items-center gap-2">
<UiInput
:model-value="searchFilter"
:placeholder="t('developer.applications.searchPlaceholder')"
:placeholder="t('admin.applications.searchPlaceholder')"
class="h-9 w-40 lg:w-[250px]"
@update:model-value="emit('update:searchFilter', String($event))"
/>
@@ -74,7 +74,7 @@ function toggleWeekday(index: number) {
async function handleCreate() {
if (!formData.value.name.trim()) {
toast.error(t('developer.applications.appNameRequired'))
toast.error(t('admin.applications.appNameRequired'))
return
}
@@ -120,16 +120,16 @@ async function handleCreate() {
const data = await response.json()
if (data.code === 200) {
toast.success(t('developer.applications.createSuccess'))
router.push('/developer/applications')
toast.success(t('admin.applications.createSuccess'))
router.push('/admin/applications')
}
else {
toast.error(data.message || t('developer.applications.createFailed'))
toast.error(data.message || t('admin.applications.createFailed'))
}
}
catch (error) {
console.error('创建应用失败:', error)
toast.error(t('developer.applications.createFailed'))
toast.error(t('admin.applications.createFailed'))
}
finally {
loading.value = false
@@ -139,31 +139,31 @@ async function handleCreate() {
<template>
<BasicPage
:title="t('developer.applications.createApp')"
:description="t('developer.applications.createAppDesc')"
:title="t('admin.applications.createApp')"
:description="t('admin.applications.createAppDesc')"
:breadcrumbs="[
{ title: t('developer.applications.title'), href: '/developer/applications' },
{ title: t('developer.applications.createApp') },
{ title: t('admin.applications.title'), href: '/admin/applications' },
{ title: t('admin.applications.createApp') },
]"
sticky
>
<div class="space-y-6">
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.basicInfo') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.basicInfoDesc') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.basicInfo') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.basicInfoDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
<UiLabel for="name">
{{ t('developer.applications.appName') }} *
{{ t('admin.applications.appName') }} *
</UiLabel>
<UiInput id="name" v-model="formData.name" :placeholder="t('developer.applications.appNamePlaceholder')" />
<UiInput id="name" v-model="formData.name" :placeholder="t('admin.applications.appNamePlaceholder')" />
</div>
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.appIcon') }}</UiLabel>
<UiLabel>{{ t('admin.applications.appIcon') }}</UiLabel>
<div class="flex items-center gap-4">
<div v-if="formData.iconPreview" class="relative group">
<img
@@ -185,7 +185,7 @@ async function handleCreate() {
class="flex items-center justify-center h-12 px-4 border-2 border-dashed rounded-lg cursor-pointer hover:bg-accent/50 transition-colors"
>
<Icon icon="lucide:upload" class="w-4 h-4 mr-2 text-muted-foreground" />
<span class="text-sm text-muted-foreground">{{ formData.iconPreview ? t('developer.applications.change') : t('developer.applications.upload') }}</span>
<span class="text-sm text-muted-foreground">{{ formData.iconPreview ? t('admin.applications.change') : t('admin.applications.upload') }}</span>
<input
id="appIcon"
type="file"
@@ -200,17 +200,17 @@ async function handleCreate() {
<div class="space-y-2">
<UiLabel for="description">
{{ t('developer.applications.appDescription') }}
{{ t('admin.applications.appDescription') }}
</UiLabel>
<UiTextarea id="description" v-model="formData.description" :placeholder="t('developer.applications.appDescriptionPlaceholder')" rows="3" />
<UiTextarea id="description" v-model="formData.description" :placeholder="t('admin.applications.appDescriptionPlaceholder')" rows="3" />
</div>
</UiCardContent>
</UiCard>
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.operationMode') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.operationModeDesc') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.operationMode') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.operationModeDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent>
<UiRadioGroup v-model="formData.billing_type" class="grid grid-cols-1 md:grid-cols-2 gap-4">
@@ -222,10 +222,10 @@ async function handleCreate() {
<UiRadioGroupItem value="free" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.freeMode') }}
{{ t('admin.applications.freeMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.freeModeDesc') }}
{{ t('admin.applications.freeModeDesc') }}
</p>
</div>
</div>
@@ -238,10 +238,10 @@ async function handleCreate() {
<UiRadioGroupItem value="subscription" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.subscriptionMode') }}
{{ t('admin.applications.subscriptionMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.subscriptionModeDesc') }}
{{ t('admin.applications.subscriptionModeDesc') }}
</p>
</div>
</div>
@@ -254,10 +254,10 @@ async function handleCreate() {
<UiRadioGroupItem value="time" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.timeMode') }}
{{ t('admin.applications.timeMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.timeModeDesc') }}
{{ t('admin.applications.timeModeDesc') }}
</p>
</div>
</div>
@@ -270,10 +270,10 @@ async function handleCreate() {
<UiRadioGroupItem value="count" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.countMode') }}
{{ t('admin.applications.countMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.countModeDesc') }}
{{ t('admin.applications.countModeDesc') }}
</p>
</div>
</div>
@@ -282,30 +282,30 @@ async function handleCreate() {
<div v-if="formData.billing_type !== 'free'" class="mt-4 pt-4 border-t space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.deductionCycle') }}</UiLabel>
<UiLabel>{{ t('admin.applications.deductionCycle') }}</UiLabel>
<UiSelect v-model="formData.deduction_cycle">
<UiSelectTrigger>
<UiSelectValue :placeholder="t('developer.applications.selectDeductionCycle')" />
<UiSelectValue :placeholder="t('admin.applications.selectDeductionCycle')" />
</UiSelectTrigger>
<UiSelectContent>
<UiSelectItem value="per_use">
{{ t('developer.applications.perUse') }}
{{ t('admin.applications.perUse') }}
</UiSelectItem>
<UiSelectItem value="per_minute">
{{ t('developer.applications.perMinute') }}
{{ t('admin.applications.perMinute') }}
</UiSelectItem>
<UiSelectItem value="per_hour">
{{ t('developer.applications.perHour') }}
{{ t('admin.applications.perHour') }}
</UiSelectItem>
<UiSelectItem value="per_day">
{{ t('developer.applications.perDay') }}
{{ t('admin.applications.perDay') }}
</UiSelectItem>
</UiSelectContent>
</UiSelect>
</div>
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.deductionAmount') }}</UiLabel>
<UiLabel>{{ t('admin.applications.deductionAmount') }}</UiLabel>
<UiNumberField v-model="formData.deduction_amount" :min="0" :step="0.01">
<UiNumberFieldContent>
<UiNumberFieldDecrement />
@@ -321,8 +321,8 @@ async function handleCreate() {
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.loginPolicy') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.loginPolicyDesc') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.loginPolicy') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.loginPolicyDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent>
<UiRadioGroup v-model="formData.login_policy" class="grid grid-cols-1 md:grid-cols-3 gap-4">
@@ -334,10 +334,10 @@ async function handleCreate() {
<UiRadioGroupItem value="loose" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.looseMode') }}
{{ t('admin.applications.looseMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.looseModeDesc') }}
{{ t('admin.applications.looseModeDesc') }}
</p>
</div>
</div>
@@ -350,10 +350,10 @@ async function handleCreate() {
<UiRadioGroupItem value="strict" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.strictMode') }}
{{ t('admin.applications.strictMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.strictModeDesc') }}
{{ t('admin.applications.strictModeDesc') }}
</p>
</div>
</div>
@@ -366,10 +366,10 @@ async function handleCreate() {
<UiRadioGroupItem value="hybrid" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.hybridMode') }}
{{ t('admin.applications.hybridMode') }}
</p>
<p class="text-sm text-muted-foreground">
{{ t('developer.applications.hybridModeDesc') }}
{{ t('admin.applications.hybridModeDesc') }}
</p>
</div>
</div>
@@ -379,14 +379,14 @@ async function handleCreate() {
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.trialSettings') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.trialSettings') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.trialSettings') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.trialSettings') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="flex items-center justify-between">
<div>
<p class="font-medium">
{{ t('developer.applications.enableTrial') }}
{{ t('admin.applications.enableTrial') }}
</p>
<p class="text-sm text-muted-foreground">
新用户注册后自动获得试用权益
@@ -397,7 +397,7 @@ async function handleCreate() {
<div v-if="formData.enable_trial" class="space-y-4 pt-4 border-t">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.trialBalance') }}</UiLabel>
<UiLabel>{{ t('admin.applications.trialBalance') }}</UiLabel>
<UiNumberField
v-model="formData.trial_balance"
:min="0"
@@ -420,14 +420,14 @@ async function handleCreate() {
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.freePeriodSettings') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.freePeriodSettings') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.freePeriodSettings') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.freePeriodSettings') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="flex items-center justify-between">
<div>
<p class="font-medium">
{{ t('developer.applications.enableFreePeriod') }}
{{ t('admin.applications.enableFreePeriod') }}
</p>
<p class="text-sm text-muted-foreground">
在设定的时间段内所有用户可免费使用
@@ -438,7 +438,7 @@ async function handleCreate() {
<div v-if="formData.enable_free_period" class="space-y-4 pt-4 border-t">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.periodType') }}</UiLabel>
<UiLabel>{{ t('admin.applications.periodType') }}</UiLabel>
<UiRadioGroup v-model="formData.free_period_type" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div
class="flex items-start gap-3 p-4 rounded-lg border cursor-pointer transition-colors"
@@ -448,7 +448,7 @@ async function handleCreate() {
<UiRadioGroupItem value="range" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.dateRange') }}
{{ t('admin.applications.dateRange') }}
</p>
<p class="text-sm text-muted-foreground">
指定开始和结束日期时间
@@ -464,7 +464,7 @@ async function handleCreate() {
<UiRadioGroupItem value="weekly" class="mt-0.5" />
<div>
<p class="font-medium">
{{ t('developer.applications.weekly') }}
{{ t('admin.applications.weekly') }}
</p>
<p class="text-sm text-muted-foreground">
每周固定日期和时间段
@@ -476,18 +476,18 @@ async function handleCreate() {
<div v-if="formData.free_period_type === 'range'" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.startTime') }}</UiLabel>
<UiDatePickerDateTimePicker v-model="formData.free_period_start" :placeholder="t('developer.applications.startTime')" />
<UiLabel>{{ t('admin.applications.startTime') }}</UiLabel>
<UiDatePickerDateTimePicker v-model="formData.free_period_start" :placeholder="t('admin.applications.startTime')" />
</div>
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.endTime') }}</UiLabel>
<UiDatePickerDateTimePicker v-model="formData.free_period_end" :placeholder="t('developer.applications.endTime')" />
<UiLabel>{{ t('admin.applications.endTime') }}</UiLabel>
<UiDatePickerDateTimePicker v-model="formData.free_period_end" :placeholder="t('admin.applications.endTime')" />
</div>
</div>
<div v-if="formData.free_period_type === 'weekly'" class="space-y-4">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.weekdays') }}</UiLabel>
<UiLabel>{{ t('admin.applications.weekdays') }}</UiLabel>
<div class="flex flex-wrap gap-2">
<template v-for="(day, index) in ['周一', '周二', '周三', '周四', '周五', '周六', '周日']" :key="index">
<UiButton
@@ -507,15 +507,15 @@ async function handleCreate() {
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.startTime') }}</UiLabel>
<UiDatePickerTimePicker v-model="formData.free_period_start_time" :placeholder="t('developer.applications.startTime')" />
<UiLabel>{{ t('admin.applications.startTime') }}</UiLabel>
<UiDatePickerTimePicker v-model="formData.free_period_start_time" :placeholder="t('admin.applications.startTime')" />
<p class="text-xs text-muted-foreground">
每天免费开始时间
</p>
</div>
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.endTime') }}</UiLabel>
<UiDatePickerTimePicker v-model="formData.free_period_end_time" :placeholder="t('developer.applications.endTime')" />
<UiLabel>{{ t('admin.applications.endTime') }}</UiLabel>
<UiDatePickerTimePicker v-model="formData.free_period_end_time" :placeholder="t('admin.applications.endTime')" />
<p class="text-xs text-muted-foreground">
每天免费结束时间
</p>
@@ -528,29 +528,29 @@ async function handleCreate() {
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.securitySettings') }}</UiCardTitle>
<UiCardDescription>{{ t('developer.applications.securitySettingsDesc') }}</UiCardDescription>
<UiCardTitle>{{ t('admin.applications.securitySettings') }}</UiCardTitle>
<UiCardDescription>{{ t('admin.applications.securitySettingsDesc') }}</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.encryptionType') }}</UiLabel>
<UiLabel>{{ t('admin.applications.encryptionType') }}</UiLabel>
<UiSelect v-model="formData.encrypt_type">
<UiSelectTrigger>
<UiSelectValue :placeholder="t('developer.applications.encryptionType')" />
<UiSelectValue :placeholder="t('admin.applications.encryptionType')" />
</UiSelectTrigger>
<UiSelectContent>
<UiSelectItem value="none">
{{ t('developer.applications.noEncryption') }}
{{ t('admin.applications.noEncryption') }}
</UiSelectItem>
<UiSelectItem value="aes">
{{ t('developer.applications.aesEncryption') }}
{{ t('admin.applications.aesEncryption') }}
</UiSelectItem>
<UiSelectItem value="rsa">
{{ t('developer.applications.rsaEncryption') }}
{{ t('admin.applications.rsaEncryption') }}
</UiSelectItem>
<UiSelectItem value="rc4">
{{ t('developer.applications.rc4Encryption') }}
{{ t('admin.applications.rc4Encryption') }}
</UiSelectItem>
</UiSelectContent>
</UiSelect>
@@ -563,7 +563,7 @@ async function handleCreate() {
</div>
<div class="space-y-2">
<UiLabel>{{ t('developer.applications.secretKey') }}</UiLabel>
<UiLabel>{{ t('admin.applications.secretKey') }}</UiLabel>
<div class="relative">
<UiInput
v-model="formData.secret_key"
@@ -591,14 +591,14 @@ async function handleCreate() {
<UiCard>
<UiCardHeader>
<UiCardTitle>{{ t('developer.applications.deviceBind') }}</UiCardTitle>
<UiCardTitle>{{ t('admin.applications.deviceBind') }}</UiCardTitle>
<UiCardDescription>控制用户登录时是否需要绑定设备</UiCardDescription>
</UiCardHeader>
<UiCardContent class="space-y-4">
<div class="flex items-center justify-between">
<div>
<p class="font-medium">
{{ t('developer.applications.deviceBind') }}
{{ t('admin.applications.deviceBind') }}
</p>
<p class="text-sm text-muted-foreground">
启用后用户登录时需要绑定设备可限制同时登录的设备数量
@@ -611,7 +611,7 @@ async function handleCreate() {
</div>
<div v-if="formData.bind_type === 'device'" class="space-y-2 pt-4 border-t">
<UiLabel>{{ t('developer.applications.maxDevices') }}</UiLabel>
<UiLabel>{{ t('admin.applications.maxDevices') }}</UiLabel>
<UiNumberField v-model="formData.max_devices" :min="1" :max="10">
<UiNumberFieldContent>
<UiNumberFieldDecrement />
@@ -627,7 +627,7 @@ async function handleCreate() {
<div class="flex items-center justify-between pt-4 border-t">
<div>
<p class="font-medium">
{{ t('developer.applications.allowMultiOpen') }}
{{ t('admin.applications.allowMultiOpen') }}
</p>
<p class="text-sm text-muted-foreground">
允许同一账号在同一设备上同时运行多个实例
@@ -639,12 +639,12 @@ async function handleCreate() {
</UiCard>
<div class="flex justify-end gap-3">
<UiButton variant="outline" @click="router.push('/developer/applications')">
<UiButton variant="outline" @click="router.push('/admin/applications')">
取消
</UiButton>
<UiButton :disabled="loading" @click="handleCreate">
<Icon v-if="loading" icon="lucide:loader-2" class="mr-2 h-4 w-4 animate-spin" />
{{ t('developer.applications.createApp') }}
{{ t('admin.applications.createApp') }}
</UiButton>
</div>
</div>