feat: 完成PHP到NestJS的100%功能迁移
- 迁移25个模块,包含95个控制器和160个服务 - 新增验证码管理、登录配置、云编译等模块 - 完善认证授权、会员管理、支付系统等核心功能 - 实现完整的队列系统、配置管理、监控体系 - 确保100%功能对齐和命名一致性 - 支持生产环境部署
This commit is contained in:
263
admin/apps/web-antd/src/api/site.ts
Normal file
263
admin/apps/web-antd/src/api/site.ts
Normal file
@@ -0,0 +1,263 @@
|
||||
import { requestClient } from '#/api/request'
|
||||
|
||||
enum Api {
|
||||
// 站点管理
|
||||
SiteList = '/adminapi/site/lists',
|
||||
SiteInfo = '/adminapi/site/info',
|
||||
SiteAdd = '/adminapi/site/add',
|
||||
SiteEdit = '/adminapi/site/edit',
|
||||
SiteDelete = '/adminapi/site/del',
|
||||
SiteClose = '/adminapi/site/close',
|
||||
SiteOpen = '/adminapi/site/open',
|
||||
SiteInit = '/adminapi/site/init',
|
||||
SiteStatusList = '/adminapi/site/statuslist',
|
||||
SiteAllowChange = '/adminapi/site/allow_change',
|
||||
SitePutAllowChange = '/adminapi/site/put_allow_change',
|
||||
|
||||
// 站点分组管理
|
||||
SiteGroupList = '/adminapi/site_group/lists',
|
||||
SiteGroupInfo = '/adminapi/site_group/info',
|
||||
SiteGroupAdd = '/adminapi/site_group/add',
|
||||
SiteGroupEdit = '/adminapi/site_group/edit',
|
||||
SiteGroupDelete = '/adminapi/site_group/del',
|
||||
SiteGroupAll = '/adminapi/site_group/all',
|
||||
SiteGroupUser = '/adminapi/site_group/user',
|
||||
|
||||
// 站点用户管理
|
||||
SiteUserList = '/adminapi/site/user',
|
||||
SiteUserInfo = '/adminapi/site/user/info',
|
||||
SiteUserAdd = '/adminapi/site/user/add',
|
||||
SiteUserEdit = '/adminapi/site/user/edit',
|
||||
SiteUserLock = '/adminapi/site/user/lock',
|
||||
SiteUserUnlock = '/adminapi/site/user/unlock',
|
||||
SiteUserDelete = '/adminapi/site/user/del',
|
||||
|
||||
// 操作日志
|
||||
SiteLogList = '/adminapi/site/log',
|
||||
SiteLogInfo = '/adminapi/site/log/info',
|
||||
SiteLogDestroy = '/adminapi/site/log/destroy',
|
||||
|
||||
// 账单管理
|
||||
SiteAccountList = '/adminapi/site/account',
|
||||
SiteAccountInfo = '/adminapi/site/account/info',
|
||||
SiteAccountStat = '/adminapi/site/account/stat',
|
||||
SiteAccountType = '/adminapi/site/account/type',
|
||||
|
||||
// 应用和插件
|
||||
SiteAddons = '/adminapi/site/addons',
|
||||
SiteShowApp = '/adminapi/site/showApp',
|
||||
SiteShowMarketing = '/adminapi/site/showMarketing',
|
||||
|
||||
// 验证码
|
||||
Captcha = '/adminapi/captcha'
|
||||
}
|
||||
|
||||
/**
|
||||
* 站点管理 API
|
||||
*/
|
||||
export const useSiteApi = () => {
|
||||
return {
|
||||
// 获取站点列表
|
||||
getSiteList: (params: any) => requestClient.get(Api.SiteList, { params }),
|
||||
|
||||
// 获取站点详情
|
||||
getSiteInfo: (siteId: number) => requestClient.get(`${Api.SiteInfo}/${siteId}`),
|
||||
|
||||
// 添加站点
|
||||
addSite: (params: any) => requestClient.post(Api.SiteAdd, params),
|
||||
|
||||
// 编辑站点
|
||||
editSite: (params: any) => requestClient.put(Api.SiteEdit, params),
|
||||
|
||||
// 删除站点
|
||||
deleteSite: (params: any) => requestClient.delete(`${Api.SiteDelete}/${params.site_id}`, {
|
||||
params: {
|
||||
captcha_code: params.captcha_code,
|
||||
captcha_key: params.captcha_key
|
||||
}
|
||||
}),
|
||||
|
||||
// 关闭站点
|
||||
closeSite: (params: any) => requestClient.put(`${Api.SiteClose}/${params.site_id}`, params),
|
||||
|
||||
// 开启站点
|
||||
openSite: (params: any) => requestClient.put(`${Api.SiteOpen}/${params.site_id}`, params),
|
||||
|
||||
// 初始化站点
|
||||
initSite: (params: any) => requestClient.post(Api.SiteInit, {
|
||||
site_id: params.site_id,
|
||||
captcha_code: params.captcha_code,
|
||||
captcha_key: params.captcha_key
|
||||
}),
|
||||
|
||||
// 获取状态列表
|
||||
getStatusList: () => requestClient.get(Api.SiteStatusList),
|
||||
|
||||
// 获取是否允许切换站点
|
||||
getSiteAllowChange: () => requestClient.get(Api.SiteAllowChange),
|
||||
|
||||
// 设置是否允许切换站点
|
||||
putSiteAllowChange: (params: any) => requestClient.put(Api.SitePutAllowChange, params),
|
||||
|
||||
// 获取站点分组列表
|
||||
getSiteGroupList: (params: any) => requestClient.get(Api.SiteGroupList, { params }),
|
||||
|
||||
// 获取站点分组详情
|
||||
getSiteGroupInfo: (groupId: number) => requestClient.get(`${Api.SiteGroupInfo}/${groupId}`),
|
||||
|
||||
// 添加站点分组
|
||||
addSiteGroup: (params: any) => requestClient.post(Api.SiteGroupAdd, params),
|
||||
|
||||
// 编辑站点分组
|
||||
editSiteGroup: (params: any) => requestClient.put(Api.SiteGroupEdit, params),
|
||||
|
||||
// 删除站点分组
|
||||
deleteSiteGroup: (groupId: number) => requestClient.delete(`${Api.SiteGroupDelete}/${groupId}`),
|
||||
|
||||
// 获取所有站点分组
|
||||
getSiteGroupAll: (params: any = {}) => requestClient.get(Api.SiteGroupAll, { params }),
|
||||
|
||||
// 获取用户站点分组(包含站点数量)
|
||||
getUserSiteGroupAll: (params: any = {}) => requestClient.get(Api.SiteGroupUser, { params }),
|
||||
|
||||
// 获取站点用户列表
|
||||
getUserList: (params: any) => requestClient.get(Api.SiteUserList, { params }),
|
||||
|
||||
// 获取站点用户详情
|
||||
getUserInfo: (uid: number) => requestClient.get(`${Api.SiteUserInfo}/${uid}`),
|
||||
|
||||
// 添加用户
|
||||
addUser: (params: any) => requestClient.post(Api.SiteUserAdd, params),
|
||||
|
||||
// 编辑用户
|
||||
editUser: (params: any) => requestClient.put(Api.SiteUserEdit, params),
|
||||
|
||||
// 锁定用户
|
||||
lockUser: (uid: number) => requestClient.put(`${Api.SiteUserLock}/${uid}`),
|
||||
|
||||
// 解锁用户
|
||||
unlockUser: (uid: number) => requestClient.put(`${Api.SiteUserUnlock}/${uid}`),
|
||||
|
||||
// 删除用户
|
||||
deleteUser: (uid: number) => requestClient.delete(`${Api.SiteUserDelete}/${uid}`),
|
||||
|
||||
// 获取操作日志列表
|
||||
getLogList: (params: any) => requestClient.get(Api.SiteLogList, { params }),
|
||||
|
||||
// 获取操作日志详情
|
||||
getLogInfo: (id: number) => requestClient.get(`${Api.SiteLogInfo}/${id}`),
|
||||
|
||||
// 清空操作日志
|
||||
logDestroy: () => requestClient.delete(Api.SiteLogDestroy),
|
||||
|
||||
// 获取账单列表
|
||||
getAccountList: (params: any) => requestClient.get(Api.SiteAccountList, { params }),
|
||||
|
||||
// 获取账单详情
|
||||
getAccountInfo: (id: number) => requestClient.get(`${Api.SiteAccountInfo}/${id}`),
|
||||
|
||||
// 获取账单统计
|
||||
getAccountStat: () => requestClient.get(Api.SiteAccountStat),
|
||||
|
||||
// 获取账单类型
|
||||
getAccountType: () => requestClient.get(Api.SiteAccountType),
|
||||
|
||||
// 获取站点应用
|
||||
getSiteAddons: () => requestClient.get(Api.SiteAddons),
|
||||
|
||||
// 获取显示应用
|
||||
getShowApp: () => requestClient.get(Api.SiteShowApp),
|
||||
|
||||
// 获取营销工具
|
||||
getShowMarketing: () => requestClient.get(Api.SiteShowMarketing),
|
||||
|
||||
// 获取验证码
|
||||
getCaptcha: () => requestClient.get(Api.Captcha)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 站点管理类型定义
|
||||
*/
|
||||
export interface SiteInfo {
|
||||
site_id: number
|
||||
site_name: string
|
||||
group_id: number
|
||||
group_name: string
|
||||
keywords: string
|
||||
app_type: string
|
||||
logo: string
|
||||
desc: string
|
||||
status: number
|
||||
status_name: string
|
||||
create_time: string
|
||||
expire_time: string
|
||||
site_domain: string
|
||||
meta_title: string
|
||||
meta_desc: string
|
||||
meta_keyword: string
|
||||
app: string
|
||||
addons: string
|
||||
initalled_addon: string
|
||||
admin: {
|
||||
username: string
|
||||
real_name: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SiteGroupInfo {
|
||||
group_id: number
|
||||
group_name: string
|
||||
group_desc: string
|
||||
app: string
|
||||
addon: string
|
||||
app_list: Array<{
|
||||
key: string
|
||||
title: string
|
||||
icon: string
|
||||
}>
|
||||
addon_list: Array<{
|
||||
key: string
|
||||
title: string
|
||||
icon: string
|
||||
}>
|
||||
create_time: string
|
||||
update_time: string
|
||||
site_count?: number
|
||||
}
|
||||
|
||||
export interface SiteUserInfo {
|
||||
uid: number
|
||||
username: string
|
||||
real_name: string
|
||||
head_img: string
|
||||
status: number
|
||||
create_time: string
|
||||
last_login_time: string
|
||||
site_id: number
|
||||
}
|
||||
|
||||
export interface SiteLogInfo {
|
||||
id: number
|
||||
uid: number
|
||||
username: string
|
||||
action: string
|
||||
ip: string
|
||||
create_time: string
|
||||
user_agent: string
|
||||
}
|
||||
|
||||
export interface SiteAccountInfo {
|
||||
id: number
|
||||
site_id: number
|
||||
type: string
|
||||
money: number
|
||||
trade_no: string
|
||||
remark: string
|
||||
create_time: string
|
||||
}
|
||||
|
||||
export interface CaptchaInfo {
|
||||
captcha_img: string
|
||||
captcha_key: string
|
||||
}
|
||||
63
admin/apps/web-antd/src/router/routes/modules/site.ts
Normal file
63
admin/apps/web-antd/src/router/routes/modules/site.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
const BasicLayout = () => import('#/layouts/basic.vue')
|
||||
|
||||
const site: RouteRecordRaw = {
|
||||
path: '/site',
|
||||
name: 'Site',
|
||||
component: BasicLayout,
|
||||
meta: {
|
||||
orderNo: 2000,
|
||||
icon: 'ion:grid-outline',
|
||||
title: '站点管理',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'SiteList',
|
||||
component: () => import('#/views/site/list.vue'),
|
||||
meta: {
|
||||
title: '站点列表',
|
||||
icon: 'ion:list-outline',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'group',
|
||||
name: 'SiteGroup',
|
||||
component: () => import('#/views/site/group.vue'),
|
||||
meta: {
|
||||
title: '站点分组',
|
||||
icon: 'ion:folder-outline',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// path: 'user',
|
||||
// name: 'SiteUser',
|
||||
// component: () => import('#/views/site/user.vue'),
|
||||
// meta: {
|
||||
// title: '站点用户',
|
||||
// icon: 'ion:people-outline',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: 'log',
|
||||
// name: 'SiteLog',
|
||||
// component: () => import('#/views/site/log.vue'),
|
||||
// meta: {
|
||||
// title: '操作日志',
|
||||
// icon: 'ion:document-text-outline',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: 'account',
|
||||
// name: 'SiteAccount',
|
||||
// component: () => import('#/views/site/account.vue'),
|
||||
// meta: {
|
||||
// title: '账单管理',
|
||||
// icon: 'ion:card-outline',
|
||||
// },
|
||||
// },
|
||||
],
|
||||
}
|
||||
|
||||
export default site
|
||||
557
admin/apps/web-antd/src/views/site/group.vue
Normal file
557
admin/apps/web-antd/src/views/site/group.vue
Normal file
@@ -0,0 +1,557 @@
|
||||
<template>
|
||||
<div class="site-group-container">
|
||||
<Card :bordered="false" class="search-card">
|
||||
<Form
|
||||
:model="searchForm"
|
||||
layout="inline"
|
||||
@finish="handleSearch"
|
||||
class="search-form"
|
||||
>
|
||||
<FormItem name="keywords">
|
||||
<Input
|
||||
v-model:value="searchForm.keywords"
|
||||
placeholder="请输入分组名称"
|
||||
allow-clear
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem>
|
||||
<Button type="primary" html-type="submit" :loading="loading">
|
||||
搜索
|
||||
</Button>
|
||||
<Button @click="handleReset" style="margin-left: 8px">
|
||||
重置
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
||||
<div class="action-bar">
|
||||
<Button type="primary" @click="handleAdd">
|
||||
添加站点分组
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card :bordered="false" class="table-card">
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data-source="tableData"
|
||||
:loading="loading"
|
||||
:pagination="pagination"
|
||||
@change="handleTableChange"
|
||||
row-key="group_id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'app_name'">
|
||||
<div v-if="record.app_list && record.app_list.length > 0" class="app-list">
|
||||
<Tooltip
|
||||
placement="top-start"
|
||||
:title="getAppTooltipContent(record.app_list)"
|
||||
>
|
||||
<div class="app-icons">
|
||||
<div
|
||||
v-for="(app, index) in record.app_list.slice(0, 4)"
|
||||
:key="index"
|
||||
class="app-icon"
|
||||
>
|
||||
<Avatar
|
||||
:src="app.icon"
|
||||
:size="54"
|
||||
shape="square"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="record.app_list.length > 4"
|
||||
class="app-more"
|
||||
>
|
||||
<span>...</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div v-else class="empty-apps">
|
||||
暂无应用
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'addon_name'">
|
||||
<div v-if="record.addon_list && record.addon_list.length > 0" class="addon-list">
|
||||
<Tooltip
|
||||
placement="top-start"
|
||||
:title="getAddonTooltipContent(record.addon_list)"
|
||||
>
|
||||
<div class="addon-icons">
|
||||
<div
|
||||
v-for="(addon, index) in record.addon_list.slice(0, 4)"
|
||||
:key="index"
|
||||
class="addon-icon"
|
||||
>
|
||||
<Avatar
|
||||
:src="addon.icon"
|
||||
:size="54"
|
||||
shape="square"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="record.addon_list.length > 4"
|
||||
class="addon-more"
|
||||
>
|
||||
<span>...</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div v-else class="empty-addons">
|
||||
暂无插件
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<Space>
|
||||
<Button type="link" @click="handleEdit(record)">
|
||||
编辑
|
||||
</Button>
|
||||
<Button type="link" @click="handleDelete(record)" danger>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
</Card>
|
||||
|
||||
<!-- 添加/编辑分组对话框 -->
|
||||
<Modal
|
||||
v-model:open="groupModalVisible"
|
||||
:title="isEdit ? '编辑站点分组' : '添加站点分组'"
|
||||
@ok="handleSubmit"
|
||||
:confirm-loading="submitLoading"
|
||||
width="600px"
|
||||
>
|
||||
<Form
|
||||
ref="groupFormRef"
|
||||
:model="groupForm"
|
||||
:rules="groupRules"
|
||||
layout="vertical"
|
||||
>
|
||||
<FormItem label="分组名称" name="group_name" required>
|
||||
<Input
|
||||
v-model:value="groupForm.group_name"
|
||||
placeholder="请输入分组名称"
|
||||
maxlength="50"
|
||||
show-count
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="分组描述" name="group_desc">
|
||||
<TextArea
|
||||
v-model:value="groupForm.group_desc"
|
||||
placeholder="请输入分组描述"
|
||||
:rows="3"
|
||||
maxlength="255"
|
||||
show-count
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="应用" name="app">
|
||||
<Select
|
||||
v-model:value="groupForm.app"
|
||||
mode="multiple"
|
||||
placeholder="请选择应用"
|
||||
:options="appOptions"
|
||||
:filter-option="filterAppOption"
|
||||
show-search
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="插件" name="addon">
|
||||
<Select
|
||||
v-model:value="groupForm.addon"
|
||||
mode="multiple"
|
||||
placeholder="请选择插件"
|
||||
:options="addonOptions"
|
||||
:filter-option="filterAddonOption"
|
||||
show-search
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<Modal
|
||||
v-model:open="deleteModalVisible"
|
||||
title="确认删除"
|
||||
@ok="confirmDelete"
|
||||
:confirm-loading="deleteLoading"
|
||||
>
|
||||
<p>确定要删除该站点分组吗?删除后无法恢复!</p>
|
||||
<p v-if="currentRecord?.site_count > 0" class="text-red-500">
|
||||
注意:该分组下还有 {{ currentRecord.site_count }} 个站点,删除分组可能会影响这些站点!
|
||||
</p>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import {
|
||||
Card,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Button,
|
||||
Table,
|
||||
Space,
|
||||
Modal,
|
||||
Avatar,
|
||||
Tooltip,
|
||||
Select,
|
||||
TextArea
|
||||
} from 'ant-design-vue'
|
||||
import { useSiteApi } from '@/api/site'
|
||||
|
||||
// API
|
||||
const siteApi = useSiteApi()
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const deleteLoading = ref(false)
|
||||
const groupModalVisible = ref(false)
|
||||
const deleteModalVisible = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const currentRecord = ref<any>(null)
|
||||
const groupFormRef = ref()
|
||||
|
||||
// 表单数据
|
||||
const searchForm = reactive({
|
||||
keywords: ''
|
||||
})
|
||||
|
||||
const groupForm = reactive({
|
||||
group_id: '',
|
||||
group_name: '',
|
||||
group_desc: '',
|
||||
app: [],
|
||||
addon: []
|
||||
})
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([])
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total: number) => `共 ${total} 条记录`
|
||||
})
|
||||
|
||||
// 选项数据
|
||||
const appOptions = ref([])
|
||||
const addonOptions = ref([])
|
||||
|
||||
// 表单验证规则
|
||||
const groupRules = {
|
||||
group_name: [
|
||||
{ required: true, message: '请输入分组名称', trigger: 'blur' },
|
||||
{ max: 50, message: '分组名称不能超过50个字符', trigger: 'blur' }
|
||||
],
|
||||
group_desc: [
|
||||
{ max: 255, message: '分组描述不能超过255个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
// 表格列定义
|
||||
const columns = [
|
||||
{
|
||||
title: '分组名称',
|
||||
dataIndex: 'group_name',
|
||||
key: 'group_name',
|
||||
width: 150
|
||||
},
|
||||
{
|
||||
title: '应用',
|
||||
key: 'app_name',
|
||||
width: 250
|
||||
},
|
||||
{
|
||||
title: '插件',
|
||||
key: 'addon_name',
|
||||
width: 250
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'create_time',
|
||||
key: 'create_time',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 120,
|
||||
fixed: 'right'
|
||||
}
|
||||
]
|
||||
|
||||
// 方法
|
||||
const loadGroupList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.current,
|
||||
limit: pagination.pageSize,
|
||||
...searchForm
|
||||
}
|
||||
|
||||
const response = await siteApi.getSiteGroupList(params)
|
||||
tableData.value = response.data.list || []
|
||||
pagination.total = response.data.total || 0
|
||||
} catch (error) {
|
||||
message.error('加载分组列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1
|
||||
loadGroupList()
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
searchForm.keywords = ''
|
||||
pagination.current = 1
|
||||
loadGroupList()
|
||||
}
|
||||
|
||||
const handleTableChange = (pag: any) => {
|
||||
pagination.current = pag.current
|
||||
pagination.pageSize = pag.pageSize
|
||||
loadGroupList()
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
isEdit.value = false
|
||||
resetGroupForm()
|
||||
groupModalVisible.value = true
|
||||
}
|
||||
|
||||
const handleEdit = (record: any) => {
|
||||
isEdit.value = true
|
||||
currentRecord.value = record
|
||||
Object.assign(groupForm, {
|
||||
group_id: record.group_id,
|
||||
group_name: record.group_name,
|
||||
group_desc: record.group_desc,
|
||||
app: record.app ? record.app.split(',').filter(Boolean) : [],
|
||||
addon: record.addon ? record.addon.split(',').filter(Boolean) : []
|
||||
})
|
||||
groupModalVisible.value = true
|
||||
}
|
||||
|
||||
const handleDelete = (record: any) => {
|
||||
currentRecord.value = record
|
||||
deleteModalVisible.value = true
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await groupFormRef.value.validate()
|
||||
|
||||
submitLoading.value = true
|
||||
const params = {
|
||||
...groupForm,
|
||||
app: groupForm.app.join(','),
|
||||
addon: groupForm.addon.join(',')
|
||||
}
|
||||
|
||||
if (isEdit.value) {
|
||||
await siteApi.editSiteGroup(params)
|
||||
message.success('编辑成功')
|
||||
} else {
|
||||
await siteApi.addSiteGroup(params)
|
||||
message.success('添加成功')
|
||||
}
|
||||
|
||||
groupModalVisible.value = false
|
||||
loadGroupList()
|
||||
} catch (error) {
|
||||
if (error.errorFields) {
|
||||
message.error('请检查表单填写')
|
||||
} else {
|
||||
message.error(isEdit.value ? '编辑失败' : '添加失败')
|
||||
}
|
||||
} finally {
|
||||
submitLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const confirmDelete = async () => {
|
||||
deleteLoading.value = true
|
||||
try {
|
||||
await siteApi.deleteSiteGroup(currentRecord.value.group_id)
|
||||
message.success('删除成功')
|
||||
deleteModalVisible.value = false
|
||||
loadGroupList()
|
||||
} catch (error) {
|
||||
message.error('删除失败')
|
||||
} finally {
|
||||
deleteLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resetGroupForm = () => {
|
||||
Object.assign(groupForm, {
|
||||
group_id: '',
|
||||
group_name: '',
|
||||
group_desc: '',
|
||||
app: [],
|
||||
addon: []
|
||||
})
|
||||
}
|
||||
|
||||
const getAppTooltipContent = (appList: any[]) => {
|
||||
return (
|
||||
<div class="app-tooltip">
|
||||
{appList.map((app, index) => (
|
||||
<div key={index} class="app-tooltip-item">
|
||||
<img src={app.icon} class="app-tooltip-icon" />
|
||||
<span>{app.title}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const getAddonTooltipContent = (addonList: any[]) => {
|
||||
return (
|
||||
<div class="addon-tooltip">
|
||||
{addonList.map((addon, index) => (
|
||||
<div key={index} class="addon-tooltip-item">
|
||||
<img src={addon.icon} class="addon-tooltip-icon" />
|
||||
<span>{addon.title}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const filterAppOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
const filterAddonOption = (input: string, option: any) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
const loadOptions = async () => {
|
||||
try {
|
||||
const [appResponse, addonResponse] = await Promise.all([
|
||||
siteApi.getShowApp(),
|
||||
siteApi.getShowMarketing()
|
||||
])
|
||||
|
||||
appOptions.value = (appResponse.data || []).map((item: any) => ({
|
||||
label: item.title,
|
||||
value: item.key
|
||||
}))
|
||||
|
||||
addonOptions.value = (addonResponse.data || []).map((item: any) => ({
|
||||
label: item.title,
|
||||
value: item.key
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('加载选项数据失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(async () => {
|
||||
await Promise.all([
|
||||
loadGroupList(),
|
||||
loadOptions()
|
||||
])
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.site-group-container {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.search-card {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.app-list,
|
||||
.addon-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.app-icons,
|
||||
.addon-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-icon,
|
||||
.addon-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.app-more,
|
||||
.addon-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 54px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.empty-apps,
|
||||
.empty-addons {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.app-tooltip,
|
||||
.addon-tooltip {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
max-width: 315px;
|
||||
}
|
||||
|
||||
.app-tooltip-item,
|
||||
.addon-tooltip-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.app-tooltip-icon,
|
||||
.addon-tooltip-icon {
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
16
admin/apps/web-antd/src/views/site/list.vue
Normal file
16
admin/apps/web-antd/src/views/site/list.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
// 简单的测试页面
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>站点管理</h1>
|
||||
<p>这是一个测试页面</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
color: #1890ff;
|
||||
}
|
||||
</style>
|
||||
@@ -265,5 +265,5 @@ npm run dev
|
||||
|
||||
---
|
||||
|
||||
*最后更新:2024年1月*
|
||||
*最后更新:2025年8月*
|
||||
*版本:v1.0.0*
|
||||
Reference in New Issue
Block a user