codex/dev
mula.liu 2026-03-26 17:32:31 +08:00
parent 4715cd4a86
commit 498bd97f99
10 changed files with 111 additions and 93 deletions

4
.gitignore vendored
View File

@ -61,3 +61,7 @@ backend/uploads/
.idea/
*.swp
*.swo
# Vibe Coding
.memsearch
/frontend/.memsearch

View File

@ -4,7 +4,7 @@ import {
Button,
Input,
Space,
Modal,
Drawer,
Form,
Select,
App,
@ -34,11 +34,11 @@ import {
CloudUploadOutlined,
CheckCircleOutlined,
RocketOutlined,
SaveOutlined,
} from '@ant-design/icons';
import apiClient from '../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../config/api';
import AdminModuleShell from '../components/AdminModuleShell';
import StatusTag from '../components/StatusTag';
const { Text } = Typography;
const { TextArea } = Input;
@ -65,7 +65,7 @@ const ClientManagement = () => {
const [clients, setClients] = useState([]);
const [loading, setLoading] = useState(true);
const [showModal, setShowModal] = useState(false);
const [showDrawer, setShowDrawer] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [selectedClient, setSelectedClient] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
@ -136,7 +136,7 @@ const ClientManagement = () => {
is_latest: false,
});
}
setShowModal(true);
setShowDrawer(true);
};
const handleSave = async () => {
@ -166,7 +166,7 @@ const ClientManagement = () => {
message.success('版本创建成功');
}
setShowModal(false);
setShowDrawer(false);
fetchClients();
} catch (error) {
if (!error?.errorFields) {
@ -336,21 +336,17 @@ const ClientManagement = () => {
{
title: '发布状态',
key: 'status',
width: 170,
width: 140,
render: (_, record) => (
<Space direction="vertical" size={4}>
<Switch
size="small"
checked={isTruthy(record.is_active)}
loading={updatingStatusId === record.id}
checkedChildren="启用"
unCheckedChildren="停用"
onChange={(checked) => handleToggleActive(record, checked)}
/>
<Space size={6}>
<StatusTag active={record.is_active} compact />
{isTruthy(record.is_latest) ? <Badge status="success" text="最新版本" /> : <Badge status="default" text="历史版本" />}
</Space>
</Space>
),
},
{
@ -368,13 +364,13 @@ const ClientManagement = () => {
render: (_, record) => (
<Space size="middle">
<Tooltip title="编辑">
<Button type="text" icon={<EditOutlined />} onClick={() => openModal(record)} />
<Button type="text" className="btn-text-edit" icon={<EditOutlined />} onClick={() => openModal(record)} />
</Tooltip>
<Tooltip title="下载">
<Button type="text" icon={<DownloadOutlined />} href={record.download_url} target="_blank" />
<Button type="text" className="btn-text-view" icon={<DownloadOutlined />} href={record.download_url} target="_blank" />
</Tooltip>
<Tooltip title="删除">
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
<Button type="text" danger className="btn-text-delete" icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
</Tooltip>
</Space>
),
@ -389,7 +385,7 @@ const ClientManagement = () => {
subtitle="统一维护移动端、桌面端与专用终端的版本发布、安装包上传、启停控制与最新版本标记。"
rightActions={(
<Space>
<Button icon={<ReloadOutlined />} onClick={fetchClients} loading={loading}>刷新</Button>
<Button icon={<ReloadOutlined />} className="btn-soft-blue" onClick={fetchClients} loading={loading}>刷新</Button>
<Button type="primary" icon={<PlusOutlined />} onClick={() => openModal()}>新增发布</Button>
</Space>
)}
@ -462,13 +458,20 @@ const ClientManagement = () => {
</div>
</AdminModuleShell>
<Modal
open={showModal}
<Drawer
open={showDrawer}
title={isEditing ? '编辑客户端版本' : '发布新版本'}
onCancel={() => setShowModal(false)}
onOk={handleSave}
width={720}
destroyOnHidden
placement="right"
width={760}
onClose={() => setShowDrawer(false)}
destroyOnClose
extra={(
<Space>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSave}>
{isEditing ? '保存修改' : '发布版本'}
</Button>
</Space>
)}
>
<Form form={form} layout="vertical" style={{ marginTop: 20 }}>
<Row gutter={16}>
@ -550,7 +553,7 @@ const ClientManagement = () => {
</Space>
</div>
</Form>
</Modal>
</Drawer>
</div>
);
};

View File

@ -13,7 +13,6 @@ import {
Segmented,
Select,
Space,
Switch,
Tag,
Tooltip,
Typography,

View File

@ -4,7 +4,7 @@ import {
Button,
Input,
Space,
Modal,
Drawer,
Form,
Select,
App,
@ -20,6 +20,7 @@ import {
} from 'antd';
import {
PlusOutlined,
SaveOutlined,
DeleteOutlined,
EditOutlined,
SearchOutlined,
@ -37,7 +38,6 @@ import {
import apiClient from '../../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../../config/api';
import AdminModuleShell from '../../components/AdminModuleShell';
import StatusTag from '../../components/StatusTag';
const { Text } = Typography;
const { TextArea } = Input;
@ -76,7 +76,7 @@ const ExternalAppManagement = () => {
const [apps, setApps] = useState([]);
const [loading, setLoading] = useState(true);
const [showModal, setShowModal] = useState(false);
const [showDrawer, setShowDrawer] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [selectedApp, setSelectedApp] = useState(null);
const [filterAppType, setFilterAppType] = useState('all');
@ -122,7 +122,7 @@ const ExternalAppManagement = () => {
app_info: {},
});
}
setShowModal(true);
setShowDrawer(true);
};
const handleSave = async () => {
@ -142,7 +142,7 @@ const ExternalAppManagement = () => {
message.success('应用创建成功');
}
setShowModal(false);
setShowDrawer(false);
fetchApps();
} catch (error) {
if (!error.errorFields) {
@ -308,16 +308,13 @@ const ExternalAppManagement = () => {
{
title: '状态',
key: 'status',
width: 140,
width: 110,
render: (_, record) => (
<Space direction="vertical" size={4}>
<Switch
size="small"
checked={record.is_active === 1 || record.is_active === true}
onChange={(checked) => handleToggleStatus(record, checked)}
/>
<StatusTag active={record.is_active} compact />
</Space>
),
},
{
@ -337,6 +334,7 @@ const ExternalAppManagement = () => {
<Tooltip title="打开入口">
<Button
type="text"
className="btn-text-view"
icon={<ExportOutlined />}
href={getAppEntryUrl(record)}
target="_blank"
@ -344,10 +342,10 @@ const ExternalAppManagement = () => {
/>
</Tooltip>
<Tooltip title="编辑">
<Button type="text" icon={<EditOutlined />} onClick={() => handleOpenModal(record)} />
<Button type="text" className="btn-text-edit" icon={<EditOutlined />} onClick={() => handleOpenModal(record)} />
</Tooltip>
<Tooltip title="删除">
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
<Button type="text" danger className="btn-text-delete" icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
</Tooltip>
</Space>
),
@ -362,7 +360,7 @@ const ExternalAppManagement = () => {
subtitle="统一维护原生应用与 Web 应用入口,支持 APK 自动解析、图标上传和状态治理。"
rightActions={(
<Space>
<Button icon={<ReloadOutlined />} onClick={fetchApps} loading={loading}>刷新</Button>
<Button icon={<ReloadOutlined />} className="btn-soft-blue" onClick={fetchApps} loading={loading}>刷新</Button>
<Button type="primary" icon={<PlusOutlined />} onClick={() => handleOpenModal()}>添加应用</Button>
</Space>
)}
@ -430,13 +428,20 @@ const ExternalAppManagement = () => {
</div>
</AdminModuleShell>
<Modal
open={showModal}
<Drawer
open={showDrawer}
title={isEditing ? '编辑外部应用' : '添加外部应用'}
onCancel={() => setShowModal(false)}
onOk={() => form.submit()}
placement="right"
width={680}
destroyOnHidden
onClose={() => setShowDrawer(false)}
destroyOnClose
extra={(
<Space>
<Button type="primary" icon={<SaveOutlined />} onClick={() => form.submit()}>
{isEditing ? '保存修改' : '创建应用'}
</Button>
</Space>
)}
>
<Form form={form} layout="vertical" style={{ marginTop: 20 }} onFinish={handleSave}>
<Form.Item name="app_type" label="应用类型" rules={[{ required: true, message: '请选择应用类型' }]}>
@ -554,12 +559,12 @@ const ExternalAppManagement = () => {
</Col>
<Col span={12}>
<Form.Item name="is_active" label="状态" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
<Switch />
</Form.Item>
</Col>
</Row>
</Form>
</Modal>
</Drawer>
</div>
);
};

View File

@ -486,7 +486,7 @@ const HotWordManagement = () => {
<Input.TextArea rows={2} placeholder="可选描述" />
</Form.Item>
<Form.Item name="status" label="启用" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
<Switch />
</Form.Item>
</Form>
</Drawer>
@ -516,7 +516,7 @@ const HotWordManagement = () => {
<Select options={languageOptions.filter((o) => o.value !== 'all')} />
</Form.Item>
<Form.Item name="status" label="是否启用" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
<Switch />
</Form.Item>
</Form>
</Drawer>

View File

@ -178,7 +178,7 @@ const ParameterManagement = () => {
<Input.TextArea rows={2} />
</Form.Item>
<Form.Item name="is_active" label="启用状态" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
<Switch />
</Form.Item>
</Form>
</Drawer>

View File

@ -1044,7 +1044,7 @@ const PermissionManagement = () => {
</Col>
<Col span={12}>
<Form.Item label="启用状态" name="is_active" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" disabled={menuPanelMode === 'view'} />
<Switch disabled={menuPanelMode === 'view'} />
</Form.Item>
</Col>
</Row>

View File

@ -195,7 +195,7 @@ const PromptManagement = () => {
</Space>
<Space>
<Text type="secondary">状态:</Text>
<Switch size="small" checked={editingPrompt.is_active === 1} onChange={v => handleEditChange('is_active', v ? 1 : 0)} />
<Switch checked={editingPrompt.is_active === 1} onChange={v => handleEditChange('is_active', v ? 1 : 0)} />
</Space>
</Space>
</Card>

View File

@ -4,7 +4,7 @@ import {
Button,
Input,
Space,
Modal,
Drawer,
Form,
Select,
App,
@ -18,6 +18,7 @@ import {
} from 'antd';
import {
PlusOutlined,
SaveOutlined,
DeleteOutlined,
EditOutlined,
SearchOutlined,
@ -32,7 +33,6 @@ import {
import apiClient from '../../utils/apiClient';
import { buildApiUrl, API_ENDPOINTS } from '../../config/api';
import AdminModuleShell from '../../components/AdminModuleShell';
import StatusTag from '../../components/StatusTag';
const { Text } = Typography;
const { TextArea } = Input;
@ -52,7 +52,7 @@ const TerminalManagement = () => {
const [filterStatus, setFilterStatus] = useState('all');
const [filterActivation, setFilterActivation] = useState('all');
const [showModal, setShowModal] = useState(false);
const [showDrawer, setShowDrawer] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [selectedTerminal, setSelectedTerminal] = useState(null);
@ -107,7 +107,7 @@ const TerminalManagement = () => {
status: true,
});
}
setShowModal(true);
setShowDrawer(true);
};
const handleSave = async () => {
@ -126,7 +126,7 @@ const TerminalManagement = () => {
message.success('终端创建成功');
}
setShowModal(false);
setShowDrawer(false);
fetchTerminals();
} catch (error) {
if (!error.errorFields) {
@ -266,16 +266,13 @@ const TerminalManagement = () => {
{
title: '状态',
key: 'status',
width: 140,
width: 110,
render: (_, record) => (
<Space direction="vertical" size={4}>
<Switch
size="small"
checked={record.status === 1}
onChange={(checked) => handleToggleStatus(record, checked)}
/>
<StatusTag active={record.status} compact />
</Space>
),
},
{
@ -304,10 +301,10 @@ const TerminalManagement = () => {
render: (_, record) => (
<Space size="middle">
<Tooltip title="编辑">
<Button type="text" icon={<EditOutlined />} onClick={() => handleOpenModal(record)} />
<Button type="text" className="btn-text-edit" icon={<EditOutlined />} onClick={() => handleOpenModal(record)} />
</Tooltip>
<Tooltip title="删除">
<Button type="text" danger icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
<Button type="text" danger className="btn-text-delete" icon={<DeleteOutlined />} onClick={() => handleDelete(record)} />
</Tooltip>
</Space>
),
@ -322,7 +319,7 @@ const TerminalManagement = () => {
subtitle="维护终端设备全生命周期:注册、绑定、激活、启停与在线状态监控。"
rightActions={(
<Space>
<Button icon={<ReloadOutlined />} onClick={fetchTerminals} loading={loading}>刷新</Button>
<Button icon={<ReloadOutlined />} className="btn-soft-blue" onClick={fetchTerminals} loading={loading}>刷新</Button>
<Button type="primary" icon={<PlusOutlined />} onClick={() => handleOpenModal()}>添加终端</Button>
</Space>
)}
@ -385,7 +382,7 @@ const TerminalManagement = () => {
<Select.Option value="pending">未激活</Select.Option>
</Select>
<Tooltip title={`最近 ${ONLINE_MINUTES} 分钟内有心跳即视为在线`}>
<Button icon={<SyncOutlined />} onClick={fetchTerminals} loading={loading} />
<Button icon={<SyncOutlined />} className="btn-soft-blue" onClick={fetchTerminals} loading={loading} />
</Tooltip>
</Space>
)}
@ -402,14 +399,20 @@ const TerminalManagement = () => {
</div>
</AdminModuleShell>
<Modal
open={showModal}
<Drawer
open={showDrawer}
title={isEditing ? '编辑终端' : '添加终端'}
onCancel={() => setShowModal(false)}
onOk={handleSave}
okText={isEditing ? '保存修改' : '创建终端'}
placement="right"
width={720}
destroyOnHidden
onClose={() => setShowDrawer(false)}
destroyOnClose
extra={(
<Space>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSave}>
{isEditing ? '保存修改' : '创建终端'}
</Button>
</Space>
)}
>
<Form form={form} layout="vertical" style={{ marginTop: 20 }}>
<Row gutter={16}>
@ -452,7 +455,7 @@ const TerminalManagement = () => {
</Col>
<Col span={12}>
<Form.Item name="status" label="启用状态" valuePropName="checked">
<Switch checkedChildren="启用" unCheckedChildren="停用" />
<Switch />
</Form.Item>
</Col>
</Row>
@ -461,7 +464,7 @@ const TerminalManagement = () => {
<TextArea rows={3} placeholder="记录设备部署位置、资产编号或特殊说明" />
</Form.Item>
</Form>
</Modal>
</Drawer>
</div>
);
};

View File

@ -1,8 +1,7 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Table, Button, Input, Space, Modal, Form, Select, App, Tooltip, Tag } from 'antd';
import { Table, Button, Input, Space, Drawer, Form, Select, App, Tooltip, Tag } from 'antd';
import {
PlusOutlined,
CloseOutlined,
EditOutlined,
DeleteOutlined,
KeyOutlined,
@ -27,7 +26,7 @@ const UserManagement = () => {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [loading, setLoading] = useState(true);
const [showUserModal, setShowUserModal] = useState(false);
const [showUserDrawer, setShowUserDrawer] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [currentUser, setCurrentUser] = useState(null);
const [roles, setRoles] = useState([]);
@ -95,7 +94,7 @@ const UserManagement = () => {
form.resetFields();
form.setFieldsValue({ role_id: 2 });
}
setShowUserModal(true);
setShowUserDrawer(true);
};
const handleSave = async () => {
@ -108,7 +107,7 @@ const UserManagement = () => {
await apiClient.post(buildApiUrl(API_ENDPOINTS.USERS.CREATE), values);
message.success('用户添加成功');
}
setShowUserModal(false);
setShowUserDrawer(false);
fetchUsers();
} catch (err) {
if (err.response) {
@ -258,15 +257,20 @@ const UserManagement = () => {
</div>
</AdminModuleShell>
<Modal
open={showUserModal}
<Drawer
open={showUserDrawer}
title={isEditing ? '编辑用户' : '新增用户'}
onCancel={() => setShowUserModal(false)}
onOk={handleSave}
okText={isEditing ? '保存修改' : '创建用户'}
okButtonProps={{ icon: <SaveOutlined /> }}
cancelButtonProps={{ icon: <CloseOutlined /> }}
destroyOnHidden
placement="right"
width={520}
onClose={() => setShowUserDrawer(false)}
destroyOnClose
extra={(
<Space>
<Button type="primary" icon={<SaveOutlined />} onClick={handleSave}>
{isEditing ? '保存修改' : '创建用户'}
</Button>
</Space>
)}
>
<Form form={form} layout="vertical" style={{ marginTop: 20 }} initialValues={{ role_id: 2 }}>
<Form.Item name="username" label="用户名" rules={[{ required: true, message: '请输入用户名' }]}>
@ -299,7 +303,7 @@ const UserManagement = () => {
</div>
)}
</Form>
</Modal>
</Drawer>
</div>
);
};