7.8 KiB
XinAdmin
XinAdmin is a full-stack development framework: PHP8.2 + Laravel12 + React19 + TypeScript + Ant Design6 + Zustand + Tailwind CSS4. Licensed under MIT, free for commercial use without authorization.
Built-in Features
- Dashboard: Echarts-based dashboards with demo pages
- Administrators: Backend user management with groups, permissions, and settings
- Role & Department Management: Role-based menu permission control, enterprise org structure
- System Settings: Visual form-based server variable configuration
- File Management: Backend file manager with folders, multi-select, grouping
- Dictionary Management: Maintenance of frequently used static data
- Mail & Storage Configuration: Visual config and testing for Laravel mail/filesystem
- AI Configuration: Visual config and testing for Laravel AI SDK
- Frontend Members: Permission, grouping, lists, balance records
AnnoRoute
AnnoRoute is a PHP 8 Attribute-based route registration module. Routes are declared via controller annotations — no manual route files needed. Sanctum auth and permission verification are auto-integrated.
Usage
#[GetRoute]/#[PostRoute]/#[PutRoute]/#[DeleteRoute]on methods declare HTTP routes- The
authorizeparameter controls access:'query'becomes abilityprefix.query,falsemakes a route public #[RequestAttribute]params:routePrefix,abilitiesPrefix,middleware(string|array),authGuard(?string)- Method attributes share:
route(path appended to prefix),authorize(string|bool),middleware,where(regex array) - Final route =
routePrefix + route; final ability =abilitiesPrefix + '.' + authorize - When
authorizeis not falsy,auth:sanctum+authGuard+abilities:middleware are auto-assembled - Extend
Modules\Common\Http\Controllers\BaseControllerforsuccess()/error()response helpers
Frontend
Source lives in web/. Bundled with Vite, outputting to public/. Package manager: pnpm.
Directory Structure
| Directory | Purpose |
|---|---|
web/api/ |
Typed Axios wrappers per backend module |
web/components/ |
Reusable UI: AuthButton, DictTag, IconFont, XinForm, XinTable |
web/domain/ |
TypeScript interfaces for API models |
web/hooks/ |
useAuth, useLanguage, useMobile, useRequest |
web/layout/ |
Layout engine (4 modes), menu, header, breadcrumbs, theme |
web/locales/ |
i18n (i18next), zh_CN + en_US |
web/pages/ |
Auto-discovered page components (file-system routing) |
web/router/ |
React Router v7 createBrowserRouter |
web/stores/ |
Zustand: global (app/theme), user (auth/perms), dict (cache) |
web/utils/ |
Axios instance with dedup, auth headers, error handling |
Key Conventions
- Path alias
@/→web/ - Zustand stores:
State+Actions→persist+devtools→ localStorage - Access stores via selector:
useXxxStore(state => state.field) - All user-facing text via
useTranslation()(react-i18next) - Locale files mirror page paths:
pages/system/user.tsx→locales/zh_CN/system/user.ts, key prefixsystem.user - All keys dot-separated, double quotes, 2-space indent. See
@skill:xinadmin-developmentfor details - Permission checks:
<AuthButton auth="system.user.create">oruseAuth().auth('permission') - HTTP client auto-attaches
Authorization: Bearer,User-Language, handles 401 auto-logout - Pages in
web/pages/are auto-routed;index.tsxmaps to parent directory; root/→/dashboard/analysis - Pages outside layout: add to
excludePathsarray in router config
Antd
Ant Design 6 is the UI component library. Components are imported from antd and themed via <ConfigProvider> with tokens from web/layout/theme.ts.
Key Conventions
- Use
antdMCP tools (antd_info,antd_doc,antd_demo) to verify component APIs before writing code - Never use deprecated props or components — check with
antd_changelogwhen upgrading or referencing older examples - Theme tokens flow:
web/layout/theme.ts→<ConfigProvider theme={...}>→ Ant Design components - Common components:
Table,Form,Modal,Drawer,Button,Input,Select,DatePicker,Switch,Tag,Card,App...
Layout
Wraps authenticated pages. Supports 4 modes set via global store: side (default), top, mix, columns.
Menus are fetched from /system/menu and stored in LayoutContext (React Context). Menu type: 'menu' (folder), 'route' (page), 'rule' (perm-only). Server filters by user role — no client-side filtering needed. Labels support i18n via node.local.
Theme tokens (20+ properties) are managed in web/layout/theme.ts, applied via Ant Design <ConfigProvider>, persisted to localStorage under global-storage.
XinForm And XinTable
Two declarative JSON-driven CRUD components. Define columns once with metadata — the same definition drives table display, search form, and create/edit forms.
XinForm
Use for settings/config pages or standalone forms. Supports 3 layout modes: 'Form' (inline), 'ModalForm', 'DrawerForm'.
<XinForm
columns={[
{ dataIndex: 'username', title: 'Username', valueType: 'text', rules: [{ required: true }] },
{ dataIndex: 'role_id', title: 'Role', valueType: 'select', fieldProps: { options: roleOptions } },
]}
layoutType="ModalForm"
grid
trigger={<Button type="primary">New</Button>}
modalProps={{ title: 'Create User', width: 600 }}
onFinish={async (values) => { await save(values); return true; }}
/>
Key FormColumn fields: dataIndex (supports nested paths ['a','b']), valueType (26 types: text, password, select, date, switch, etc.), fieldProps, fieldRender (custom render), dependency (field linkage: { dependencies, visible?, disabled?, fieldProps? }), hideIn* visibility flags.
formRef exposes open(), close(), isOpen(), setLoading() plus all Ant Design FormInstance methods.
XinTable
Use for standard CRUD pages (list + create + update + delete). Auto-handles API calls, permissions, search, and toolbar.
<XinTable<ISysUser>
api="/system/user"
columns={[
{ title: 'ID', dataIndex: 'id', hideInForm: true, width: 80 },
{ title: 'Username', dataIndex: 'username', valueType: 'text', rules: [{ required: true }] },
{ title: 'Status', dataIndex: 'status', valueType: 'radio', render: (v) => <Tag>{v === 1 ? 'Active' : 'Inactive'}</Tag> },
]}
rowKey="id"
accessName="system.user"
formProps={{ grid: true, colProps: { span: 12 }, layout: 'vertical' }}
modalProps={{ width: 800 }}
/>
Required props: api (REST endpoint), accessName (permission prefix), rowKey (PK field), columns.
Default REST behavior — GET {api} for list, POST {api} for create, PUT {api}/{id} for update, DELETE {api}/{id} for delete. Add/edit/delete buttons auto-wrapped in <AuthButton auth={accessName + '.create'}>.
Customize with: handleRequest (full custom fetch), requestParams (transform before send), handleFinish (custom submit), actionBarRender / toolBarRender / operateRender (slot overrides).
Choosing Between Them
- XinTable: Full CRUD pages (users, roles, dicts, files)
- XinForm (inline/ModalForm): Settings pages with a single form (mail, storage, AI config)
- XinForm (ModalForm + trigger): Add/edit without a table (dept management)
- Use
hideInForm/hideInTable/hideInSearchto control per-context visibility
Development Workflow
When building a new CRUD feature, follow this four-phase workflow. See @skill:xinadmin-development for complete details.
- Database Migration — create table structure, indexes, foreign keys
- Backend — Controller (AnnoRoute attributes), Model, FormRequest
- Frontend — Page (file-system routing), Domain types, API wrappers, i18n
- Menu & Permissions — seeder menu entry + rules, menu translation keys