Files
tiantian-system/app/pages/admin/developers.vue
赵忠林 f9e1286ab1 refactor(developer-config): 移除开发者配置页面相关代码和文档
- 删除应用配置页面及相关组件,重构路由为 /developer/config/[id].vue
- 移除开发者文档页面及其导航与样式实现
- 清理开发者侧功能完善工作日志文件
- 删除全局.gitignore配置文件,清理无用忽略规则
- 优化应用配置页面的参数读取和路由结构,解决刷新404问题
- 解决数据库配置唯一键冲突,调整保存逻辑避免重复插入
- 移除对后端配置加密字段的 secret 标记,修正加密异常问题
2026-04-09 07:35:34 +08:00

235 lines
11 KiB
Vue

<template>
<div class="developers-page">
<a-card :bordered="false">
<template #title>开发者管理</template>
<a-tabs v-model:activeKey="activeTab">
<!-- 开发者申请 -->
<a-tab-pane key="apply" tab="开发者申请">
<div class="filter-bar">
<a-input-search v-model:value="searchKeyword" placeholder="搜索申请人、企业..." style="width: 280px" allow-clear />
<a-select v-model:value="filterType" placeholder="申请类型" style="width: 150px" allow-clear>
<a-select-option value="api">API 开发者</a-select-option>
<a-select-option value="plugin">插件开发者</a-select-option>
<a-select-option value="template">模板开发者</a-select-option>
</a-select>
<a-button @click="resetFilter">重置</a-button>
</div>
<a-table :columns="applyColumns" :data-source="applyData" row-key="id">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'applicant'">
<div class="user-cell">
<a-avatar style="background: linear-gradient(135deg, #11998e, #38ef7d)" :size="36">{{ record.name[0] }}</a-avatar>
<div>
<p class="name-text">{{ record.name }}</p>
<p class="sub-text">{{ record.email }}</p>
</div>
</div>
</template>
<template v-else-if="column.key === 'type'">
<a-tag :color="typeColor[record.type]">{{ typeMap[record.type] }}</a-tag>
</template>
<template v-else-if="column.key === 'status'">
<a-badge :status="statusBadge[record.status]" :text="statusText[record.status]" />
</template>
<template v-else-if="column.key === 'actions'">
<a-space>
<a-button v-if="record.status === 'pending'" type="primary" size="small" @click="handleApprove(record)">审核</a-button>
<a-button type="link" size="small" @click="handleViewApply(record)">详情</a-button>
</a-space>
</template>
</template>
</a-table>
</a-tab-pane>
<!-- 权限审核 -->
<a-tab-pane key="audit" tab="权限审核">
<div class="filter-bar">
<a-select v-model:value="auditFilterType" placeholder="权限类型" style="width: 150px" allow-clear>
<a-select-option value="api">API 权限</a-select-option>
<a-select-option value="plugin">插件权限</a-select-option>
<a-select-option value="admin">管理权限</a-select-option>
</a-select>
<a-button type="primary" @click="auditModalVisible = true">新增审核</a-button>
</div>
<a-table :columns="auditColumns" :data-source="auditData" row-key="id">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'type'">
<a-tag :color="auditTypeColor[record.type]">{{ auditTypeMap[record.type] }}</a-tag>
</template>
<template v-else-if="column.key === 'level'">
<a-tag :color="levelColor[record.level]">{{ levelMap[record.level] }}</a-tag>
</template>
<template v-else-if="column.key === 'status'">
<a-badge :status="statusBadge[record.status]" :text="statusText[record.status]" />
</template>
<template v-else-if="column.key === 'actions'">
<a-space>
<a-button v-if="record.status === 'pending'" type="primary" size="small" @click="handleAudit(record)">审核</a-button>
<a-button type="link" size="small" @click="handleViewAudit(record)">详情</a-button>
</a-space>
</template>
</template>
</a-table>
</a-tab-pane>
</a-tabs>
</a-card>
<!-- 审核弹窗 -->
<a-modal
v-model:open="auditModalVisible"
:title="editingApply ? '审核开发者申请' : '权限审核'"
width="560px"
:confirm-loading="submitting"
@ok="handleSubmitAudit"
@cancel="auditModalVisible = false"
>
<a-alert v-if="editingApply" :message="`正在审核:${editingApply.name} (${editingApply.email})`" type="info" show-icon class="mb-4" />
<a-form :model="auditForm" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
<a-form-item label="申请人">
<a-input v-model:value="auditForm.name" />
</a-form-item>
<a-form-item label="权限类型">
<a-select v-model:value="auditForm.type">
<a-select-option value="api">API 权限</a-select-option>
<a-select-option value="plugin">插件权限</a-select-option>
<a-select-option value="admin">管理权限</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="权限等级">
<a-select v-model:value="auditForm.level">
<a-select-option value="basic">基础</a-select-option>
<a-select-option value="standard">标准</a-select-option>
<a-select-option value="advance">高级</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="审核结果">
<a-radio-group v-model:value="auditForm.result">
<a-radio value="approved">通过</a-radio>
<a-radio value="rejected">拒绝</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="审核备注">
<a-textarea v-model:value="auditForm.remark" :rows="3" placeholder="选填" />
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue'
definePageMeta({ layout: 'admin' })
const activeTab = ref('apply')
const searchKeyword = ref('')
const filterType = ref<string | undefined>()
const auditFilterType = ref<string | undefined>()
const auditModalVisible = ref(false)
const submitting = ref(false)
const editingApply = ref<any>(null)
const auditForm = reactive({
name: '',
type: 'api',
level: 'basic',
result: 'approved',
remark: '',
})
const typeMap: Record<string, string> = { api: 'API 开发者', plugin: '插件开发者', template: '模板开发者' }
const typeColor: Record<string, string> = { api: 'blue', plugin: 'green', template: 'purple' }
const statusText: Record<string, string> = { pending: '待审核', approved: '已通过', rejected: '已拒绝' }
const statusBadge: Record<string, any> = { pending: 'warning', approved: 'success', rejected: 'error' }
const auditTypeMap: Record<string, string> = { api: 'API 权限', plugin: '插件权限', admin: '管理权限' }
const auditTypeColor: Record<string, string> = { api: 'blue', plugin: 'green', admin: 'purple' }
const levelMap: Record<string, string> = { basic: '基础', standard: '标准', advance: '高级' }
const levelColor: Record<string, string> = { basic: 'default', standard: 'blue', advance: 'red' }
const applyColumns = [
{ title: '申请人', key: 'applicant', width: 220 },
{ title: '企业', dataIndex: 'enterprise', key: 'enterprise', width: 160 },
{ title: '申请类型', key: 'type', width: 110 },
{ title: '申请理由', dataIndex: 'reason', key: 'reason', ellipsis: true },
{ title: '申请时间', dataIndex: 'date', key: 'date', width: 120 },
{ title: '状态', key: 'status', width: 100 },
{ title: '操作', key: 'actions', width: 140, fixed: 'right' },
]
const applyData = ref([
{ id: 1, name: '陈志远', email: 'chenzy@example.com', enterprise: '腾云科技', type: 'api', reason: '需要调用平台 API 实现数据对接功能', date: '2026-04-08', status: 'pending' },
{ id: 2, name: '林晓东', email: 'linxd@example.com', enterprise: '华创数据', type: 'plugin', reason: '希望开发企业级插件产品', date: '2026-04-07', status: 'approved' },
{ id: 3, name: '周文博', email: 'zhouwb@example.com', enterprise: '云智科技', type: 'api', reason: '进行系统集成开发', date: '2026-04-06', status: 'approved' },
{ id: 4, name: '吴浩宇', email: 'wuhao@example.com', enterprise: '数智科技', type: 'template', reason: '发布企业模板到应用市场', date: '2026-04-05', status: 'pending' },
{ id: 5, name: '郑海峰', email: 'zhenghf@example.com', enterprise: '腾云科技', type: 'api', reason: '需要高级 API 权限进行批量操作', date: '2026-04-04', status: 'approved' },
])
const auditColumns = [
{ title: '申请人', dataIndex: 'name', key: 'name', width: 140 },
{ title: '企业', dataIndex: 'enterprise', key: 'enterprise', width: 140 },
{ title: '权限类型', key: 'type', width: 110 },
{ title: '权限等级', key: 'level', width: 100 },
{ title: '申请时间', dataIndex: 'date', key: 'date', width: 120 },
{ title: '审核人', dataIndex: 'auditor', key: 'auditor', width: 100 },
{ title: '状态', key: 'status', width: 100 },
{ title: '操作', key: 'actions', width: 140, fixed: 'right' },
]
const auditData = ref([
{ id: 1, name: '陈志远', enterprise: '腾云科技', type: 'api', level: 'standard', date: '2026-04-08', auditor: '李明', status: 'pending' },
{ id: 2, name: '吴浩宇', enterprise: '数智科技', type: 'plugin', level: 'advance', date: '2026-04-05', auditor: '李明', status: 'pending' },
{ id: 3, name: '林晓东', enterprise: '华创数据', type: 'plugin', level: 'standard', date: '2026-04-07', auditor: '李明', status: 'approved' },
{ id: 4, name: '周文博', enterprise: '云智科技', type: 'api', level: 'basic', date: '2026-04-06', auditor: '李明', status: 'approved' },
])
const resetFilter = () => { searchKeyword.value = ''; filterType.value = undefined }
const handleViewApply = (r: any) => message.info('查看申请:' + r.name)
const handleViewAudit = (r: any) => message.info('查看审核:' + r.name)
const handleApprove = (r: any) => { editingApply.value = r; Object.assign(auditForm, { name: r.name, type: r.type }); auditModalVisible.value = true }
const handleAudit = (r: any) => { editingApply.value = r; Object.assign(auditForm, { name: r.name, type: r.type }); auditModalVisible.value = true }
const handleSubmitAudit = async () => {
submitting.value = true
await new Promise((r) => setTimeout(r, 800))
message.success('审核提交成功')
auditModalVisible.value = false
submitting.value = false
editingApply.value = null
}
</script>
<style scoped>
.filter-bar {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.user-cell {
display: flex;
align-items: center;
gap: 10px;
}
.name-text {
font-weight: 500;
color: #111827;
margin: 0;
}
.sub-text {
font-size: 12px;
color: #9ca3af;
margin: 0;
}
.mb-4 {
margin-bottom: 16px;
}
</style>