antdtable组件支持增加搜索栏配置。增加按钮等操作。
闲话少叙,上代码
<!-- 更多与收起详见用户管理页面 -->
<template>
<div class="c-data-table">
<a-spin :spinning="spinning">
<a-card :title="title" :bordered="false">
<div class="dt-search" v-if="$slots.search || $slots.searchmore">
<!-- -->
<a-form
ref="searchform"
size="mini"
class="dt-search-form-inline"
layout="inline"
:model="searchParams"
@submit.prevent="search({ _fromBar: true, _begin: 0 })"
>
<div v-if="showmore">
<div class="formSearchLittle">
<slot name="search" />
</div>
</div>
<div v-else>
<div class="">
<slot name="searchmore" />
</div>
</div>
<button type="submit" style="display: none;"></button>
</a-form>
</div>
<div class="dt-toolbar" v-if="$slots.toolbar">
<slot name="toolbar" />
</div>
<a-table
:columns="columns"
:data-source="dataSource"
:pagination="false"
:bordered="bordered"
rowKey="id"
>
</a-table>
<a-config-provider :locale="locale" v-if="pageable">
<a-pagination
show-size-changer
v-model:current="current"
v-model:pageSize="pageSize"
:total="total"
:showQuickJumper="true"
@showSizeChange="onShowSizeChange"
@change="onChange"
>
</a-pagination>
</a-config-provider>
</a-card>
</a-spin>
</div>
</template>
<script>
import { defineComponent, ref, watch, getCurrentInstance } from "vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
import { message } from "ant-design-vue";
import { useForm } from "@ant-design-vue/use";
export default defineComponent({
name: "c-data-table",
props: {
//是否显示边框
bordered: {
type: Boolean,
default: false,
},
// 请求的返回渲染参数
resultKey: {
type: String,
default: "data",
},
// 行
columns: Array,
//请求地址
serverId: String,
//搜索请求
searchParams: {
type: Object,
default: () => ({}),
},
title: String,
// 是否显示分页
pageable: {
type: Boolean,
default: true,
},
},
setup() {
let { proxy } = getCurrentInstance();
const dataSource = ref([]);
// const searchParams = reactive({ name: "" });
const { resetFields } = useForm(proxy.$props.searchParams, {});
const spinning = ref(false);
const pageSize = ref(20);
const current = ref(1);
const total = ref(0);
const onShowSizeChange = (current, pageSize) => {
console.log(current, pageSize);
};
const onChange = (pageNumber) => {
console.log("Page: ", pageNumber);
search();
};
// 页面搜索
const search = (params = {}, fn = (rows) => rows) => {
const { _begin } = params;
console.log(proxy, fn);
if (_begin >= 0) {
current.value = _begin + 1;
}
const defaultParams = {
pageNum: current.value,
pageSize: pageSize.value,
...proxy.$props.searchParams,
};
spinning.value = true;
return proxy.axios
.get(proxy.$props.serverId, {
params: { ...defaultParams },
})
.then((response) => {
if (response.data.status == 1) {
if (proxy.$props.pageable) {
total.value = response.data.pageInfo.totalCount;
}
dataSource.value = response.data.data;
} else {
message.error("操作失败");
}
})
.catch((error) => {
console.log(error);
message.error("接口异常");
})
.finally(() => {
spinning.value = false;
});
};
//展开与收起
const showmore = ref(true);
const toogleShow = () => {
showmore.value = !showmore.value;
};
watch(pageSize, () => {
search();
});
return {
onShowSizeChange,
dataSource,
onChange,
locale: zhCN,
total,
pageSize,
current,
search,
spinning,
resetFields,
showmore,
toogleShow,
};
},
});
</script>
<style lang="scss">
.c-data-table {
.ant-table-thead > tr > th {
background-color: #1890ff;
line-height: 14px;
color: #fff;
border-bottom: 5px solid #fff;
}
.ant-table-tbody > tr > td {
line-height: 5px;
background-color: #f0f8ff;
border-bottom: 5px solid #fff;
}
.ant-table-tbody
> tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
> td {
background-color: #ddebff !important;
}
.ant-pagination {
margin-top: 1em;
}
.dt-search {
box-sizing: border-box;
padding: 8px 0 5px;
.dt-search-form-inline {
.ant-form-item {
margin-bottom: 5px;
&:last-child {
margin-right: 0;
}
}
}
.formSearchLookMore {
display: inline-block;
position: relative;
top: 4px;
}
.formSearchLittle {
display: inline-block;
margin-right: 20px;
}
}
.dt-search {
.ant-btn {
min-width: 79px;
margin-right: 10px;
font-size: 14px;
}
}
.ant-card-body {
padding: 0px 24px 24px;
}
.btnbox {
a {
margin-right: 20px;
}
}
}
.dt-toolbar {
box-sizing: border-box;
padding: 8px 0;
.ant-btn {
min-width: 79px;
margin-right: 10px;
font-size: 13px;
}
}
</style>
下边我们看一下这个组件的使用方法
使用的时候请放开所有注释
<!---本页面注释建议不要随便动!!!!!!!!!!!!!--->
<template>
<div>
<a-spin :spinning="loading">
<c-data-table
:columns="columns"
:title="'用户管理'"
:searchParams="searchParams"
ref="RefChilde"
serverId="/apis/users"
resultKey="data"
>
<template v-slot:search>
<a-form-item label="用户名">
<a-input v-model:value="searchParams.username" />
</a-form-item>
<a-form-item label="部门">
<a-input v-model:value="searchParams.deptName" />
</a-form-item>
<span class="formSearchLookMore">
<a-button type="primary" class="search" @click="gosearch()">
<template #icon>
<SearchOutlined />
查询
</template>
</a-button>
<a-button type="default" class="reset" @click="reset()">
<template #icon>
<ReloadOutlined />
重置
</template>
</a-button>
<!-- <a href="javascript:;" @click="toogleShowMore">展开<DownOutlined /></a> -->
</span>
</template>
<!-- <template v-slot:searchmore>
<a-form-item label="用户名:">
<a-input v-model:value="searchParams.username" />
</a-form-item>
<a-form-item label="密码:">
<a-input v-model:value="searchParams.deptName" />
</a-form-item>
<a-form-item label="用户名:">
<a-input v-model:value="searchParams.name1" />
</a-form-item>
<a-form-item label="密码:">
<a-input v-model:value="searchParams.pass1" />
</a-form-item>
<a-form-item label="用户名:">
<a-input v-model:value="searchParams.name2" />
</a-form-item>
<a-form-item label="密码:">
<a-input v-model:value="searchParams.pass2" />
</a-form-item>
<a-button type="primary" class="search" @click="gosearch()">
<template #icon>
<SearchOutlined />
查询
</template>
</a-button>
<a-button type="default" class="reset" @click="resetFields">
<template #icon>
<ReloadOutlined />
重置
</template>
</a-button>
<a href="javascript:;" @click="toogleShowMore">收起<UpOutlined /></a>
</template> -->
</c-data-table>
</a-spin>
</div>
</template>
<script>
import {
defineComponent,
reactive,
ref,
getCurrentInstance,
onMounted,
} from "vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
import { SearchOutlined, ReloadOutlined } from "@ant-design/icons-vue";
import { Modal, message } from "ant-design-vue";
import CDataTable from "../../../../commons/CDataTable";
import { fmtDict } from "../../../../commons/common";
import { gender, status } from "../../../../commons/publicArray";
import _ from "lodash";
export default defineComponent({
components: {
[CDataTable.name]: CDataTable,
SearchOutlined,
ReloadOutlined,
},
setup() {
const columns = [
{
title: "用户名",
dataIndex: "username",
key: "username",
},
{
title: "性别",
dataIndex: "gender",
customRender: ({ text }) => {
return <div>{fmtDict(text, gender)}</div>;
},
},
{
title: "手机号",
dataIndex: "phone",
key: "phone",
ellipsis: true,
},
{
title: "邮箱",
dataIndex: "email",
key: "email",
ellipsis: true,
},
{
title: "部门",
dataIndex: "deptName",
key: "deptName",
ellipsis: true,
},
{
title: "创建时间",
dataIndex: "createTime",
key: "createTime",
ellipsis: true,
},
{
title: "更新时间",
dataIndex: "updateTime",
key: "updateTime",
ellipsis: true,
},
{
title: "用户状态",
dataIndex: "status",
customRender: ({ text }) => {
return <div>{fmtDict(text, status)}</div>;
},
},
{
title: "操作",
width: "220px",
customRender: ({ text, index }) => {
if (text.status == "FROZEN") {
return (
<div class="btnbox">
<a href="javascript:;" onClick={() => lookMore(text, index)}>
角色分配
</a>
<a href="javascript:;" onClick={() => unblock(text, index)}>
解冻
</a>
</div>
);
} else {
return (
<div class="btnbox">
<a href="javascript:;" onClick={() => lookMore(text, index)}>
角色分配
</a>
<a href="javascript:;" onClick={() => block(text, index)}>
冻结
</a>
</div>
);
}
},
},
];
let { proxy } = getCurrentInstance();
//搜索数据
const searchParams = reactive({
username: "",
deptName: "",
});
//loading加载
const loading = ref(false);
//弹框显示与隐藏
const visible = ref(false);
const RefChilde = ref(null);
//角色弹框title
const title = ref("");
//用于存储userid
const userId = ref();
//用户分配角色
const targetKeys = ref([]);
const selectedKeys = ref([]);
const mockData = ref([]);
const handleChange = (nextTargetKeys, direction, moveKeys) => {
console.log("nextTargetKeys", nextTargetKeys);
console.log("direction: ", direction);
console.log("moveKeys: ", moveKeys);
if (direction == "right") {
//绑定角色
proxy.axios
.post("/apis/users/" + userId.value + "/bindRole", {
roleIds: moveKeys,
})
.then((res) => {
if (res.data.status == 1) {
message.success("分配成功");
targetKeys.value = nextTargetKeys;
} else {
message.error("分配失败");
}
});
} else {
//移出角色
proxy.axios
.post("/apis/users/" + userId.value + "/removeRole", {
roleIds: moveKeys,
})
.then((res) => {
if (res.data.status == 1) {
message.success("移除成功");
targetKeys.value = nextTargetKeys;
} else {
message.error("移除失败");
}
});
}
};
const handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys];
};
//调用子组件的查询方法
const gosearch = () => {
RefChilde.value.search({ _fromBar: true, _begin: 0 });
};
//掉用子组件的重置方法
const reset = () => {
RefChilde.value.resetFields();
};
//给用户绑定角色拉起弹框
const lookMore = (text, index) => {
console.log(text, index);
loading.value = true;
title.value = "为 " + text.username + " 赋予角色";
userId.value = text.id;
proxy.axios
.get("/apis/users/" + text.id + "/roles")
.then((res) => {
mockData.value = res.data.data.assigned.concat(
res.data.data.available
);
_.forEach(res.data.data.assigned, (item) => {
targetKeys.value.push(item.id);
});
visible.value = true;
})
.catch(() => {
message.error("获取失败");
})
.finally(() => {
loading.value = false;
});
};
//冻结
const block = (item, index) => {
console.log(item, index);
Modal.warning({
title: "请确认是否对用户" + item.name + "进行冻结操作",
okText: "确认", // 设置按钮内容,默认为 OK
onOk: () => {
// 点击确认后的回调
proxy.axios
.patch("/apis/users/" + item.id + "/freeze")
.then((res) => {
if (res.data.status == 1) {
message.success("冻结成功");
gosearch();
} else {
message.error("冻结失败");
}
})
.catch((error) => {
message.error(error);
});
},
});
};
//解冻
const unblock = (item, index) => {
console.log(item, index);
Modal.warning({
title: "请确认是否对用户" + item.name + "进行解冻操作",
okText: "确认", // 设置按钮内容,默认为 OK
onOk: () => {
// 点击确认后的回调
proxy.axios
.patch("/apis/users/" + item.id + "/unfreeze")
.then((res) => {
if (res.data.status == 1) {
message.success("解冻成功");
gosearch();
} else {
message.error("解冻失败");
}
})
.catch((error) => {
message.error(error);
});
},
});
};
//展开与收起切换
// const toogleShowMore = () => {
// RefChilde.value.toogleShow();
// };
onMounted(() => {
gosearch();
});
return {
columns,
lookMore,
searchParams,
gosearch,
reset,
RefChilde,
// toogleShowMore,
block,
unblock,
loading,
visible,
title,
mockData,
targetKeys,
selectedKeys,
handleChange,
handleSelectChange,
locale: zhCN,
};
},
});
</script>