This commit is contained in:
xmdhs 2023-10-08 17:15:02 +08:00
parent 6493edce01
commit b2eb6ee28e
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95
4 changed files with 102 additions and 13 deletions

View File

@ -104,8 +104,12 @@ export async function changeName(name: string, token: string) {
return await apiGet<unknown>(r) return await apiGet<unknown>(r)
} }
export async function ListUser(page: number, token: string) { export async function ListUser(page: number, token: string, email: string, name: string) {
const r = await fetch(import.meta.env.VITE_APIADDR + "/api/v1/admin/users?page=" + String(page), { const u = new URL(import.meta.env.VITE_APIADDR + "/api/v1/admin/users")
u.searchParams.set("page", String(page))
u.searchParams.set("email", email)
u.searchParams.set("name", name)
const r = await fetch(u.toString(), {
method: "GET", method: "GET",
headers: { headers: {
"Authorization": "Bearer " + token "Authorization": "Bearer " + token

View File

@ -6,7 +6,7 @@ import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper'; import Paper from '@mui/material/Paper';
import useTitle from '@/hooks/useTitle'; import useTitle from '@/hooks/useTitle';
import { useRequest } from 'ahooks'; import { useMemoizedFn, useRequest } from 'ahooks';
import { ListUser } from '@/apis/apis'; import { ListUser } from '@/apis/apis';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
@ -15,28 +15,56 @@ import TablePagination from '@mui/material/TablePagination';
import Alert from '@mui/material/Alert'; import Alert from '@mui/material/Alert';
import Snackbar from '@mui/material/Snackbar'; import Snackbar from '@mui/material/Snackbar';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
import Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import { UserInfo } from '@/apis/model';
import { produce } from 'immer'
export default function UserAdmin() { export default function UserAdmin() {
useTitle("用户管理") useTitle("用户管理")
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const nowtoken = useAtomValue(token) const nowtoken = useAtomValue(token)
const [err, setErr] = useState("") const [err, setErr] = useState("")
const [email, setEmail] = useState("")
const [name, setName] = useState("")
const [open, setOpen] = useState(false);
const [row, setRow] = useState<UserInfo | null>(null)
const handleOpen = (row: UserInfo) => {
setRow(row)
setOpen(true)
}
const uq = new URLSearchParams("/api/v1/admin/users")
uq.set("page", String(page))
uq.set("email", email)
uq.set("name", name)
const { data, run } = useRequest(ListUser, { const { data, run } = useRequest(ListUser, {
cacheKey: "/api/v1/admin/users?page=" + String(page), cacheKey: uq.toString(),
debounceWait: 300,
onError: e => { onError: e => {
setErr(String(e)) setErr(String(e))
} }
}) })
useEffect(() => { useEffect(() => {
run(page, nowtoken) run(page, nowtoken, email, name)
}, [page, nowtoken, run]) }, [page, nowtoken, run, email, name])
return (<> return (<>
<Paper> <Paper>
<Box sx={{ p: "1em", display: "flex", gap: "1em", alignItems: "flex-end" }}>
<Chip label="前缀筛选" />
<TextField onChange={v => setEmail(v.target.value)} label="邮箱" variant="standard" />
<TextField onChange={v => setName(v.target.value)} label="用户名" variant="standard" />
</Box>
<TableContainer > <TableContainer >
<Table> <Table>
<TableHead> <TableHead>
@ -55,7 +83,7 @@ export default function UserAdmin() {
<TableCell>{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell>{row.reg_ip}</TableCell> <TableCell>{row.reg_ip}</TableCell>
<TableCell>{row.uuid}</TableCell> <TableCell>{row.uuid}</TableCell>
<TableCell><Button></Button></TableCell> <TableCell><Button onClick={() => handleOpen(row)}></Button></TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
@ -74,5 +102,49 @@ export default function UserAdmin() {
<Alert onClose={() => setErr("")} severity="error">{err}</Alert> <Alert onClose={() => setErr("")} severity="error">{err}</Alert>
</Snackbar> </Snackbar>
<MyDialog open={open} setOpen={setOpen} row={row} />
</>); </>);
} }
interface MyDialogProp {
open: boolean
setOpen: (b: boolean) => void
row: UserInfo | null
}
function MyDialog({ open, row, setOpen }: MyDialogProp) {
const handleClose = useMemoizedFn(() => {
setOpen(false)
})
const [nrow, setNrow] = useState(row)
useEffect(() => {
setNrow(row)
}, [row])
return (
<Dialog open={open}>
<DialogTitle></DialogTitle>
<DialogContent>
<TextField
margin="dense"
label="邮箱"
type="email"
fullWidth
variant="standard"
value={nrow?.email}
onChange={e => setNrow(produce(v => {
if (!v) return
v.email = e.target.value
return
}))}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}></Button>
<Button onClick={handleClose}></Button>
</DialogActions>
</Dialog>
)
}

View File

@ -70,8 +70,10 @@ func (h *Handel) ListUser() http.HandlerFunc {
} }
pagei = p pagei = p
} }
email := r.FormValue("email")
name := r.FormValue("name")
ul, uc, err := h.webService.ListUser(ctx, pagei) ul, uc, err := h.webService.ListUser(ctx, pagei, email, name)
if err != nil { if err != nil {
h.handleError(ctx, w, err.Error(), model.ErrService, 500, slog.LevelWarn) h.handleError(ctx, w, err.Error(), model.ErrService, 500, slog.LevelWarn)
return return

View File

@ -5,7 +5,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/xmdhs/authlib-skin/db/ent/predicate"
"github.com/xmdhs/authlib-skin/db/ent/user" "github.com/xmdhs/authlib-skin/db/ent/user"
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
"github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
utilsService "github.com/xmdhs/authlib-skin/service/utils" utilsService "github.com/xmdhs/authlib-skin/service/utils"
@ -32,8 +34,17 @@ func (w *WebService) IsAdmin(ctx context.Context, t *model.TokenClaims) error {
return nil return nil
} }
func (w *WebService) ListUser(ctx context.Context, page int) ([]model.UserList, int, error) { func (w *WebService) ListUser(ctx context.Context, page int, email, name string) ([]model.UserList, int, error) {
u, err := w.client.User.Query().WithProfile().Limit(20).Offset((page - 1) * 20).All(ctx) whereL := []predicate.User{}
if email != "" {
whereL = append(whereL, user.EmailHasPrefix(email))
}
if name != "" {
whereL = append(whereL, user.HasProfileWith(userprofile.NameHasPrefix(name)))
}
u, err := w.client.User.Query().WithProfile().
Where(user.And(whereL...)).
Limit(20).Offset((page - 1) * 20).All(ctx)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("ListUser: %w", err) return nil, 0, fmt.Errorf("ListUser: %w", err)
} }
@ -55,7 +66,7 @@ func (w *WebService) ListUser(ctx context.Context, page int) ([]model.UserList,
}) })
} }
uc, err := w.client.User.Query().Count(ctx) uc, err := w.client.User.Query().Where(user.And(whereL...)).Count(ctx)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("ListUser: %w", err) return nil, 0, fmt.Errorf("ListUser: %w", err)
} }