|
|
@@ -0,0 +1,281 @@
|
|
|
+<script setup>
|
|
|
+import { Page, useVbenModal } from '@vben/common-ui';
|
|
|
+import { Button, Card, Tag, Avatar, Switch, Space, Popconfirm, message } from "ant-design-vue";
|
|
|
+import { useVbenForm } from '#/adapter/form';
|
|
|
+import { $t } from "@vben/locales";
|
|
|
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
|
|
|
+import { getAccountList, deleteAccount, getAccountInfo, updateAccountInfo, createAccount } from "#/api/user/user_list";
|
|
|
+import { ref } from 'vue';
|
|
|
+import dayjs from 'dayjs';
|
|
|
+
|
|
|
+import ExtraModal from './user_info.vue';
|
|
|
+
|
|
|
+// const [QueryForm] = useVbenForm({
|
|
|
+// // 默认展开
|
|
|
+// collapsed: false,
|
|
|
+// // 所有表单项共用,可单独在表单内覆盖
|
|
|
+// commonConfig: {
|
|
|
+// // 所有表单项
|
|
|
+// componentProps: {
|
|
|
+// class: 'w-full',
|
|
|
+// },
|
|
|
+// },
|
|
|
+// // 提交函数
|
|
|
+// handleSubmit: onSearch,
|
|
|
+// // 垂直布局,label和input在不同行,值为vertical
|
|
|
+// // 水平布局,label和input在同一行
|
|
|
+// layout: 'horizontal',
|
|
|
+// schema: [
|
|
|
+// {
|
|
|
+// component: 'Input',
|
|
|
+// componentProps: {
|
|
|
+// placeholder: $t('user.search.user_name'),
|
|
|
+// allowClear: true,
|
|
|
+// },
|
|
|
+// fieldName: 'user_name',
|
|
|
+// label: $t('user.search.user_name'),
|
|
|
+// },
|
|
|
+// {
|
|
|
+// component: 'Input',
|
|
|
+// componentProps: {
|
|
|
+// placeholder: $t('user.search.nick_name'),
|
|
|
+// allowClear: true,
|
|
|
+// },
|
|
|
+// fieldName: 'nick_name',
|
|
|
+// label: $t('user.search.nick_name'),
|
|
|
+// },
|
|
|
+// {
|
|
|
+// component: 'Input',
|
|
|
+// componentProps: {
|
|
|
+// placeholder: $t('user.search.phone'),
|
|
|
+// allowClear: true,
|
|
|
+// },
|
|
|
+// fieldName: 'phone',
|
|
|
+// label: $t('user.search.phone'),
|
|
|
+// },
|
|
|
+// {
|
|
|
+// component: 'Select',
|
|
|
+// componentProps: {
|
|
|
+// allowClear: true,
|
|
|
+// filterOption: true,
|
|
|
+// options: [
|
|
|
+// {
|
|
|
+// label: $t('user.role.admin'),
|
|
|
+// value: 0,
|
|
|
+// },
|
|
|
+// {
|
|
|
+// label: $t('user.role.operator'),
|
|
|
+// value: 1,
|
|
|
+// },
|
|
|
+// {
|
|
|
+// label: $t('user.role.user'),
|
|
|
+// value: 2,
|
|
|
+// },
|
|
|
+// ],
|
|
|
+// placeholder: $t('common.placeholder_select'),
|
|
|
+// showSearch: true,
|
|
|
+// },
|
|
|
+// fieldName: 'user_role',
|
|
|
+// label: $t('user.search.user_role'),
|
|
|
+// },
|
|
|
+// ],
|
|
|
+// // 是否可展开
|
|
|
+// showCollapseButton: true,
|
|
|
+// submitButtonOptions: {
|
|
|
+// content: '查询',
|
|
|
+// },
|
|
|
+// wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
|
|
|
+// });
|
|
|
+
|
|
|
+// function onSearch(values) {
|
|
|
+// // 触发表格重新加载
|
|
|
+// gridApi.reload();
|
|
|
+// }
|
|
|
+
|
|
|
+const gridOptions = {
|
|
|
+ border: true,
|
|
|
+ stripe: true,
|
|
|
+ checkboxConfig: {
|
|
|
+ highlight: true,
|
|
|
+ },
|
|
|
+ columns: [
|
|
|
+ { fixed: 'left', title: '序号', type: 'seq', width: 60 },
|
|
|
+ { field: 'user_id', title: $t('user.table.user_id'), width: 60 },
|
|
|
+ { field: 'user_name', title: $t('user.table.user_name'), width: 100 },
|
|
|
+ { field: 'nick_name', title: $t('user.table.nick_name'), width: 150 },
|
|
|
+ { field: 'phone', title: $t('user.table.phone'), width: 150 },
|
|
|
+ { field: 'role_name', title: $t('user.table.role_name'), width: 150, slots: { default: 'role' } },
|
|
|
+ { field: 'white_list_ip', title: $t('user.table.white_list_ip'), width: 150, slots: { default: 'ip' } },
|
|
|
+ { field: 'create_time', title: $t('user.table.create_time'), width: 180 },
|
|
|
+ { field: 'login_time', title: $t('user.table.login_time'), width: 180, slots: { default: 'login_time' } },
|
|
|
+ { field: 'update_time', title: $t('user.table.update_time'), width: 180 },
|
|
|
+ { fixed: 'right', title: $t('user.table.action'), width: 120, slots: { default: 'action' } },
|
|
|
+ ],
|
|
|
+ exportConfig: {},
|
|
|
+ keepSource: true,
|
|
|
+ proxyConfig: {
|
|
|
+ ajax: {
|
|
|
+ query: async ({ page }) => {
|
|
|
+ let params = {
|
|
|
+ page: page.currentPage,
|
|
|
+ limit: page.pageSize,
|
|
|
+ };
|
|
|
+ try {
|
|
|
+ const res = await getAccountList(params);
|
|
|
+ return {
|
|
|
+ total: res.total,
|
|
|
+ items: res.list
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取账号列表失败:', error);
|
|
|
+ return {
|
|
|
+ total: 0,
|
|
|
+ items: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ rowConfig: {
|
|
|
+ isHover: true,
|
|
|
+ },
|
|
|
+ toolbarConfig: {
|
|
|
+ custom: true,
|
|
|
+ export: true,
|
|
|
+ refresh: true,
|
|
|
+ zoom: true,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+const [Grid, gridApi] = useVbenVxeGrid({
|
|
|
+ gridOptions,
|
|
|
+});
|
|
|
+
|
|
|
+// 格式化登录时间
|
|
|
+const formatLoginTime = (timestamp) => {
|
|
|
+ if (!timestamp || timestamp === 0) {
|
|
|
+ return '从未登录';
|
|
|
+ }
|
|
|
+ return dayjs(timestamp * 1000).format('YYYY-MM-DD HH:mm:ss');
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化IP地址
|
|
|
+const formatIP = (ip) => {
|
|
|
+ return ip || '无限制';
|
|
|
+};
|
|
|
+
|
|
|
+// 获取角色标签颜色
|
|
|
+const getRoleColor = (roleId) => {
|
|
|
+ if (roleId === 1) {
|
|
|
+ return 'red';
|
|
|
+ } else if (roleId === 100) {
|
|
|
+ return 'blue';
|
|
|
+ }
|
|
|
+ return 'green';
|
|
|
+};
|
|
|
+
|
|
|
+const [Modal, modalApi] = useVbenModal({
|
|
|
+ connectedComponent: ExtraModal,
|
|
|
+ onBeforeClose() {
|
|
|
+ const { formData } = modalApi.getData();
|
|
|
+ if (!formData) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (formData.user_id) {
|
|
|
+ updateAccountInfo(formData)
|
|
|
+ .then(res => {
|
|
|
+ message.success('编辑账号成功');
|
|
|
+ gridApi.reload();
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ message.error('编辑账号失败');
|
|
|
+ console.error('编辑账号失败:', err);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ createAccount(formData)
|
|
|
+ .then(res => {
|
|
|
+ message.success('新增账号成功');
|
|
|
+ gridApi.reload();
|
|
|
+ })
|
|
|
+ .catch(err => {
|
|
|
+ message.error('新增账号失败');
|
|
|
+ console.error('新增账号失败:', err);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+// 新增账号
|
|
|
+const addAccount = () => {
|
|
|
+ modalApi.setState({ title: '新增账号' })
|
|
|
+ .open();
|
|
|
+};
|
|
|
+
|
|
|
+// 编辑账号
|
|
|
+const editAccount = (row) => {
|
|
|
+ modalApi.setData({ formData: row })
|
|
|
+ .setState({ title: '编辑账号' })
|
|
|
+ .open();
|
|
|
+};
|
|
|
+
|
|
|
+// 处理删除账号
|
|
|
+const handleDelete = async (row) => {
|
|
|
+ try {
|
|
|
+ await deleteAccount({ user_id: row.user_id });
|
|
|
+ message.success('删除成功');
|
|
|
+ gridApi.reload();
|
|
|
+ } catch (error) {
|
|
|
+ message.error('删除失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <Page>
|
|
|
+ <!-- <Card class="mb-5">
|
|
|
+ <QueryForm />
|
|
|
+ </Card> -->
|
|
|
+ <Card>
|
|
|
+ <div class="vp-raw w-full">
|
|
|
+ <Grid>
|
|
|
+ <template #toolbar-actions>
|
|
|
+ <Button type="primary" @click="addAccount">新增账号</Button>
|
|
|
+ </template>
|
|
|
+ <template #role="{ row }">
|
|
|
+ <Tag :color="getRoleColor(row.user_role)" size="large">
|
|
|
+ {{ row.role_name }}
|
|
|
+ </Tag>
|
|
|
+ </template>
|
|
|
+ <template #ip="{ row }">
|
|
|
+ <span>{{ formatIP(row.white_list_ip) }}</span>
|
|
|
+ </template>
|
|
|
+ <template #login_time="{ row }">
|
|
|
+ <span>{{ formatLoginTime(row.login_time) }}</span>
|
|
|
+ </template>
|
|
|
+ <template #action="{ row }">
|
|
|
+ <Space>
|
|
|
+ <Button type="link" size="small" @click="editAccount(row)">编辑</Button>
|
|
|
+ <Popconfirm
|
|
|
+ title="确定要删除这个账号吗?"
|
|
|
+ @confirm="handleDelete(row)"
|
|
|
+ ok-text="确定"
|
|
|
+ cancel-text="取消"
|
|
|
+ >
|
|
|
+ <Button type="link" size="small" danger>删除</Button>
|
|
|
+ </Popconfirm>
|
|
|
+ </Space>
|
|
|
+ </template>
|
|
|
+ </Grid>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ <Modal />
|
|
|
+ </Page>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.ant-card {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+</style>
|