bonus-ui/src/views/system/ipWhitelist/index.vue

499 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="IP地址" prop="ipAddress">
<el-input
v-model="queryParams.ipAddress"
placeholder="请输入IP地址"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="开始时间" prop="accessStartTime">
<el-date-picker clearable
v-model="queryParams.accessStartTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择允许访问的开始时间"
>
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="accessEndTime">
<el-date-picker clearable
v-model="queryParams.accessEndTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择允许访问的结束时间"
>
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:whitelist:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:whitelist:edit']"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:whitelist:remove']"
>删除
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="whitelistList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"/>
<el-table-column type="index" label="序号" width="50"/>
<el-table-column label="IP地址" align="center" prop="ipAddress" min-width="120px">
<template slot-scope="scope">
<span> {{scope.row.ipAddress?scope.row.ipAddress:scope.row.ipRangeStart+" - " + scope.row.ipRangeEnd}} </span>
</template>
</el-table-column>
<el-table-column label="开放时间" align="center" prop="ipRangeStart" min-width="120px">
<template slot-scope="scope">
<span> {{!scope.row.accessStartTime?"不限时间":parseTime(scope.row.accessStartTime)+" - " + parseTime(scope.row.accessEndTime)}} </span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" key="status" min-width="20px">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:whitelist:edit']"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:whitelist:remove']"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改【请填写功能名称】对话框 -->
<el-dialog title="新增" :visible.sync="open" width="800px">
<el-form ref="form" :model="form" :rules="rules">
<!-- IP 地址选择 -->
<el-form-item label="IP地址" required>
<el-radio-group v-model="ipType">
<el-radio label="single">单IP地址</el-radio>
<el-radio label="range">IP地址段</el-radio>
</el-radio-group>
<el-row v-show="ipType === 'single'" :gutter="24">
<el-col :span="10">
<IpInput
style="margin-top: 10px"
v-model="form.ipAddress"
:disabled=false
/>
</el-col>
</el-row>
<el-row v-show="ipType === 'range'" :gutter="24">
<el-col :span="10">
<IpInput
v-model="form.ipRangeStart"
style="margin-top: 10px"
:disabled=false
/>
</el-col>
<el-col :span="1">
<div style="margin-top: 10px">
<span>—</span>
</div>
</el-col>
<el-col :span="10">
<IpInput
v-model="form.ipRangeEnd"
style="margin-top: 10px"
:disabled=false
/>
</el-col>
</el-row>
</el-form-item>
<!-- 访问时间设置 -->
<el-form-item label="设置访问时间" required>
<el-radio-group v-model="timeLimit">
<el-radio label="unlimited">不限时间</el-radio>
<el-radio label="limited">限制时间</el-radio>
</el-radio-group>
<el-row v-if="timeLimit === 'limited'" :gutter="24">
<el-col :span="10">
<el-date-picker
v-model="form.accessStartTime"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</el-col>
</el-row>
</el-form-item>
<!-- 确认与取消按钮 -->
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="addSubmitForm">确 定</el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addWhitelist, delWhitelist, getWhitelist, listWhitelist, updateWhitelist,updateSysIpWhitelistStatus } from '@/api/system/ipWhitelist'
import IpInput from '@/components/bonus/IpInput/index.vue'
import { parseTime } from '../../../utils/bonus'
import { changeUserStatus } from '@/api/system/user'
export default {
components: { IpInput },
name: 'Whitelist',
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 【请填写功能名称】表格数据
whitelistList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
ipAddress: null,
ipRangeStart: null,
ipRangeEnd: null,
accessStartTime: null,
accessEndTime: null,
createdAt: null,
updatedAt: null
},
ipType: 'single',
timeLimit: 'unlimited',
// 表单参数
form: {},
// 表单校验
rules: {
ipAddress: [
{ required: true, message: '记录创建时间不能为空', trigger: 'blur' }
],
ipRangeStart: [
{ required: true, message: '记录更新时间不能为空', trigger: 'blur' }
],
ipRangeEnd: [
{ required: true, message: '记录更新时间不能为空', trigger: 'blur' }
]
}
}
},
created() {
this.getList()
},
methods: {
// 用户状态修改
handleStatusChange(row) {
let text = row.status === '0' ? '启用' : '停用'
this.$modal.confirm('确认要"' + text + '吗?').then(function() {
return updateSysIpWhitelistStatus(row.id, row.status)
}).then(() => {
this.$modal.msgSuccess(text + '成功')
}).catch(function() {
row.status = row.status === '0' ? '1' : '0'
})
},
// 格式化时间为时分秒HH:mm:ss
formatTime(timeStr) {
return new Date(`1970-01-01T${timeStr.slice(11)}`); // 只取时分秒部分
},
parseTime,
/** 查询【请填写功能名称】列表 */
getList() {
this.loading = true
listWhitelist(this.queryParams).then(response => {
this.whitelistList = response.rows
this.total = response.total
this.loading = false
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
id: null,
ipAddress: null,
ipRangeStart: null,
ipRangeEnd: null,
accessStartTime: null,
accessEndTime: null,
createdAt: null,
updatedAt: null
}
this.ipType ='single'
this.timeLimit = 'unlimited'
this.resetForm('form')
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = '添加【请填写功能名称】'
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
const id = row.id || this.ids
getWhitelist(id).then(response => {
this.form = response.data
if (!this.form.ipAddress){
this.ipType = 'range'
}else {
this.ipType = 'single'
}
if (!this.form.accessStartTime){
this.timeLimit = 'unlimited'
}else {
this.timeLimit = 'limited'
this.form.accessStartTime=[this.formatTime(this.form.accessStartTime), this.formatTime(this.form.accessEndTime)]
}
this.open = true
this.title = '修改'
})
},
addSubmitForm() {
if (this.ipType === 'single') {
if (!this.form.ipAddress) {
this.$modal.msgWarning('请输入正确的ip地址')
return
} else {
this.form.ipRangeStart = null
this.form.ipRangeEnd = null
}
} else {
if (!this.form.ipRangeStart || !this.form.ipRangeEnd) {
this.$modal.msgWarning('请输入正确的ip地址段')
return
} else {
if (!this.checkSameSubnet(this.form.ipRangeStart, this.form.ipRangeEnd)){
this.$modal.msgWarning('请输入正确的ip地址段')
return
}
if (!this.checkIpRangeValidity(this.form.ipRangeStart, this.form.ipRangeEnd)){
this.$modal.msgWarning('请输入正确的ip地址段')
return
}
this.form.ipAddress = null
}
}
if (this.timeLimit === 'limited') {
if (!this.form.accessStartTime){
this.$modal.msgWarning('请选择访问时间段')
return
}else {
const date = this.form.accessStartTime;
this.form.accessStartTime = date[0];
this.form.accessEndTime = date[1];
}
}else {
this.form.accessStartTime = null;
this.form.accessEndTime = null;
}
if (this.form.id != null) {
updateWhitelist(this.form).then(response => {
this.$modal.msgSuccess('修改成功')
this.open = false
this.getList()
})
} else {
addWhitelist(this.form).then(response => {
this.$modal.msgSuccess('新增成功')
this.open = false
this.getList()
})
}
},
// 将IP地址转换为二进制
ipToBinary(ip) {
return ip
.split('.')
.map((octet) => ('00000000' + parseInt(octet, 10).toString(2)).slice(-8))
.join('')
},
// 判断IP地址属于哪个类A、B、C类
getClass(ip) {
const firstOctet = parseInt(ip.split('.')[0], 10)
if (firstOctet >= 1 && firstOctet <= 127) return 'A'
if (firstOctet >= 128 && firstOctet <= 191) return 'B'
if (firstOctet >= 192 && firstOctet <= 223) return 'C'
return 'Unknown'
},
// 获取默认子网掩码
getDefaultSubnetMask(ip) {
const ipClass = this.getClass(ip)
switch (ipClass) {
case 'A':
return '255.0.0.0' // /8
case 'B':
return '255.255.0.0' // /16
case 'C':
return '255.255.255.0' // /24
default:
return null
}
},
// 将IP地址和子网掩码进行按位与运算得到网络部分
applySubnetMask(ipBinary, subnetBinary) {
let network = ''
for (let i = 0; i < 32; i++) {
network += ipBinary[i] === subnetBinary[i] ? ipBinary[i] : '0'
}
return network
},
// 判断两个IP是否在同一个网段
checkSameSubnet(ip1, ip2) {
const subnetMask = this.getDefaultSubnetMask(ip1)
if (!subnetMask) return false // 如果没有子网掩码,则无法判断
const ip1Binary = this.ipToBinary(ip1)
const ip2Binary = this.ipToBinary(ip2)
const subnetBinary = this.ipToBinary(subnetMask)
const ip1Network = this.applySubnetMask(ip1Binary, subnetBinary)
const ip2Network = this.applySubnetMask(ip2Binary, subnetBinary)
return ip1Network === ip2Network
},
// 检查IP范围是否有效
checkIpRangeValidity(startIp, endIp) {
const startBinary = this.ipToBinary(startIp)
const endBinary = this.ipToBinary(endIp)
// 确保起始IP小于等于结束IP
return startBinary <= endBinary
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除这些数据项?').then(function() {
return delWhitelist(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess('删除成功')
}).catch(() => {
})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/whitelist/export', {
...this.queryParams
}, `whitelist_${new Date().getTime()}.xlsx`)
}
}
}
</script>
<style lang="scss" scoped>
.el-radio__original {
display: none !important; /* 隐藏原生 radio 输入,但仍然允许交互 */
}
.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner {
box-shadow: none !important;
}
</style>