🎨合并编译打包
This commit is contained in:
442
web-src/src/views/server/clients.vue
Normal file
442
web-src/src/views/server/clients.vue
Normal file
@@ -0,0 +1,442 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
deleteClient,
|
||||
downloadClient,
|
||||
getClients,
|
||||
saveClient
|
||||
} from "@/api/clients";
|
||||
import { h, reactive, ref } from "vue";
|
||||
import { addDialog } from "@/components/ReDialog/index";
|
||||
import qrCodeForms from "./component/qrCode.vue";
|
||||
import editClientForms from "./component/detail.vue";
|
||||
import { type PlusColumn, PlusSearch } from "plus-pro-components";
|
||||
import "plus-pro-components/es/components/search/style/css";
|
||||
import { storageLocal } from "@pureadmin/utils";
|
||||
import { ArrowDown } from "@element-plus/icons-vue";
|
||||
import { ElMessageBox } from "element-plus";
|
||||
|
||||
defineOptions({
|
||||
// name 作为一种规范最好必须写上并且和路由的name保持一致
|
||||
name: "Clients"
|
||||
});
|
||||
|
||||
const editClientFormRef = ref();
|
||||
|
||||
const clientSearchForm = ref({
|
||||
name: "",
|
||||
email: "",
|
||||
ip: "",
|
||||
createUser: "",
|
||||
enabled: undefined,
|
||||
current: 1,
|
||||
size: 9
|
||||
});
|
||||
|
||||
const clientSearchProps = {
|
||||
gutter: 0
|
||||
};
|
||||
|
||||
const clientSearchFormColumns: PlusColumn[] = [
|
||||
{
|
||||
label: "名称",
|
||||
prop: "name",
|
||||
valueType: "copy",
|
||||
fieldProps: {
|
||||
placeholder: "请输入"
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "邮箱",
|
||||
prop: "email",
|
||||
valueType: "copy",
|
||||
fieldProps: {
|
||||
placeholder: "请输入"
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "IP",
|
||||
prop: "ip",
|
||||
valueType: "copy",
|
||||
fieldProps: {
|
||||
placeholder: "请输入"
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "创建人",
|
||||
prop: "createUser",
|
||||
valueType: "copy",
|
||||
fieldProps: {
|
||||
placeholder: "请输入"
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "状态",
|
||||
prop: "enabled",
|
||||
valueType: "select",
|
||||
options: [
|
||||
{
|
||||
label: "启用",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "禁用",
|
||||
value: 0
|
||||
}
|
||||
],
|
||||
fieldProps: {
|
||||
placeholder: "请选择"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const clientsList = reactive({
|
||||
data: [],
|
||||
total: 0
|
||||
});
|
||||
|
||||
const getClientsApi = (data?: object) => {
|
||||
getClients(data).then(clients => {
|
||||
if (clients.code === 200) {
|
||||
clientsList.data = clients.data.records;
|
||||
clientsList.total = clients.data.total;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 下载客户端配置文件
|
||||
const downloadClientConfig = (id: string, clientName: string) => {
|
||||
downloadClient(id).then(response => {
|
||||
if (response) {
|
||||
const blob = new Blob([response], {
|
||||
type: "text/plain"
|
||||
});
|
||||
const link = document.createElement("a"); // 创建a标签
|
||||
link.download = clientName + ".conf"; // a标签添加属性
|
||||
link.style.display = "none";
|
||||
link.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(link);
|
||||
link.click(); // 执行下载
|
||||
URL.revokeObjectURL(link.href); // 释放url
|
||||
document.body.removeChild(link); // 释放标签
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 打开二维码模态框
|
||||
const openQrCodeDialog = (clientName: string, id: string) => {
|
||||
addDialog({
|
||||
width: "20%",
|
||||
title: clientName,
|
||||
contentRenderer: () => h(qrCodeForms),
|
||||
props: {
|
||||
formInline: {
|
||||
id: id
|
||||
}
|
||||
},
|
||||
hideFooter: true
|
||||
});
|
||||
};
|
||||
|
||||
// 打开新增客户端弹窗
|
||||
const openAddClientDialog = () => {
|
||||
const serverInfo = storageLocal().getItem("server-info");
|
||||
addDialog({
|
||||
width: "40%",
|
||||
title: "新增",
|
||||
contentRenderer: () => h(editClientForms, { ref: editClientFormRef }),
|
||||
props: {
|
||||
formInline: {
|
||||
id: "",
|
||||
serverId: serverInfo.id,
|
||||
name: "",
|
||||
email: "",
|
||||
subnetRange: "",
|
||||
ipAllocation: "",
|
||||
allowedIPS: "",
|
||||
extraAllowedIPS: "",
|
||||
endpoint: "",
|
||||
useServerDNS: 0,
|
||||
enableAfterCreation: 0,
|
||||
keys: null,
|
||||
enabled: 1
|
||||
}
|
||||
},
|
||||
beforeSure: (done, { options }) => {
|
||||
const FormRef = editClientFormRef.value.getDetailFormRef();
|
||||
FormRef.validate(valid => {
|
||||
if (!valid) return;
|
||||
saveClient(options.props.formInline).then(res => {
|
||||
if (res.code === 200) {
|
||||
done();
|
||||
getClientsApi(clientSearchForm.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 打开编辑客户端信息模态框
|
||||
const openEditClientDialog = (client?: any) => {
|
||||
const serverInfo = storageLocal().getItem("server-info");
|
||||
addDialog({
|
||||
width: "40%",
|
||||
title: client.name,
|
||||
contentRenderer: () => h(editClientForms, { ref: editClientFormRef }),
|
||||
props: {
|
||||
formInline: {
|
||||
id: client.id,
|
||||
serverId: serverInfo.id,
|
||||
name: client.name,
|
||||
email: client.email,
|
||||
subnetRange: client.subnetRange,
|
||||
ipAllocation: client.ipAllocation,
|
||||
allowedIPS: client.allowedIPS,
|
||||
extraAllowedIPS: client.extraAllowedIPS,
|
||||
endpoint: client.endpoint,
|
||||
useServerDNS: client.useServerDNS,
|
||||
enableAfterCreation: client.enableAfterCreation,
|
||||
keys: client.keys,
|
||||
enabled: Number(client.enabled)
|
||||
}
|
||||
},
|
||||
beforeSure: (done, { options }) => {
|
||||
const FormRef = editClientFormRef.value.getDetailFormRef();
|
||||
FormRef.validate(valid => {
|
||||
if (!valid) return;
|
||||
saveClient(options.props.formInline).then(res => {
|
||||
if (res.code === 200) {
|
||||
done();
|
||||
getClientsApi(clientSearchForm.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 打开删除弹窗
|
||||
const openDeleteMessageBox = (clientName: string, clientId: string) => {
|
||||
ElMessageBox.confirm("是否删除:" + clientName, "删除", {
|
||||
distinguishCancelAndClose: true,
|
||||
confirmButtonText: "确认",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
center: true
|
||||
}).then(() => {
|
||||
deleteClient(clientId).then(res => {
|
||||
if (res.code === 200) {
|
||||
getClientsApi(clientSearchForm.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const searchHandler = (value: object) => {
|
||||
getClientsApi(value);
|
||||
};
|
||||
|
||||
// 重置搜索表单
|
||||
const resetSearchHandler = (value: object) => {
|
||||
getClientsApi({
|
||||
current: 1,
|
||||
size: 9
|
||||
});
|
||||
clientSearchForm.value.current = 1;
|
||||
clientSearchForm.value.size = 9;
|
||||
};
|
||||
|
||||
// 定义分页相关事件
|
||||
const pageChange = (page: number, size: number) => {
|
||||
clientSearchForm.value.size = size;
|
||||
clientSearchForm.value.current = page;
|
||||
getClientsApi(clientSearchForm.value);
|
||||
};
|
||||
|
||||
// 超长省略号显示
|
||||
const ellipsis = (str: string) => {
|
||||
if (!str) return "";
|
||||
if (str.length >= 10) {
|
||||
return str.slice(0, 10) + "...";
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
getClientsApi(clientSearchForm.value);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-header" style="padding-bottom: 5px">
|
||||
<el-card>
|
||||
<PlusSearch
|
||||
v-model="clientSearchForm"
|
||||
resetText="重置"
|
||||
searchText="搜索"
|
||||
:hasUnfold="false"
|
||||
:columns="clientSearchFormColumns"
|
||||
:rowProps="clientSearchProps"
|
||||
label-width="80"
|
||||
label-position="right"
|
||||
@search="searchHandler"
|
||||
@reset="resetSearchHandler"
|
||||
/>
|
||||
</el-card>
|
||||
<div style="margin-top: 5px">
|
||||
<el-card>
|
||||
<el-button type="primary" @click="openAddClientDialog"
|
||||
>新增客户端</el-button
|
||||
>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<el-card body-style="padding: inherit" shadow="hover">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<el-card
|
||||
v-for="val in clientsList.data"
|
||||
style="width: 540px"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-tooltip :content="val.name" placement="top">
|
||||
<el-tag size="large">
|
||||
{{ ellipsis(val.name) }}
|
||||
</el-tag>
|
||||
</el-tooltip>
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
type="primary"
|
||||
split-button
|
||||
style="float: right"
|
||||
>
|
||||
更多
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<el-button
|
||||
type="warning"
|
||||
@click="downloadClientConfig(val.id, val.name)"
|
||||
>下载</el-button
|
||||
>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-button
|
||||
type="danger"
|
||||
@click="openDeleteMessageBox(val.name, val.id)"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button
|
||||
type="success"
|
||||
style="float: right; margin-right: 5px"
|
||||
@click="openQrCodeDialog(val.name, val.id)"
|
||||
>二维码</el-button
|
||||
>
|
||||
<el-button
|
||||
type="primary"
|
||||
style="float: right; margin-right: 5px"
|
||||
@click="openEditClientDialog(val)"
|
||||
>
|
||||
详情
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-form label-position="top">
|
||||
<el-form-item prop="name" label="名称">
|
||||
<el-input v-model="val.name" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="email" label="邮箱">
|
||||
<el-input v-model="val.email" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="ipAllocation" label="客户端IP">
|
||||
<el-select
|
||||
v-model="val.ipAllocation"
|
||||
:clearable="true"
|
||||
:reserve-keyword="false"
|
||||
suffix-icon=""
|
||||
tag-type="primary"
|
||||
popper-class="options-class"
|
||||
placeholder=""
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="allowedIPS" label="允许的IP范围">
|
||||
<el-select
|
||||
v-model="val.allowedIPS"
|
||||
:clearable="true"
|
||||
:reserve-keyword="false"
|
||||
suffix-icon=""
|
||||
tag-type="danger"
|
||||
popper-class="options-class"
|
||||
placeholder=""
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人">
|
||||
<el-tag effect="dark" type="primary">{{
|
||||
val.createUser
|
||||
}}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户端状态">
|
||||
<el-tag v-if="val.enabled" effect="dark" type="success"
|
||||
>启用</el-tag
|
||||
>
|
||||
<el-tag v-else effect="dark" type="warning">禁用</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item class="timeItem">
|
||||
<p>创建时间: {{ val.createdAt }}</p>
|
||||
<p>更新时间: {{ val.updatedAt }}</p>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="paginate" style="background-color: #ffffff; margin-top: 5px">
|
||||
<el-card>
|
||||
<el-pagination
|
||||
small
|
||||
background
|
||||
layout="total,prev,pager,next"
|
||||
:page-size="clientSearchForm.size"
|
||||
:total="clientsList.total"
|
||||
@change="pageChange"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.timeItem {
|
||||
.el-form-item__content {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.options-class {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.example-showcase .el-dropdown + .el-dropdown {
|
||||
margin-left: 15px;
|
||||
}
|
||||
.example-showcase .el-dropdown-link {
|
||||
cursor: pointer;
|
||||
color: var(--el-color-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user