853 lines
26 KiB
Vue
853 lines
26 KiB
Vue
<template>
|
||
<SimpleScrollbar>
|
||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||
<ACard
|
||
:title="t('page.portal.title')"
|
||
:bordered="false"
|
||
:body-style="{ flex: 1, overflow: 'hidden' }"
|
||
class="flex-col-stretch sm:flex-1-hidden card-wrapper"
|
||
>
|
||
<template #extra>
|
||
<div class="flex items-center gap-4">
|
||
<!-- 站点选择 -->
|
||
<a-select
|
||
v-model:value="selectedSiteId"
|
||
:loading="siteLoading"
|
||
:placeholder="t('page.portal.selectSite')"
|
||
style="width: 200px"
|
||
@change="handleSiteChange"
|
||
>
|
||
<a-select-option
|
||
v-for="site in siteList"
|
||
:key="site.siteId"
|
||
:value="site.siteId"
|
||
>
|
||
{{ site.name }}
|
||
</a-select-option>
|
||
</a-select>
|
||
|
||
<!-- 表格操作组件 -->
|
||
<TableHeaderOperation
|
||
v-model:columns="columnChecks"
|
||
:loading="tableLoading"
|
||
:show-delete="false"
|
||
@add="handleAdd"
|
||
@refresh="getData"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 表格 -->
|
||
<ATable
|
||
:columns="columns"
|
||
:data-source="tableData"
|
||
:loading="tableLoading"
|
||
:pagination="{
|
||
...mobilePagination,
|
||
total: mobilePagination.total,
|
||
current: searchParams.pageNum,
|
||
pageSize: searchParams.pageSize,
|
||
showTotal: (total: number) => `${t('page.portal.total')} ${total} `
|
||
}"
|
||
@change="(pagination) => {
|
||
searchParams.pageNum = pagination.current;
|
||
searchParams.pageSize = pagination.pageSize;
|
||
getData();
|
||
}"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'operate'">
|
||
<div class="flex items-center justify-center gap-2">
|
||
<a-tooltip :title="t('common.edit')">
|
||
<a-button
|
||
type="link"
|
||
size="small"
|
||
@click="() => handleEdit(record)"
|
||
>
|
||
<template #icon>
|
||
<EditOutlined />
|
||
</template>
|
||
</a-button>
|
||
</a-tooltip>
|
||
|
||
<a-tooltip :title="t('common.delete')">
|
||
<a-button
|
||
type="link"
|
||
size="small"
|
||
class="text-red-500"
|
||
@click="() => handleDelete(record)"
|
||
>
|
||
<template #icon>
|
||
<DeleteOutlined />
|
||
</template>
|
||
</a-button>
|
||
</a-tooltip>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
</ATable>
|
||
</ACard>
|
||
|
||
<!-- 添加门户对话框 -->
|
||
<a-modal
|
||
v-model:visible="addVisible"
|
||
:title="t('page.portal.addPortal')"
|
||
@ok="handleAddConfirm"
|
||
width="600px"
|
||
>
|
||
<a-form
|
||
:model="addForm"
|
||
:rules="addRules"
|
||
:label-col="{ span: 6 }"
|
||
:wrapper-col="{ span: 16 }"
|
||
layout="horizontal"
|
||
ref="formRef"
|
||
>
|
||
<a-form-item name="name" :label="t('page.portal.name')">
|
||
<a-input v-model:value="addForm.name" />
|
||
</a-form-item>
|
||
|
||
<a-form-item name="enable" :label="t('page.portal.enable')">
|
||
<a-switch v-model:checked="addForm.enable" />
|
||
</a-form-item>
|
||
|
||
<a-form-item name="ssidList" :label="t('page.portal.ssid')">
|
||
<a-tree-select
|
||
v-model:value="addForm.ssidList"
|
||
:tree-data="treeData"
|
||
:loading="ssidLoading"
|
||
:placeholder="t('page.portal.selectSsid')"
|
||
multiple
|
||
tree-checkable
|
||
:tree-default-expand-all="true"
|
||
:show-checked-strategy="TreeSelect.SHOW_CHILD"
|
||
style="width: 100%"
|
||
/>
|
||
</a-form-item>
|
||
|
||
<!-- 外部Portal服务器配置 -->
|
||
<a-form-item name="externalPortal" :label="t('page.portal.externalPortal')">
|
||
<div class="flex-col gap-2">
|
||
<!-- URL输入框 -->
|
||
<a-form-item
|
||
:name="['externalPortal', 'serverUrl']"
|
||
:label="t('page.portal.url')"
|
||
>
|
||
<a-input-group compact>
|
||
<a-select
|
||
v-model:value="addForm.externalPortal.serverUrlScheme"
|
||
style="width: 30%"
|
||
>
|
||
<a-select-option value="http">http://</a-select-option>
|
||
<a-select-option value="https">https://</a-select-option>
|
||
</a-select>
|
||
<a-input
|
||
v-model:value="addForm.externalPortal.serverUrl"
|
||
style="width: 70%"
|
||
:placeholder="t('page.portal.enterUrl')"
|
||
/>
|
||
</a-input-group>
|
||
</a-form-item>
|
||
</div>
|
||
</a-form-item>
|
||
|
||
<!-- 身份验证时间配置项,仅在非外部Portal认证时显示 -->
|
||
<a-form-item
|
||
v-if="addForm.authType !== 4"
|
||
name="authTimeout"
|
||
:label="t('page.portal.authTimeout')"
|
||
>
|
||
<a-input-group compact>
|
||
<a-input-number
|
||
v-model:value="addForm.authTimeout.customTimeout"
|
||
style="width: 60%"
|
||
:min="1"
|
||
:max="getMaxTimeout(addForm.authTimeout.customTimeoutUnit)"
|
||
/>
|
||
<a-select
|
||
v-model:value="addForm.authTimeout.customTimeoutUnit"
|
||
style="width: 40%"
|
||
>
|
||
<a-select-option :value="1">{{ t('page.portal.timeUnit.min') }}</a-select-option>
|
||
<a-select-option :value="2">{{ t('page.portal.timeUnit.hour') }}</a-select-option>
|
||
<a-select-option :value="3">{{ t('page.portal.timeUnit.day') }}</a-select-option>
|
||
</a-select>
|
||
</a-input-group>
|
||
</a-form-item>
|
||
|
||
<!-- <a-form-item name="noAuth" :label="t('page.portal.dailyLimit')">-->
|
||
<!-- <a-checkbox v-model:checked="addForm.noAuth.dailyLimitEnable">-->
|
||
<!-- {{ t('page.portal.enableDailyLimit') }}-->
|
||
<!-- </a-checkbox>-->
|
||
<!-- </a-form-item>-->
|
||
|
||
<a-form-item name="httpsRedirectEnable" :label="t('page.portal.httpsRedirect')">
|
||
<a-checkbox v-model:checked="addForm.httpsRedirectEnable">
|
||
{{ t('page.portal.enableHttpsRedirect') }}
|
||
</a-checkbox>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
|
||
<!-- 添加编辑门户对话框 -->
|
||
<a-modal
|
||
v-model:visible="editVisible"
|
||
:title="t('page.portal.editPortal')"
|
||
@ok="handleEditConfirm"
|
||
width="600px"
|
||
>
|
||
<a-form
|
||
:model="editForm"
|
||
:rules="addRules"
|
||
:label-col="{ span: 6 }"
|
||
:wrapper-col="{ span: 16 }"
|
||
layout="horizontal"
|
||
ref="editFormRef"
|
||
>
|
||
<a-form-item name="name" :label="t('page.portal.name')">
|
||
<a-input v-model:value="editForm.name" />
|
||
</a-form-item>
|
||
|
||
<a-form-item name="enable" :label="t('page.portal.enable')">
|
||
<a-switch v-model:checked="editForm.enable" />
|
||
</a-form-item>
|
||
|
||
<a-form-item name="ssidList" :label="t('page.portal.ssid')">
|
||
<a-tree-select
|
||
v-model:value="editForm.ssidList"
|
||
:tree-data="treeData"
|
||
:loading="ssidLoading"
|
||
:placeholder="t('page.portal.selectSsid')"
|
||
multiple
|
||
tree-checkable
|
||
:tree-default-expand-all="true"
|
||
:show-checked-strategy="TreeSelect.SHOW_CHILD"
|
||
style="width: 100%"
|
||
/>
|
||
</a-form-item>
|
||
|
||
<!-- 外部Portal服务器配置 -->
|
||
<a-form-item name="externalPortal" :label="t('page.portal.externalPortal')">
|
||
<div class="flex-col gap-2">
|
||
<!-- URL输入框 -->
|
||
<a-form-item
|
||
:name="['externalPortal', 'serverUrl']"
|
||
:label="t('page.portal.url')"
|
||
>
|
||
<a-input-group compact>
|
||
<a-select
|
||
v-model:value="editForm.externalPortal.serverUrlScheme"
|
||
style="width: 30%"
|
||
>
|
||
<a-select-option value="http">http://</a-select-option>
|
||
<a-select-option value="https">https://</a-select-option>
|
||
</a-select>
|
||
<a-input
|
||
v-model:value="editForm.externalPortal.serverUrl"
|
||
style="width: 70%"
|
||
:placeholder="t('page.portal.enterUrl')"
|
||
/>
|
||
</a-input-group>
|
||
</a-form-item>
|
||
</div>
|
||
</a-form-item>
|
||
|
||
<!-- 身份验证时间配置项,仅在非外部Portal认证时显示 -->
|
||
<a-form-item
|
||
v-if="editForm.authType !== 4"
|
||
name="authTimeout"
|
||
:label="t('page.portal.authTimeout')"
|
||
>
|
||
<a-input-group compact>
|
||
<a-input-number
|
||
v-model:value="editForm.authTimeout.customTimeout"
|
||
style="width: 60%"
|
||
:min="1"
|
||
:max="getMaxTimeout(editForm.authTimeout.customTimeoutUnit)"
|
||
/>
|
||
<a-select
|
||
v-model:value="editForm.authTimeout.customTimeoutUnit"
|
||
style="width: 40%"
|
||
>
|
||
<a-select-option :value="1">{{ t('page.portal.timeUnit.min') }}</a-select-option>
|
||
<a-select-option :value="2">{{ t('page.portal.timeUnit.hour') }}</a-select-option>
|
||
<a-select-option :value="3">{{ t('page.portal.timeUnit.day') }}</a-select-option>
|
||
</a-select>
|
||
</a-input-group>
|
||
</a-form-item>
|
||
|
||
<a-form-item name="httpsRedirectEnable" :label="t('page.portal.httpsRedirect')">
|
||
<a-checkbox v-model:checked="editForm.httpsRedirectEnable">
|
||
{{ t('page.portal.enableHttpsRedirect') }}
|
||
</a-checkbox>
|
||
</a-form-item>
|
||
</a-form>
|
||
</a-modal>
|
||
</div>
|
||
</SimpleScrollbar>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { SimpleScrollbar } from '~/packages/materials/src';
|
||
import { ref, onMounted, watch } from 'vue';
|
||
import { Card as ACard, Table as ATable, message, TreeSelect, Modal } from 'ant-design-vue';
|
||
import { useI18n } from 'vue-i18n';
|
||
import {
|
||
fetchSiteList,
|
||
fetchPortalList,
|
||
fetchSsidList,
|
||
addPortal,
|
||
getPortalConfig,
|
||
updatePortalConfig,
|
||
deletePortal
|
||
} from '@/service/api/auth';
|
||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue';
|
||
import { useTable } from '@/hooks/common/table';
|
||
import type { TreeSelectProps } from 'ant-design-vue';
|
||
|
||
const { t } = useI18n();
|
||
|
||
// 站点相关
|
||
const siteList = ref<Api.Site.SiteInfo[]>([]);
|
||
const selectedSiteId = ref<string>('');
|
||
const siteLoading = ref(false);
|
||
|
||
// 使用 useTable hook
|
||
const {
|
||
columns,
|
||
columnChecks,
|
||
data: tableData,
|
||
loading: tableLoading,
|
||
getData,
|
||
mobilePagination,
|
||
searchParams,
|
||
} = useTable<Api.Portal.Portal>({
|
||
apiFn: async (params) => {
|
||
if (!selectedSiteId.value) {
|
||
return {
|
||
data: {
|
||
rows: [],
|
||
total: 0
|
||
}
|
||
};
|
||
}
|
||
return fetchPortalList(selectedSiteId.value, {
|
||
pageNum: params.pageNum || 1,
|
||
pageSize: params.pageSize || 10
|
||
});
|
||
},
|
||
rowKey: 'id',
|
||
columns: () => [
|
||
{
|
||
title: t('page.portal.name'),
|
||
dataIndex: 'name',
|
||
key: 'name',
|
||
width: 150
|
||
},
|
||
{
|
||
title: 'SSID',
|
||
dataIndex: 'ssidNames',
|
||
key: 'ssidNames',
|
||
width: 200,
|
||
customRender: ({ text }: { text: string[] }) => {
|
||
return text ? text.join(', ') : '-';
|
||
}
|
||
},
|
||
{
|
||
title: t('page.portal.authType'),
|
||
dataIndex: 'authType',
|
||
key: 'authType',
|
||
width: 150,
|
||
customRender: ({ text }: { text: number }) => {
|
||
const authTypeMap: Record<number, string> = {
|
||
0: t('page.portal.auth.none'),
|
||
1: t('page.portal.auth.simplePassword'),
|
||
2: t('page.portal.auth.externalRadius'),
|
||
4: t('page.portal.auth.externalPortal'),
|
||
11: t('page.portal.auth.hotspot'),
|
||
15: t('page.portal.auth.ldap')
|
||
};
|
||
return authTypeMap[text] || text;
|
||
}
|
||
},
|
||
{
|
||
title: t('common.operate'),
|
||
key: 'operate',
|
||
width: 120,
|
||
fixed: 'right',
|
||
align: 'center'
|
||
}
|
||
]
|
||
});
|
||
|
||
// 获取站点列表
|
||
const getSiteList = async () => {
|
||
siteLoading.value = true;
|
||
const { data, error } = await fetchSiteList({
|
||
pageNum: 1,
|
||
pageSize: 100
|
||
});
|
||
|
||
if (!error) {
|
||
siteList.value = data.rows || [];
|
||
// 如果有站点数据,默认选择第一个
|
||
if (siteList.value.length > 0) {
|
||
selectedSiteId.value = siteList.value[0].siteId;
|
||
// 获取第一个站点的数据
|
||
await getData();
|
||
}
|
||
}
|
||
siteLoading.value = false;
|
||
};
|
||
|
||
// 处理站点变更
|
||
const handleSiteChange = async (value: string) => {
|
||
selectedSiteId.value = value;
|
||
await getData();
|
||
};
|
||
|
||
// 组件挂载时获取站点列表
|
||
onMounted(() => {
|
||
getSiteList();
|
||
});
|
||
|
||
// 添加表单相关
|
||
const addVisible = ref(false);
|
||
const formRef = ref();
|
||
const ssidList = ref<Api.Portal.SsidInfo[]>([]);
|
||
const ssidLoading = ref(false);
|
||
const treeData = ref<TreeSelectProps['treeData']>([]);
|
||
|
||
// URL 格式校验正则
|
||
const URL_PATTERN = new RegExp(
|
||
'^(([-a-zA-Z0-9@:%._+~#=]{2,256}\\.[a-z]{2,63})|(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.)){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))' +
|
||
'((:([1-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]))?)' +
|
||
'(/[-a-zA-Z0-9@:%_+.~#?&//=]*)?$'
|
||
);
|
||
|
||
const addForm = ref({
|
||
name: '',
|
||
enable: true, // 默认启用
|
||
ssidList: [],
|
||
authType: 4, // 固定为外部 Portal 认证
|
||
authTimeout: {
|
||
customTimeout: 8, // 默认超时时间
|
||
customTimeoutUnit: 2 // 默认单位为小时
|
||
},
|
||
noAuth: {
|
||
dailyLimitEnable: false // 默认不启用每日限额
|
||
},
|
||
httpsRedirectEnable: false, // 默认不启用 HTTPS 重定向
|
||
landingPage: 1, // 默认登录页面
|
||
pageType: 2, // 默认页面类型
|
||
importedPortalPage: {
|
||
id: 'test' // 默认导入的门户页面 ID
|
||
},
|
||
externalPortal: {
|
||
hostType: 2, // 默认外部 Portal 服务器类型
|
||
serverUrl: '', // 默认服务器 URL
|
||
serverUrlScheme: 'http' // 默认协议
|
||
},
|
||
portalCustomize: { // 新增的默认参数
|
||
defaultLanguage: 1,
|
||
backgroundPictureId: '',
|
||
logoPictureId: '',
|
||
logoDisplay: true,
|
||
inputBoxColor: '',
|
||
inputBoxOpacity: 0,
|
||
inputTextColor: '',
|
||
inputTextOpacity: 0,
|
||
buttonColor: '',
|
||
buttonOpacity: 0,
|
||
buttonTextColor: '',
|
||
buttonTextOpacity: 0,
|
||
buttonText: '',
|
||
// formAuthButtonText: '',
|
||
welcomeEnable: true,
|
||
// welcomeInformation: '',
|
||
// welcomeTextColor: '',
|
||
welcomeTextOpacity: 0,
|
||
welcomeTextFontSize: 0,
|
||
termsOfServiceEnable: true,
|
||
termsOfServiceText: '',
|
||
termsOfServiceFontSize: 0,
|
||
termsOfServiceUrlTexts: [
|
||
{
|
||
content: '',
|
||
text: ''
|
||
}
|
||
],
|
||
copyrightEnable: false,
|
||
copyright: '',
|
||
// copyrightTextColor: '',
|
||
// copyrightTextOpacity: 0,
|
||
copyrightTextFontSize: 12,
|
||
redirectionCountDownEnable: true,
|
||
advertisement: {
|
||
enable: false,
|
||
pictureIds: [],
|
||
// totalDuration: 0,
|
||
// pictureInterval: 0,
|
||
// skipEnable: true
|
||
}
|
||
}
|
||
});
|
||
|
||
const addRules = {
|
||
name: [
|
||
{ required: true, message: t('page.portal.nameRequired'), trigger: 'blur' }
|
||
],
|
||
ssidList: [
|
||
{
|
||
validator: (_rule: any, value: Record<string, string>) => {
|
||
if (Object.keys(value).length === 0) {
|
||
return Promise.reject(t('page.portal.ssidRequired'));
|
||
}
|
||
return Promise.resolve();
|
||
},
|
||
trigger: 'change'
|
||
}
|
||
],
|
||
externalPortal: [
|
||
{
|
||
validator: (_rule: any, value: Api.Portal.ExternalPortal) => {
|
||
if (addForm.value.authType === 4) {
|
||
if (!value.serverUrl) {
|
||
return Promise.reject(t('page.portal.urlRequired'));
|
||
}
|
||
// URL 格式校验
|
||
if (!URL_PATTERN.test(value.serverUrl)) {
|
||
return Promise.reject(t('page.portal.invalidUrl'));
|
||
}
|
||
}
|
||
return Promise.resolve();
|
||
}
|
||
}
|
||
]
|
||
};
|
||
|
||
// 获取 SSID 列表
|
||
const getSsidList = async () => {
|
||
if (!selectedSiteId.value) return;
|
||
|
||
ssidLoading.value = true;
|
||
const { data, error } = await fetchSsidList(selectedSiteId.value);
|
||
|
||
if (!error) {
|
||
// 转换数据为树形结构
|
||
treeData.value = data.map((group: Api.Portal.WlanGroup) => ({
|
||
title: group.wlanName,
|
||
value: group.wlanId, // 这个值不会被选中,只是为了符合树结构
|
||
key: group.wlanId,
|
||
selectable: false, // 禁止选择父节点
|
||
children: group.ssidList.map((ssid: Api.Portal.SsidInfo) => ({
|
||
title: ssid.ssidName,
|
||
value: ssid.ssidId,
|
||
key: ssid.ssidId,
|
||
isLeaf: true
|
||
}))
|
||
}));
|
||
} else {
|
||
message.error(t('common.error'));
|
||
}
|
||
|
||
ssidLoading.value = false;
|
||
};
|
||
|
||
// 根据时间单位获取最大超时时间
|
||
const getMaxTimeout = (unit: number) => {
|
||
switch (unit) {
|
||
case 1: return 1000000; // 分钟
|
||
case 2: return 10000; // 小时
|
||
case 3: return 1000; // 天
|
||
default: return 1000000;
|
||
}
|
||
};
|
||
|
||
// 处理添加
|
||
const handleAdd = async () => {
|
||
addVisible.value = true;
|
||
await getSsidList();
|
||
};
|
||
|
||
// 修改添加确认处理函数
|
||
const handleAddConfirm = async () => {
|
||
await formRef.value?.validate();
|
||
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
|
||
// 创建一个新对象来存储要提交的数据
|
||
const submitData = {
|
||
...addForm.value,
|
||
// 这里可以直接使用默认值
|
||
authType: 4, // 固定为外部 Portal 认证
|
||
authTimeout: {
|
||
customTimeout: 8,
|
||
customTimeoutUnit: 2
|
||
},
|
||
noAuth: {
|
||
dailyLimitEnable: false
|
||
},
|
||
httpsRedirectEnable: false,
|
||
landingPage: 1,
|
||
pageType: 2,
|
||
importedPortalPage: {
|
||
id: 'test'
|
||
},
|
||
externalPortal: {
|
||
hostType: 2,
|
||
serverUrl: addForm.value.externalPortal.serverUrl, // 确保从 addForm 中获取 serverUrl
|
||
serverUrlScheme: addForm.value.externalPortal.serverUrlScheme
|
||
},
|
||
portalCustomize: { // 新增的默认参数
|
||
defaultLanguage: 1,
|
||
backgroundPictureId: '',
|
||
logoPictureId: '',
|
||
logoDisplay: true,
|
||
inputBoxColor: "#ffffff",
|
||
inputBoxOpacity: 100,
|
||
inputTextColor: "#2B2B2B",
|
||
inputTextOpacity: 100,
|
||
buttonColor: "#00778C",
|
||
buttonOpacity: 100,
|
||
buttonTextColor: "#FFFFFF",
|
||
buttonTextOpacity: 100,
|
||
buttonText: "Log In",
|
||
// formAuthButtonText: '',
|
||
welcomeEnable: false,
|
||
// welcomeInformation: '',
|
||
// welcomeTextColor: '',
|
||
welcomeTextOpacity: 100,
|
||
welcomeTextFontSize: 12,
|
||
termsOfServiceEnable: false,
|
||
termsOfServiceText: "I agree to Terms of Service",
|
||
termsOfServiceFontSize: 12,
|
||
termsOfServiceUrlTexts: [
|
||
{
|
||
content: "By accepting this agreement and accessing the wireless network, you acknowledge that you are of legal age, you have read and understood, and agree to be bound by this agreement.",
|
||
text: "Terms of Service"
|
||
}
|
||
],
|
||
copyrightEnable: false,
|
||
copyright: '',
|
||
// copyrightTextColor: '',
|
||
// copyrightTextOpacity: 0,
|
||
copyrightTextFontSize: 12,
|
||
redirectionCountDownEnable: true,
|
||
advertisement: {
|
||
enable: false,
|
||
pictureIds: [],
|
||
// totalDuration: 0,
|
||
// pictureInterval: 0,
|
||
// skipEnable: true
|
||
}
|
||
}
|
||
};
|
||
|
||
const { error } = await addPortal(selectedSiteId.value, submitData);
|
||
|
||
hide();
|
||
if (!error) {
|
||
message.success(t('page.portal.addSuccess'));
|
||
addVisible.value = false;
|
||
getData(); // 刷新列表
|
||
}
|
||
};
|
||
|
||
// 添加响应式变量
|
||
const currentPortalId = ref<string>('');
|
||
const editVisible = ref(false);
|
||
const editFormRef = ref();
|
||
const editForm = ref({
|
||
name: '',
|
||
enable: true, // 默认启用
|
||
ssidList: [],
|
||
authType: 4, // 固定为外部 Portal 认证
|
||
authTimeout: {
|
||
customTimeout: 8, // 默认超时时间
|
||
customTimeoutUnit: 2 // 默认单位为小时
|
||
},
|
||
httpsRedirectEnable: false, // 默认不启用 HTTPS 重定向
|
||
landingPage: 1, // 默认登录页面
|
||
pageType: 2, // 默认页面类型
|
||
importedPortalPage: {
|
||
id: 'test' // 默认导入的门户页面 ID
|
||
},
|
||
externalPortal: {
|
||
hostType: 2, // 默认外部 Portal 服务器类型
|
||
serverUrl: '', // 默认服务器 URL
|
||
serverUrlScheme: 'http' // 默认协议
|
||
},
|
||
portalCustomize: { // 新增的默认参数
|
||
defaultLanguage: 1,
|
||
backgroundPictureId: '',
|
||
logoPictureId: '',
|
||
logoDisplay: true,
|
||
inputBoxColor: "#ffffff",
|
||
inputBoxOpacity: 100,
|
||
inputTextColor: "#2B2B2B",
|
||
inputTextOpacity: 100,
|
||
buttonColor: "#00778C",
|
||
buttonOpacity: 100,
|
||
buttonTextColor: "#FFFFFF",
|
||
buttonTextOpacity: 100,
|
||
buttonText: "Log In",
|
||
// formAuthButtonText: '',
|
||
welcomeEnable: false,
|
||
// welcomeInformation: '',
|
||
// welcomeTextColor: '',
|
||
welcomeTextOpacity: 100,
|
||
welcomeTextFontSize: 12,
|
||
termsOfServiceEnable: false,
|
||
termsOfServiceText: "I agree to Terms of Service",
|
||
termsOfServiceFontSize: 12,
|
||
termsOfServiceUrlTexts: [
|
||
{
|
||
content: "By accepting this agreement and accessing the wireless network, you acknowledge that you are of legal age, you have read and understood, and agree to be bound by this agreement.",
|
||
text: "Terms of Service"
|
||
}
|
||
],
|
||
copyrightEnable: false,
|
||
copyright: '',
|
||
// copyrightTextColor: '',
|
||
// copyrightTextOpacity: 0,
|
||
copyrightTextFontSize: 12,
|
||
redirectionCountDownEnable: true,
|
||
advertisement: {
|
||
enable: false,
|
||
pictureIds: [],
|
||
// totalDuration: 0,
|
||
// pictureInterval: 0,
|
||
// skipEnable: true
|
||
}
|
||
}
|
||
});
|
||
|
||
// 处理编辑按钮点击
|
||
const handleEdit = async (record: Api.Portal.Portal) => {
|
||
currentPortalId.value = record.id;
|
||
editVisible.value = true;
|
||
|
||
// 获取 SSID 列表
|
||
await getSsidList();
|
||
|
||
// 获取当前门户的配置
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
const { data, error } = await getPortalConfig(selectedSiteId.value, currentPortalId.value);
|
||
hide();
|
||
|
||
if (!error && data) {
|
||
// 移除 noAuth 字段后再赋值
|
||
const { noAuth, ...configWithoutNoAuth } = data;
|
||
editForm.value = configWithoutNoAuth;
|
||
}
|
||
};
|
||
|
||
// 修改编辑确认处理函数
|
||
const handleEditConfirm = async () => {
|
||
await editFormRef.value?.validate();
|
||
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
|
||
const submitData = {
|
||
name: editForm.value.name,
|
||
enable: editForm.value.enable,
|
||
ssidList: editForm.value.ssidList,
|
||
authType: 4, // 固定为外部 Portal 认证
|
||
httpsRedirectEnable: editForm.value.httpsRedirectEnable,
|
||
landingPage: 1,
|
||
pageType: 2,
|
||
importedPortalPage: {
|
||
id: 'test'
|
||
},
|
||
authTimeout: {
|
||
customTimeout: 8,
|
||
customTimeoutUnit: 2
|
||
},
|
||
externalPortal: {
|
||
hostType: 2,
|
||
serverUrl: editForm.value.externalPortal.serverUrl,
|
||
serverUrlScheme: editForm.value.externalPortal.serverUrlScheme
|
||
},
|
||
portalCustomize: { // 新增的默认参数
|
||
defaultLanguage: 1,
|
||
backgroundPictureId: '',
|
||
logoPictureId: '',
|
||
logoDisplay: true,
|
||
inputBoxColor: "#ffffff",
|
||
inputBoxOpacity: 100,
|
||
inputTextColor: "#2B2B2B",
|
||
inputTextOpacity: 100,
|
||
buttonColor: "#00778C",
|
||
buttonOpacity: 100,
|
||
buttonTextColor: "#FFFFFF",
|
||
buttonTextOpacity: 100,
|
||
buttonText: "Log In",
|
||
// formAuthButtonText: '',
|
||
welcomeEnable: false,
|
||
// welcomeInformation: '',
|
||
// welcomeTextColor: '',
|
||
welcomeTextOpacity: 100,
|
||
welcomeTextFontSize: 12,
|
||
termsOfServiceEnable: false,
|
||
termsOfServiceText: "I agree to Terms of Service",
|
||
termsOfServiceFontSize: 12,
|
||
termsOfServiceUrlTexts: [
|
||
{
|
||
content: "By accepting this agreement and accessing the wireless network, you acknowledge that you are of legal age, you have read and understood, and agree to be bound by this agreement.",
|
||
text: "Terms of Service"
|
||
}
|
||
],
|
||
copyrightEnable: false,
|
||
copyright: '',
|
||
// copyrightTextColor: '',
|
||
// copyrightTextOpacity: 0,
|
||
copyrightTextFontSize: 12,
|
||
redirectionCountDownEnable: true,
|
||
advertisement: {
|
||
enable: false,
|
||
pictureIds: [],
|
||
// totalDuration: 0,
|
||
// pictureInterval: 0,
|
||
// skipEnable: true
|
||
}
|
||
}
|
||
};
|
||
|
||
const { error } = await updatePortalConfig(selectedSiteId.value, currentPortalId.value, submitData);
|
||
|
||
hide();
|
||
if (!error) {
|
||
message.success(t('page.portal.updateSuccess'));
|
||
editVisible.value = false;
|
||
getData(); // 刷新列表
|
||
}
|
||
};
|
||
|
||
// 添加删除门户的 API 函数
|
||
const handleDelete = (record: Api.Portal.Portal) => {
|
||
Modal.confirm({
|
||
title: t('page.portal.confirmDelete'),
|
||
content: t('page.portal.deleteConfirmContent', { name: record.name }),
|
||
okText: t('common.confirm'),
|
||
cancelText: t('common.cancel'),
|
||
onOk: async () => {
|
||
const hide = message.loading(t('common.loading'), 0);
|
||
const { error } = await deletePortal(selectedSiteId.value, record.id);
|
||
hide();
|
||
|
||
if (!error) {
|
||
message.success(t('page.portal.deleteSuccess'));
|
||
getData(); // 刷新列表
|
||
}
|
||
}
|
||
});
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.card-wrapper {
|
||
margin-top: 16px;
|
||
}
|
||
</style>
|