chore: apply cargo fmt across workspace and update docs

- Run cargo fmt on all Rust crates for consistent formatting
- Update CLAUDE.md with WASM plugin commands and dev.ps1 instructions
- Update wiki: add WASM plugin architecture, rewrite dev environment docs
- Minor frontend cleanup (unused imports)
This commit is contained in:
iven
2026-04-15 00:49:20 +08:00
parent e16c1a85d7
commit 9568dd7875
113 changed files with 4355 additions and 937 deletions

View File

@@ -14,6 +14,7 @@ export interface UserInfo {
avatar_url?: string;
status: string;
roles: RoleInfo[];
version: number;
}
export interface RoleInfo {

View File

@@ -11,6 +11,7 @@ export interface OrganizationInfo {
level: number;
sort_order: number;
children: OrganizationInfo[];
version: number;
}
export interface CreateOrganizationRequest {
@@ -24,6 +25,7 @@ export interface UpdateOrganizationRequest {
name?: string;
code?: string;
sort_order?: number;
version: number;
}
// --- Department types ---
@@ -38,6 +40,7 @@ export interface DepartmentInfo {
path?: string;
sort_order: number;
children: DepartmentInfo[];
version: number;
}
export interface CreateDepartmentRequest {
@@ -53,6 +56,7 @@ export interface UpdateDepartmentRequest {
code?: string;
manager_id?: string;
sort_order?: number;
version: number;
}
// --- Position types ---
@@ -64,6 +68,7 @@ export interface PositionInfo {
code?: string;
level: number;
sort_order: number;
version: number;
}
export interface CreatePositionRequest {
@@ -78,6 +83,7 @@ export interface UpdatePositionRequest {
code?: string;
level?: number;
sort_order?: number;
version: number;
}
// --- Organization API ---

View File

@@ -7,6 +7,7 @@ export interface RoleInfo {
code: string;
description?: string;
is_system: boolean;
version: number;
}
export interface PermissionInfo {
@@ -27,6 +28,7 @@ export interface CreateRoleRequest {
export interface UpdateRoleRequest {
name?: string;
description?: string;
version: number;
}
export async function listRoles(page = 1, pageSize = 20) {

View File

@@ -22,6 +22,7 @@ export interface UpdateUserRequest {
phone?: string;
display_name?: string;
status?: string;
version: number;
}
export async function listUsers(page = 1, pageSize = 20, search = '') {

View File

@@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react';
import { Badge, List, Popover, Button, Empty, Typography, Space, theme } from 'antd';
import { BellOutlined, CheckOutlined } from '@ant-design/icons';
import { Badge, List, Popover, Button, Empty, Typography, theme } from 'antd';
import { BellOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { useMessageStore } from '../stores/message';

View File

@@ -82,7 +82,7 @@ const SidebarMenuItem = memo(function SidebarMenuItem({
export default function MainLayout({ children }: { children: React.ReactNode }) {
const { sidebarCollapsed, toggleSidebar, theme: themeMode, setTheme } = useAppStore();
const { user, logout } = useAuthStore();
const { token } = theme.useToken();
theme.useToken();
const navigate = useNavigate();
const location = useLocation();
const currentPath = location.pathname || '/';

View File

@@ -1,4 +1,3 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Form, Input, Button, message, Divider } from 'antd';
import { UserOutlined, LockOutlined, SafetyCertificateOutlined } from '@ant-design/icons';

View File

@@ -10,8 +10,6 @@ import {
Table,
Popconfirm,
message,
Typography,
Card,
Empty,
Tag,
theme,
@@ -52,7 +50,7 @@ export default function Organizations() {
// --- Org tree state ---
const [orgTree, setOrgTree] = useState<OrganizationInfo[]>([]);
const [selectedOrg, setSelectedOrg] = useState<OrganizationInfo | null>(null);
const [loading, setLoading] = useState(false);
const [, setLoading] = useState(false);
// --- Department tree state ---
const [deptTree, setDeptTree] = useState<DepartmentInfo[]>([]);
@@ -144,6 +142,7 @@ export default function Organizations() {
name: values.name,
code: values.code,
sort_order: values.sort_order,
version: editOrg.version,
});
message.success('组织更新成功');
} else {

View File

@@ -69,7 +69,7 @@ export default function Roles() {
}) => {
try {
if (editRole) {
await updateRole(editRole.id, values);
await updateRole(editRole.id, { ...values, version: editRole.version });
message.success('角色更新成功');
} else {
await createRole(values);

View File

@@ -107,6 +107,7 @@ export default function Users() {
display_name: values.display_name,
email: values.email,
phone: values.phone,
version: editUser.version,
};
await updateUser(editUser.id, req);
message.success('用户更新成功');
@@ -144,7 +145,9 @@ export default function Users() {
const handleToggleStatus = async (id: string, status: string) => {
try {
await updateUser(id, { status });
const user = users.find(u => u.id === id);
if (!user) return;
await updateUser(id, { status, version: user.version });
message.success(status === 'disabled' ? '用户已禁用' : '用户已启用');
fetchUsers();
} catch {

View File

@@ -1,5 +1,5 @@
import { useState } from 'react';
import { Tabs, theme } from 'antd';
import { Tabs } from 'antd';
import { PartitionOutlined, FileSearchOutlined, CheckSquareOutlined, MonitorOutlined } from '@ant-design/icons';
import ProcessDefinitions from './workflow/ProcessDefinitions';
import PendingTasks from './workflow/PendingTasks';
@@ -8,8 +8,6 @@ import InstanceMonitor from './workflow/InstanceMonitor';
export default function Workflow() {
const [activeKey, setActiveKey] = useState('definitions');
const { token } = theme.useToken();
const isDark = token.colorBgContainer === '#111827' || token.colorBgContainer === 'rgb(17, 24, 39)';
return (
<div>

View File

@@ -1,5 +1,5 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { Table, Select, Input, Space, Tag, message, theme } from 'antd';
import { useState, useEffect, useCallback } from 'react';
import { Table, Select, Input, Tag, message, theme } from 'antd';
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import { listAuditLogs, type AuditLogItem, type AuditLogQuery } from '../../api/auditLogs';
@@ -53,12 +53,8 @@ export default function AuditLogViewer() {
setLoading(false);
}, []);
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
fetchLogs(query);
}
fetchLogs(query);
}, [query, fetchLogs]);
const handleFilterChange = (field: keyof AuditLogQuery, value: string | undefined) => {

View File

@@ -50,7 +50,7 @@ export default function DictionaryManager() {
setLoading(true);
try {
const result = await listDictionaries();
setDictionaries(Array.isArray(result) ? result : result.items ?? []);
setDictionaries(Array.isArray(result) ? result : result.data ?? []);
} catch {
message.error('加载字典列表失败');
}

View File

@@ -45,29 +45,6 @@ function flattenMenuTree(tree: MenuItem[]): MenuItem[] {
return result;
}
/** Convert flat menu list to tree structure for Table children prop */
function buildMenuTree(items: MenuItem[]): MenuItem[] {
const map = new Map<string, MenuItem>();
const roots: MenuItem[] = [];
const withChildren = items.map((item) => ({
...item,
children: [] as MenuItem[],
}));
withChildren.forEach((item) => map.set(item.id, item));
withChildren.forEach((item) => {
if (item.parent_id && map.has(item.parent_id)) {
map.get(item.parent_id)!.children!.push(item);
} else {
roots.push(item);
}
});
return roots;
}
/** Convert menu tree to TreeSelect data nodes */
function toTreeSelectData(
items: MenuItem[],
@@ -91,7 +68,7 @@ const menuTypeLabels: Record<string, { text: string; color: string }> = {
// --- Component ---
export default function MenuConfig() {
const [menus, setMenus] = useState<MenuItem[]>([]);
const [_menus, setMenus] = useState<MenuItem[]>([]);
const [menuTree, setMenuTree] = useState<MenuItem[]>([]);
const [loading, setLoading] = useState(false);
const [modalOpen, setModalOpen] = useState(false);

View File

@@ -57,7 +57,7 @@ export default function NumberingRules() {
setLoading(true);
try {
const result = await listNumberingRules();
setRules(Array.isArray(result) ? result : result.items ?? []);
setRules(Array.isArray(result) ? result : result.data ?? []);
} catch {
message.error('加载编号规则失败');
}

View File

@@ -3,14 +3,13 @@ import { Form, Input, Select, Button, ColorPicker, message, Typography } from 'a
import {
getTheme,
updateTheme,
type ThemeConfig,
} from '../../api/themes';
// --- Component ---
export default function ThemeSettings() {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const fetchTheme = useCallback(async () => {

View File

@@ -86,7 +86,7 @@ export default function InstanceMonitor() {
title: '确认挂起',
content: '确定要挂起该流程实例吗?挂起后可通过"恢复"按钮继续执行。',
okText: '确定挂起',
okType: 'warning',
okType: 'default',
cancelText: '取消',
onOk: async () => {
try {

View File

@@ -162,7 +162,7 @@ export default function ProcessDesigner({ definitionId, onSave }: ProcessDesigne
const flowNodes: NodeDef[] = nodes.map((n) => ({
id: n.id,
type: (n.data.nodeType as NodeDef['type']) || 'UserTask',
name: n.data.name || String(n.data.label),
name: String(n.data.name || n.data.label || ''),
position: { x: Math.round(n.position.x), y: Math.round(n.position.y) },
}));
const flowEdges: EdgeDef[] = edges.map((e) => ({
@@ -220,7 +220,7 @@ export default function ProcessDesigner({ definitionId, onSave }: ProcessDesigne
<p style={{ fontWeight: 500, margin: '0 0 8px', fontSize: 12 }}></p>
<Input
size="small"
value={selectedNode.data.name || ''}
value={String(selectedNode.data.name || '')}
onChange={(e) => handleUpdateNodeName(e.target.value)}
placeholder="节点名称"
style={{ marginBottom: 8 }}

View File

@@ -3,9 +3,9 @@ import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
plugins: [react(), ...tailwindcss()],
server: {
port: 5173,
port: 5174,
proxy: {
"/api": {
target: "http://localhost:3000",
@@ -22,21 +22,19 @@ export default defineConfig({
cssTarget: "chrome120",
rollupOptions: {
output: {
manualChunks: {
"vendor-react": ["react", "react-dom", "react-router-dom"],
"vendor-antd": ["antd", "@ant-design/icons"],
"vendor-utils": ["axios", "zustand"],
manualChunks(id) {
if (id.includes("node_modules/react-dom") || id.includes("node_modules/react/") || id.includes("node_modules/react-router-dom")) {
return "vendor-react";
}
if (id.includes("node_modules/antd") || id.includes("node_modules/@ant-design")) {
return "vendor-antd";
}
if (id.includes("node_modules/axios") || id.includes("node_modules/zustand")) {
return "vendor-utils";
}
},
},
},
minify: "terser",
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ["console.log", "console.info", "console.debug"],
},
},
sourcemap: false,
reportCompressedSize: false,
chunkSizeWarningLimit: 600,