hotgo/web/src/views/system/blacklist/index.vue

369 lines
9.1 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>
<n-card :bordered="false" class="proCard" title="访问黑名单">
<BasicForm
@register="register"
@submit="handleSubmit"
@reset="handleReset"
@keyup.enter="handleSubmit"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:openChecked="true"
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1090"
>
<template #tableTitle>
<n-button type="primary" @click="addTable">
<template #icon>
<n-icon>
<PlusOutlined />
</n-icon>
</template>
新建
</n-button>
&nbsp;
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
<template #icon>
<n-icon>
<DeleteOutlined />
</n-icon>
</template>
批量删除
</n-button>
</template>
</BasicTable>
<n-modal
v-model:show="showModal"
:show-icon="false"
preset="dialog"
title="新建"
style="width: 720px"
>
<n-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
>
<n-form-item label="IP地址" path="ip">
<n-input type="textarea" placeholder="请输入IP地址" v-model:value="formParams.ip" />
<template #feedback>
<p>支持添加IP如果添加多个IP请用","隔开</p>
<p>支持添加IP段,如192.168.0.0/24</p>
<p>支持添加IP范围,格式如192.168.1.xx-192.168.1.xx</p>
<br />
</template>
</n-form-item>
<n-form-item label="状态" path="status">
<n-radio-group v-model:value="formParams.status" name="status">
<n-radio-button
v-for="status in statusOptions"
:key="status.value"
:value="status.value"
:label="status.label"
/>
</n-radio-group>
</n-form-item>
<n-form-item label="备注" path="remark">
<n-input type="textarea" placeholder="请输入备注" v-model:value="formParams.remark" />
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showModal = false)">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
</n-space>
</template>
</n-modal>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { h, onMounted, reactive, ref } from 'vue';
import { NTag, useDialog, useMessage } from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
import { Delete, Edit, List, Status } from '@/api/sys/blacklist';
import { DeleteOutlined, PlusOutlined } from '@vicons/antd';
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
import { Dict } from '@/api/dict/dict';
import { getOptionLabel, getOptionTag } from '@/utils/hotgo';
const options = ref({
status: [],
});
const columns = [
{
title: 'ID',
key: 'id',
},
{
title: 'IP地址',
key: 'ip',
},
{
title: '备注',
key: 'remark',
},
{
title: '状态',
key: 'status',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: getOptionTag(options.value.status, row.status),
bordered: false,
},
{
default: () => getOptionLabel(options.value.status, row.status),
}
);
},
},
{
title: '创建时间',
key: 'createdAt',
},
];
const params = ref<any>({
pageSize: 10,
title: '',
content: '',
status: null,
});
const rules = {
title: {
// required: true,
trigger: ['blur', 'input'],
message: '请输入标题',
},
};
const schemas = ref<FormSchema[]>([
{
field: 'ip',
component: 'NInput',
label: 'IP地址',
componentProps: {
placeholder: '请输入IP地址',
onUpdateValue: (e: any) => {
console.log(e);
},
},
rules: [{ message: '请输入IP地址', trigger: ['blur'] }],
},
{
field: 'status',
component: 'NSelect',
label: '状态',
defaultValue: null,
componentProps: {
placeholder: '请选择类型',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
]);
const message = useMessage();
const actionRef = ref();
const dialog = useDialog();
const showModal = ref(false);
const formBtnLoading = ref(false);
const searchFormRef = ref<any>({});
const formRef = ref<any>({});
const batchDeleteDisabled = ref(true);
const checkedIds = ref([]);
const resetFormParams = {
id: 0,
ip: '',
remark: '',
sort: 0,
status: 1,
};
let formParams = ref<any>(resetFormParams);
const actionColumn = reactive({
width: 220,
title: '操作',
key: 'action',
fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'button',
actions: [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
onClick: handleDelete.bind(null, record),
},
],
dropDownActions: statusActions,
select: (key) => {
updateStatus(record.id, key);
},
});
},
});
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
function addTable() {
showModal.value = true;
formParams.value = resetFormParams;
}
const loadDataTable = async (res) => {
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
};
function onCheckedRow(rowKeys) {
console.log(rowKeys);
batchDeleteDisabled.value = rowKeys.length <= 0;
checkedIds.value = rowKeys;
}
function reloadTable() {
actionRef.value.reload();
}
function confirmForm(e) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
Edit(formParams.value)
.then((_res) => {
message.success('操作成功');
setTimeout(() => {
showModal.value = false;
reloadTable();
formParams.value = ref(resetFormParams);
});
})
.catch((e: Error) => {
message.error(e.message ?? '操作失败');
});
} else {
message.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
function handleEdit(record: Recordable) {
showModal.value = true;
formParams.value = record;
}
function handleDelete(record: Recordable) {
dialog.warning({
title: '警告',
content: '你确定要删除?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Delete(record).then((_res) => {
message.success('操作成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function batchDelete() {
dialog.warning({
title: '警告',
content: '你确定要删除?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Delete({ id: checkedIds.value })
.then((_res) => {
message.success('操作成功');
reloadTable();
})
.catch((e: Error) => {
message.error(e.message ?? '操作失败');
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function handleSubmit(values: Recordable) {
params.value = values;
reloadTable();
}
function handleReset(values: Recordable) {
params.value = values;
reloadTable();
}
function updateStatus(id, status) {
Status({ id: id, status: status }).then((_res) => {
message.success('操作成功');
setTimeout(() => {
reloadTable();
});
});
}
async function loadOptions() {
options.value.status = await Dict('sys_normal_disable');
for (const item of schemas.value) {
if (item.field === 'status') {
item.componentProps.options = options.value.status;
}
}
}
onMounted(async () => {
await loadOptions();
});
</script>
<style lang="less" scoped></style>