Commit 5a3fb30d authored by David Yang's avatar David Yang

feat: 应用切换

parent 48eaa28c
...@@ -20,6 +20,8 @@ export default defineConfig({ ...@@ -20,6 +20,8 @@ export default defineConfig({
react: resolvePackageRoot('react'), react: resolvePackageRoot('react'),
'react-dom': resolvePackageRoot('react-dom'), 'react-dom': resolvePackageRoot('react-dom'),
}, },
base: '/model_analysis/',
publicPath: '/model_analysis/',
routes: [ routes: [
{ {
path: ROUTE_PATHS.login, path: ROUTE_PATHS.login,
......
{
"name": "model_analysis",
"version": "1.0.1",
"build": "abc",
"description": "merge master",
"date": "2025-07-14 19:27:20",
"author": "yang"
}
...@@ -100,7 +100,7 @@ export function Combobox({ ...@@ -100,7 +100,7 @@ export function Combobox({
// Anchor positioning // Anchor positioning
'[--anchor-gap:--spacing(2)] [--anchor-padding:--spacing(4)] sm:data-[anchor~=start]:[--anchor-offset:-4px]', '[--anchor-gap:--spacing(2)] [--anchor-padding:--spacing(4)] sm:data-[anchor~=start]:[--anchor-offset:-4px]',
// Base styles, // Base styles,
'isolate min-w-[calc(var(--input-width)+8px)] scroll-py-1 rounded-xl p-1 select-none empty:invisible', 'isolate z-[160] min-w-[calc(var(--input-width)+8px)] scroll-py-1 rounded-xl p-1 select-none empty:invisible',
// Invisible border that is only visible in `forced-colors` mode for accessibility purposes // Invisible border that is only visible in `forced-colors` mode for accessibility purposes
'outline outline-transparent focus:outline-hidden', 'outline outline-transparent focus:outline-hidden',
// Handle scrolling when menu won't fit in viewport // Handle scrolling when menu won't fit in viewport
......
import { UserContext } from '@/wrapper/Auth'; import { UserContext } from '@/wrapper/Auth';
import { import {
ChartCard, ChartCard,
HeroBanner,
MetricCard, MetricCard,
NoticeBanner, NoticeBanner,
Panel,
SectionHeader,
Tag,
} from './AnalysisShared'; } from './AnalysisShared';
import {
ClockIcon,
ShareIcon,
} from '@heroicons/react/24/outline';
import { import {
buildOverviewCharts, buildOverviewCharts,
buildMetricCards, buildMetricCards,
...@@ -19,6 +19,58 @@ import { ...@@ -19,6 +19,58 @@ import {
} from './analysisService'; } from './analysisService';
import { useContext, useEffect, useMemo, useState } from 'react'; import { useContext, useEffect, useMemo, useState } from 'react';
function OverviewStatusItem({ icon: Icon, label, value, hint }) {
return (
<div className="flex min-w-0 items-start gap-3 rounded-lg border border-zinc-200 bg-white px-4 py-3 shadow-sm">
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-rose-50 text-rose-600">
<Icon className="size-[18px]" />
</div>
<div className="min-w-0">
<div className="text-xs font-medium text-zinc-500">{label}</div>
<div className="mt-1 truncate text-lg font-semibold leading-6 text-zinc-950">
{value}
</div>
<div className="mt-0.5 truncate text-xs text-zinc-500">{hint}</div>
</div>
</div>
);
}
function OverviewHeader({ welcomeName, lastUpdatedAt, sharedViewCount }) {
return (
<section className="overflow-hidden rounded-lg border border-zinc-200/80 bg-white shadow-sm">
<div className="grid gap-5 bg-[linear-gradient(135deg,rgba(255,241,242,0.78),rgba(255,255,255,0.96)_42%,rgba(248,250,252,0.98))] p-5 lg:grid-cols-[minmax(0,1fr)_minmax(360px,480px)] lg:items-center lg:p-6">
<div className="min-w-0">
<div className="inline-flex rounded-full border border-rose-200 bg-white/80 px-3 py-1 text-[11px] font-semibold tracking-[0.16em] text-rose-700">
ANALYSIS OVERVIEW
</div>
<h1 className="mt-4 max-w-4xl text-2xl font-semibold leading-tight text-zinc-950 sm:text-3xl">
{welcomeName},这里是新分析工具的统一驾驶舱
</h1>
<p className="mt-3 max-w-4xl text-sm leading-6 text-zinc-600">
聚合视图配置、转发审批和图表看板三条主链路,先判断配置成熟度,再进入具体分析任务。
</p>
</div>
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<OverviewStatusItem
icon={ClockIcon}
label="最近更新时间"
value={lastUpdatedAt}
hint="配置或审批变更"
/>
<OverviewStatusItem
icon={ShareIcon}
label="共享视图数"
value={sharedViewCount}
hint="团队开放配置"
/>
</div>
</div>
</section>
);
}
export default function AnalysisOverview() { export default function AnalysisOverview() {
const userInfo = useContext(UserContext); const userInfo = useContext(UserContext);
const [subjects, setSubjects] = useState([]); const [subjects, setSubjects] = useState([]);
...@@ -76,6 +128,20 @@ export default function AnalysisOverview() { ...@@ -76,6 +128,20 @@ export default function AnalysisOverview() {
); );
const welcomeName = const welcomeName =
userInfo?.display_name || userInfo?.displayName || userInfo?.username || '业务同事'; userInfo?.display_name || userInfo?.displayName || userInfo?.username || '业务同事';
const lastUpdatedAt = useMemo(
() =>
formatDateTime(
[...views, ...forwards, ...boards]
.map((item) => item.updatedAt || item.createdAt)
.sort()
.pop(),
),
[boards, forwards, views],
);
const sharedViewCount = useMemo(
() => views.filter((item) => item.scope === 'shared').length,
[views],
);
const viewChartOption = useMemo( const viewChartOption = useMemo(
() => ({ () => ({
...@@ -159,41 +225,10 @@ export default function AnalysisOverview() { ...@@ -159,41 +225,10 @@ export default function AnalysisOverview() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
<HeroBanner <OverviewHeader
eyebrow="ANALYSIS OVERVIEW" welcomeName={welcomeName}
title={`${welcomeName},这里是新分析工具的统一驾驶舱`} lastUpdatedAt={lastUpdatedAt}
description="总览页聚合对象覆盖、视图配置、转发审批和图表看板四条主链路,方便业务先看配置成熟度,再进入视图或审批页处理具体分析任务。" sharedViewCount={sharedViewCount}
aside={
<div className="grid gap-3 sm:grid-cols-2">
<div className="rounded-[24px] border border-white/70 bg-white/80 p-4 shadow-sm">
<div className="text-xs font-semibold tracking-[0.18em] text-zinc-500">
最近更新时间
</div>
<div className="mt-2 text-2xl font-semibold text-zinc-950">
{formatDateTime(
[...views, ...forwards, ...boards]
.map((item) => item.updatedAt || item.createdAt)
.sort()
.pop(),
)}
</div>
<div className="mt-1 text-sm text-zinc-500">
最新配置或审批变更时间
</div>
</div>
<div className="rounded-[24px] border border-white/70 bg-white/80 p-4 shadow-sm">
<div className="text-xs font-semibold tracking-[0.18em] text-zinc-500">
共享视图数
</div>
<div className="mt-2 text-2xl font-semibold text-zinc-950">
{views.filter((item) => item.scope === 'shared').length}
</div>
<div className="mt-1 text-sm text-zinc-500">
已对团队开放的分析配置
</div>
</div>
</div>
}
/> />
{loading ? <NoticeBanner>正在加载分析总览...</NoticeBanner> : null} {loading ? <NoticeBanner>正在加载分析总览...</NoticeBanner> : null}
...@@ -230,83 +265,6 @@ export default function AnalysisOverview() { ...@@ -230,83 +265,6 @@ export default function AnalysisOverview() {
emptyText="还没有图表看板" emptyText="还没有图表看板"
/> />
</div> </div>
<div className="grid gap-6 xl:grid-cols-[1.1fr_0.9fr]">
<Panel className="p-6">
<SectionHeader
title="对象覆盖"
description="后端对象定义是整个分析工具的底座,新增对象后可以直接在视图页配置。"
/>
<div className="grid gap-3">
{subjects.length > 0 ? (
subjects.map((subject) => (
<div
key={subject.name}
className="rounded-[22px] border border-zinc-200 bg-zinc-50/80 px-4 py-4"
>
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div>
<div className="text-base font-semibold text-zinc-950">
{subject.title || subject.name}
</div>
<div className="mt-1 text-sm text-zinc-500">
{subject.description || '当前对象已可用于配置分析视图。'}
</div>
</div>
<Tag tone="sky">{subject.fields.length} 个字段</Tag>
</div>
</div>
))
) : (
<div className="text-sm text-zinc-400">暂无可用对象定义</div>
)}
</div>
</Panel>
<Panel className="p-6">
<SectionHeader
title="最近活动"
description="把最近新增或更新的视图、审批和看板放在一起,方便判断业务关注点。"
/>
<div className="space-y-3">
{[...views, ...forwards, ...boards]
.sort((left, right) =>
String(right.updatedAt || right.createdAt).localeCompare(
String(left.updatedAt || left.createdAt),
),
)
.slice(0, 6)
.map((item) => (
<div
key={`${item.id}_${item.updatedAt || item.createdAt}`}
className="rounded-[22px] border border-zinc-200 bg-white px-4 py-4"
>
<div className="flex items-center justify-between gap-3">
<div className="min-w-0">
<div className="truncate text-sm font-semibold text-zinc-950">
{item.title}
</div>
<div className="mt-1 text-xs text-zinc-500">
更新于 {formatDateTime(item.updatedAt || item.createdAt)}
</div>
</div>
{'approvalStatus' in item ? (
<Tag tone="amber">审批记录</Tag>
) : 'widgets' in item ? (
<Tag tone="emerald">图表看板</Tag>
) : (
<Tag tone="sky">分析视图</Tag>
)}
</div>
</div>
))}
{views.length + forwards.length + boards.length === 0 ? (
<div className="text-sm text-zinc-400">当前还没有配置活动</div>
) : null}
</div>
</Panel>
</div>
</div> </div>
); );
} }
...@@ -38,6 +38,8 @@ import { ...@@ -38,6 +38,8 @@ import {
formatDateTime, formatDateTime,
formatFieldValue, formatFieldValue,
getApprovalStatusLabel, getApprovalStatusLabel,
getForwardRowStatusLabel,
getForwardRowStatusTone,
getFieldInputKind, getFieldInputKind,
getViewScopeLabel, getViewScopeLabel,
loadAnalysisSubjectDefinition, loadAnalysisSubjectDefinition,
...@@ -153,6 +155,10 @@ export function ApprovalStatusTag({ status }) { ...@@ -153,6 +155,10 @@ export function ApprovalStatusTag({ status }) {
return <Tag tone={tone}>{getApprovalStatusLabel(status)}</Tag>; return <Tag tone={tone}>{getApprovalStatusLabel(status)}</Tag>;
} }
export function WorkflowStatusTag({ status }) {
return <Tag tone={getForwardRowStatusTone(status)}>{getForwardRowStatusLabel(status)}</Tag>;
}
export function EmptyCollection({ title, description }) { export function EmptyCollection({ title, description }) {
return ( return (
<div className="rounded-[24px] border border-dashed border-zinc-200 bg-zinc-50 px-5 py-10 text-center"> <div className="rounded-[24px] border border-dashed border-zinc-200 bg-zinc-50 px-5 py-10 text-center">
...@@ -258,6 +264,7 @@ export function UserSelectField({ ...@@ -258,6 +264,7 @@ export function UserSelectField({
required = false, required = false,
placeholder = '搜索用户', placeholder = '搜索用户',
}) { }) {
const [query, setQuery] = useState('');
const [options, setOptions] = useState([]); const [options, setOptions] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
...@@ -266,17 +273,22 @@ export function UserSelectField({ ...@@ -266,17 +273,22 @@ export function UserSelectField({
(async () => { (async () => {
setLoading(true); setLoading(true);
const result = await searchUsers(''); try {
if (!cancelled) { const result = await searchUsers(query);
setOptions(result); if (!cancelled) {
setLoading(false); setOptions(result);
}
} finally {
if (!cancelled) {
setLoading(false);
}
} }
})(); })();
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, []); }, [query]);
return ( return (
<div> <div>
...@@ -291,6 +303,7 @@ export function UserSelectField({ ...@@ -291,6 +303,7 @@ export function UserSelectField({
.toLowerCase() .toLowerCase()
.includes(String(query || '').toLowerCase()) .includes(String(query || '').toLowerCase())
} }
onQueryChange={setQuery}
placeholder={placeholder} placeholder={placeholder}
aria-label={label} aria-label={label}
> >
...@@ -645,6 +658,9 @@ export function RecordsResultTable({ ...@@ -645,6 +658,9 @@ export function RecordsResultTable({
records, records,
columns, columns,
selectedIds, selectedIds,
rowStatusByRecordId = {},
forwardItemByRecordId = new Map(),
onOpenForwardItem,
onToggleRow, onToggleRow,
onToggleAll, onToggleAll,
}) { }) {
...@@ -663,6 +679,7 @@ export function RecordsResultTable({ ...@@ -663,6 +679,7 @@ export function RecordsResultTable({
/> />
</TableHeader> </TableHeader>
<TableHeader>标题</TableHeader> <TableHeader>标题</TableHeader>
<TableHeader>当前状态</TableHeader>
{columns.map((column) => ( {columns.map((column) => (
<TableHeader key={column.alias}>{column.label}</TableHeader> <TableHeader key={column.alias}>{column.label}</TableHeader>
))} ))}
...@@ -670,29 +687,44 @@ export function RecordsResultTable({ ...@@ -670,29 +687,44 @@ export function RecordsResultTable({
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{records.map((record) => ( {records.map((record) => {
<TableRow key={record.id}> const recordKey = record.recordName || record.id;
<TableCell> const forwardItem = forwardItemByRecordId.get(String(recordKey));
<Checkbox
color="sky" return (
checked={selectedIds.includes(record.id)} <TableRow key={record.id}>
onChange={(checked) => onToggleRow(record, Boolean(checked))} <TableCell>
aria-label={`选择 ${record.title || record.id}`} <Checkbox
/> color="sky"
</TableCell> checked={selectedIds.includes(record.id)}
<TableCell className="font-medium text-zinc-950"> onChange={(checked) => onToggleRow(record, Boolean(checked))}
{record.title || '-'} aria-label={`选择 ${record.title || record.id}`}
</TableCell> />
{columns.map((column) => (
<TableCell key={column.alias} className="text-zinc-600">
{formatFieldValue(column, record[column.alias])}
</TableCell> </TableCell>
))} <TableCell className="font-medium text-zinc-950">
<TableCell className="text-zinc-500"> <button
{formatDateTime(record.updatedAt)} type="button"
</TableCell> onClick={() => onOpenForwardItem?.(record, forwardItem || null)}
</TableRow> className="max-w-72 truncate text-left font-medium text-sky-700 underline-offset-4 hover:text-sky-900 hover:underline"
))} aria-label={`查看 ${record.title || record.id} 的回填详情`}
>
{record.title || '-'}
</button>
</TableCell>
<TableCell>
<WorkflowStatusTag status={rowStatusByRecordId[recordKey] || 'pending_send'} />
</TableCell>
{columns.map((column) => (
<TableCell key={column.alias} className="text-zinc-600">
{formatFieldValue(column, record[column.alias])}
</TableCell>
))}
<TableCell className="text-zinc-500">
{formatDateTime(record.updatedAt)}
</TableCell>
</TableRow>
);
})}
</TableBody> </TableBody>
</Table> </Table>
); );
...@@ -705,4 +737,3 @@ export function ForwardStatusOptionsHint() { ...@@ -705,4 +737,3 @@ export function ForwardStatusOptionsHint() {
</div> </div>
); );
} }
This diff is collapsed.
import ApplicationSwitcherDialog from '@/pages/project_manager_xy/ApplicationSwitcherDialog';
import xyLogo from '@/assets/xy-logo.png'; import xyLogo from '@/assets/xy-logo.png';
import xyLogoSmall from '@/assets/xy-logo_small.png'; import xyLogoSmall from '@/assets/xy-logo_small.png';
import { UserContext } from '@/wrapper/Auth';
import { SiteContext } from '@/wrapper/Site';
import { import {
ArrowsRightLeftIcon, ArrowsRightLeftIcon,
Bars3Icon, Bars3Icon,
ChartBarSquareIcon, ChartBarSquareIcon,
ChartPieIcon, ChartPieIcon,
ClipboardDocumentListIcon, ClipboardDocumentListIcon,
Squares2X2Icon,
XMarkIcon, XMarkIcon,
} from '@heroicons/react/24/outline'; } from '@heroicons/react/24/outline';
import clsx from 'clsx'; import clsx from 'clsx';
import { useEffect, useMemo, useState } from 'react'; import { useContext, useEffect, useMemo, useState } from 'react';
import { Link, Outlet, useLocation } from 'umi'; import { Link, Outlet, useLocation } from 'umi';
const APP_NAME = '数据分析工具'; const APP_NAME = '数据分析工具';
...@@ -185,7 +189,10 @@ function MobileSidebar({ open, close, children }) { ...@@ -185,7 +189,10 @@ function MobileSidebar({ open, close, children }) {
export default function ProjectManagerLayout() { export default function ProjectManagerLayout() {
const location = useLocation(); const location = useLocation();
const userInfo = useContext(UserContext);
const siteInfo = useContext(SiteContext);
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);
const [isApplicationDialogOpen, setIsApplicationDialogOpen] = useState(false);
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false); const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
...@@ -229,6 +236,23 @@ export default function ProjectManagerLayout() { ...@@ -229,6 +236,23 @@ export default function ProjectManagerLayout() {
); );
}, [location.pathname]); }, [location.pathname]);
const applicationSwitcherButton = (
<button
type="button"
onClick={() => setIsApplicationDialogOpen(true)}
aria-label="Open application switcher"
title="应用切换"
className={clsx(
'inline-flex items-center justify-center rounded-xl border border-zinc-700 bg-zinc-800 text-zinc-300 shadow-sm transition duration-200 hover:border-[#fb923c]/70 hover:bg-zinc-800/90 hover:text-[#fdba74] focus:outline-none focus-visible:ring-2 focus-visible:ring-[#fb923c]/40',
sidebarCollapsed ? 'size-9' : 'size-10',
)}
>
<Squares2X2Icon
className={clsx(sidebarCollapsed ? 'size-[18px]' : 'size-5')}
/>
</button>
);
return ( return (
<div className="flex h-screen overflow-hidden bg-zinc-50"> <div className="flex h-screen overflow-hidden bg-zinc-50">
<aside <aside
...@@ -239,22 +263,34 @@ export default function ProjectManagerLayout() { ...@@ -239,22 +263,34 @@ export default function ProjectManagerLayout() {
> >
<div <div
className={clsx( className={clsx(
'mb-7 flex items-center', 'mb-7',
sidebarCollapsed ? 'justify-center' : 'gap-3 px-1', sidebarCollapsed
? 'flex flex-col items-center gap-3'
: 'flex items-start justify-between gap-4 px-1',
)} )}
> >
{sidebarCollapsed ? ( {sidebarCollapsed ? (
<img <>
src={xyLogoSmall} <img
alt="XY Logo" src={xyLogoSmall}
className="h-9 w-auto max-w-[52px] shrink-0 object-contain" alt="XY Logo"
/> className="h-8 w-auto max-w-8 shrink-0 object-contain"
) : null} />
{!sidebarCollapsed ? ( {applicationSwitcherButton}
<h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95"> </>
{APP_NAME} ) : (
</h1> <>
) : null} <div className="min-w-0 flex-1">
<h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95">
{APP_NAME}
</h1>
<div className="mt-1 text-xs text-zinc-400">
配置驱动的数据分析工具
</div>
</div>
{applicationSwitcherButton}
</>
)}
</div> </div>
<nav className="flex-1 space-y-5 overflow-y-auto"> <nav className="flex-1 space-y-5 overflow-y-auto">
...@@ -280,6 +316,17 @@ export default function ProjectManagerLayout() { ...@@ -280,6 +316,17 @@ export default function ProjectManagerLayout() {
</div> </div>
))} ))}
</nav> </nav>
{!sidebarCollapsed ? (
<div className="mt-6 rounded-2xl border border-zinc-800 bg-zinc-950/70 p-4 text-sm text-zinc-300">
<div className="font-medium text-white/90">
{userInfo?.display_name || userInfo?.username || '当前用户'}
</div>
<div className="mt-1 text-xs text-zinc-500">
当前正在查看数据分析工具
</div>
</div>
) : null}
</aside> </aside>
<div className="relative z-30 hidden lg:flex"> <div className="relative z-30 hidden lg:flex">
...@@ -307,15 +354,20 @@ export default function ProjectManagerLayout() { ...@@ -307,15 +354,20 @@ export default function ProjectManagerLayout() {
close={() => setIsMobileSidebarOpen(false)} close={() => setIsMobileSidebarOpen(false)}
> >
<div className="px-5 pt-6"> <div className="px-5 pt-6">
<div className="flex items-center gap-2"> <div>
<img <div className="flex items-center gap-2">
src={xyLogo} <img
alt="XY Logo" src={xyLogo}
className="h-5 w-auto max-w-[128px] shrink-0 object-contain" alt="XY Logo"
/> className="h-5 w-auto max-w-[128px] shrink-0 object-contain"
<h1 className="text-base font-semibold tracking-[0.02em] text-white"> />
{APP_NAME} <h1 className="text-base font-semibold tracking-[0.02em] text-white">
</h1> {APP_NAME}
</h1>
</div>
<div className="mt-1 text-xs text-zinc-500">
配置驱动分析工作区
</div>
</div> </div>
</div> </div>
...@@ -351,12 +403,26 @@ export default function ProjectManagerLayout() { ...@@ -351,12 +403,26 @@ export default function ProjectManagerLayout() {
<Bars3Icon className="size-5" /> <Bars3Icon className="size-5" />
</NavbarItem> </NavbarItem>
<div className="text-sm text-zinc-500">{currentGroupTitle}</div> <div className="text-sm text-zinc-500">{currentGroupTitle}</div>
<NavbarItem
onClick={() => setIsApplicationDialogOpen(true)}
aria-label="Open application switcher"
className="border border-rose-200 bg-white text-rose-500 shadow-sm hover:bg-rose-50 hover:text-rose-600"
>
<Squares2X2Icon className="size-5" />
</NavbarItem>
</div> </div>
<div className="flex-1 overflow-y-auto rounded-[32px] border border-white/70 bg-white/75 p-4 shadow-[0_24px_80px_rgba(15,23,42,0.06)] backdrop-blur sm:p-6"> <div className="flex-1 overflow-y-auto rounded-[32px] border border-white/70 bg-white/75 p-4 shadow-[0_24px_80px_rgba(15,23,42,0.06)] backdrop-blur sm:p-6">
<Outlet /> <Outlet />
</div> </div>
</main> </main>
<ApplicationSwitcherDialog
open={isApplicationDialogOpen}
onClose={() => setIsApplicationDialogOpen(false)}
userInfo={userInfo}
siteInfo={siteInfo}
/>
</div> </div>
); );
} }
...@@ -317,7 +317,7 @@ export async function searchSystemUsers(keyword = '') { ...@@ -317,7 +317,7 @@ export async function searchSystemUsers(keyword = '') {
: '', : '',
null, null,
); );
return mergeUserRecords(response?.records || []); return mergeUserRecords(response?.users || response?.records || []);
} }
export async function fetchSystemUsersByIds(ids = []) { export async function fetchSystemUsersByIds(ids = []) {
......
...@@ -603,7 +603,7 @@ function parseDocument(formData) { ...@@ -603,7 +603,7 @@ function parseDocument(formData) {
} }
// user // user
function queryUsers(page, page_size, filter = {}, status = null) { function queryUsers(page, page_size, filter = {}, status = null, groups = false) {
return request('/user/query', { return request('/user/query', {
method: 'post', method: 'post',
data: { data: {
...@@ -611,6 +611,7 @@ function queryUsers(page, page_size, filter = {}, status = null) { ...@@ -611,6 +611,7 @@ function queryUsers(page, page_size, filter = {}, status = null) {
page_size, page_size,
filter, filter,
status, status,
groups,
}, },
}); });
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment