Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 优化项目创建和菜单页面关联
Browse files Browse the repository at this point in the history
JackySoft committed Oct 26, 2024

Verified

This commit was signed with the committer’s verified signature.
veigaribo Gabriel Lopes Veiga
1 parent 7259b66 commit d97fb2a
Showing 14 changed files with 330 additions and 115 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -160,15 +160,17 @@ If you encounter any technical or commercial authorization issues during use, pl

Thank you to the following brothers for their donation:

| name | profile picture |
| --------------- | ------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| name | profile picture |
| --------------- | -------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| yangshare | <img src="http://docs.marsview.cc/sponsor/8.jpeg" width="50"> |
| Joker6578 | <img src="http://docs.marsview.cc/sponsor/9.png" width="50"> |

## 🤝 Participate and contribute

20 changes: 11 additions & 9 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -161,15 +161,17 @@ git merge upstream/main

感谢以下兄弟的捐赠:

| 名称 | 头像 |
| --------------- | ------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| 名称 | 头像 |
| --------------- | -------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| yangshare | <img src="http://docs.marsview.cc/sponsor/8.jpeg" width="50"> |
| Joker6578 | <img src="http://docs.marsview.cc/sponsor/9.png" width="50"> |

## 🤝 参与贡献

Binary file added packages/docs/src/public/sponsor/8.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/docs/src/public/sponsor/9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 11 additions & 9 deletions packages/docs/src/sponsor.md
Original file line number Diff line number Diff line change
@@ -10,12 +10,14 @@ Marsview 是一个开源的可视化搭建平台,采用 MIT 许可的开源项

### 当前赞助者

| 名称 | 头像 |
| --------------- | ------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| 名称 | 头像 |
| --------------- | -------------------------------------------------------------- |
| 物联网方案-肖工 | <img src="http://docs.marsview.cc/sponsor/3.png" width="50"> |
| 🥕 二月贝弋 🥕 | <img src="http://docs.marsview.cc/sponsor/2.png" width="50"> |
| 猩猩点灯 | <img src="http://docs.marsview.cc/sponsor/1.png" width="50"> |
| 元次达 | <img src="http://docs.marsview.cc/sponsor/4.png" width="50"> |
| IoT-Fast | <img src="http://docs.marsview.cc/sponsor/5.png" width="50"> |
| w10752842 | <img src="http://docs.marsview.cc/sponsor/6.png" width="50"> |
| 朱红宾 | <img src="http://docs.marsview.cc/sponsor/7.png" width="50"> |
| yangshare | <img src="http://docs.marsview.cc/sponsor/8.jpeg" width="50"> |
| Joker6578 | <img src="http://docs.marsview.cc/sponsor/9.png" width="50"> |
2 changes: 0 additions & 2 deletions packages/editor/src/api/types/index.ts
Original file line number Diff line number Diff line change
@@ -40,14 +40,12 @@ export interface CreatePageParams {
name: string;
user_name: string;
user_id: string;
path: string;
}

export interface UpdatePageParams {
id: number;
user_id: string;
name: string;
path: string;
}

export interface PublishPageParams {
105 changes: 105 additions & 0 deletions packages/editor/src/components/CreateProject.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Input, Modal, Form, Radio } from 'antd';
import { useImperativeHandle, useState, forwardRef, useMemo } from 'react';
import { addProject } from '@/api';
import { usePageStore } from '@/stores/pageStore';
import UploadImages from './UploadImages/UploadImages';
import { message } from '@/utils/AntdGlobal';

/**
* 创建项目
*/
const CreateProject = (props: { update: () => void }, ref: any) => {
const [form] = Form.useForm();
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const userId = usePageStore((store) => store.userInfo.userId);

// 暴露方法
useImperativeHandle(ref, () => ({
open() {
setVisible(true);
},
}));

// 提交
const handleOk = async () => {
try {
await form.validateFields();
const values = form.getFieldsValue();
setLoading(true);
await addProject({ ...initValue, ...values });
message.success('创建成功');
props.update();
setLoading(false);
setVisible(false);
} catch (error) {
setLoading(false);
}
};

// 关闭
const handleCancel = () => {
form.resetFields();
setVisible(false);
};

const initValue = useMemo(() => {
return {
layout: 1,
menu_mode: 'inline',
menu_theme_color: 'dark',
system_theme_color: '#1677ff',
breadcrumb: true,
tag: true,
footer: false,
logo: 'https://marsview.cdn.bcebos.com/mars-logo.png',
is_public: 1,
is_edit: 2,
};
}, []);
return (
<Modal
title="创建项目"
open={visible}
confirmLoading={loading}
onOk={handleOk}
onCancel={handleCancel}
width={600}
okText="确定"
cancelText="取消"
>
<Form form={form} labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} initialValues={initValue}>
<Form.Item label="名称" name="name" rules={[{ required: true, message: '请输入页面名称' }]}>
<Input placeholder="请输入项目名称" maxLength={15} showCount />
</Form.Item>
<Form.Item label="描述" name="remark">
<Input placeholder="请输入项目描述" maxLength={20} showCount />
</Form.Item>
<Form.Item label="LOGO" name="logo" rules={[{ required: true, message: '请上传项目Logo' }]}>
<UploadImages />
</Form.Item>
<Form.Item
label="权限"
name="is_public"
rules={[{ required: true, message: '请选择访问类型' }]}
extra="公开页面支持所有人访问。私有页面仅自己可访问。"
>
<Radio.Group>
<Radio value={1}>公开</Radio>
<Radio value={2}>私有</Radio>
{/* 普通用户暂不开放模板设置 */}
{userId == 50 ? <Radio value={3}>公开模板</Radio> : null}
</Radio.Group>
</Form.Item>
<Form.Item label="模式" name="is_edit" rules={[{ required: true, message: '请选择编辑模式' }]} extra="公开后设置他人可查看或编辑;">
<Radio.Group>
<Radio value={1}>编辑</Radio>
<Radio value={2}>查看</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Modal>
);
};

export default forwardRef(CreateProject);
82 changes: 82 additions & 0 deletions packages/editor/src/components/CustomIconList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, { useState, useMemo } from 'react';
import { Segmented, Select } from 'antd';
import * as icons from '@ant-design/icons';
import { styled } from 'styled-components';

const BoxWrapper = styled.div`
display: flex;
flex-wrap: wrap;
width: 100%;
height: 300px;
overflow: auto;
`;

const IconItem = styled.div`
width: 50px;
height: 50px;
padding: 10px;
cursor: pointer;
`;
/**
* 菜单中,自定义图标选择列表
*/
export default function CustomIconOptions({ value, onChange }: any) {
const [open, setOpen] = useState(false);
const [type, setType] = useState('线框风格');

const allList = useMemo(() => {
// 获取所有的antd图标,动态渲染到下拉框中
const iconsList: { [key: string]: any } = icons;

return Object.keys(icons)
.filter((item) => !['default', 'createFromIconfontCN', 'getTwoToneColor', 'setTwoToneColor', 'IconProvider'].includes(item))
.map((key) => ({ value: key, label: React.createElement(iconsList[key], { style: { fontSize: '24px', verticalAlign: 'middle' } }) }));
}, []);

// 过滤出不同风格的图标
const outlined = useMemo(() => allList.filter((item) => item.value.includes('Outlined')), []);
const filled = useMemo(() => allList.filter((item) => item.value.includes('Filled')), []);
const twoTone = useMemo(() => allList.filter((item) => item.value.includes('TwoTone')), []);

const options = useMemo(() => {
switch (type) {
case '线框风格':
return outlined;
case '实底风格':
return filled;
default:
return twoTone;
}
}, [type]);
return (
<Select
placeholder="请选择图标"
allowClear
value={value}
open={open}
options={options}
onDropdownVisibleChange={(visible) => setOpen(visible)}
onClear={() => onChange('')}
dropdownRender={() => (
<div>
<Segmented options={['线框风格', '实底风格', '双色风格']} block value={type} onChange={setType}></Segmented>
<BoxWrapper>
{options.map((item) => {
return (
<IconItem
key={item.value}
onClick={() => {
onChange(item.value);
setOpen(false);
}}
>
{item.label}
</IconItem>
);
})}
</BoxWrapper>
</div>
)}
/>
);
}
100 changes: 44 additions & 56 deletions packages/editor/src/pages/admin/menu/CreateMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useImperativeHandle, useRef, useState } from 'react';
import { useImperativeHandle, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Modal, Form, TreeSelect, Input, Select, InputNumber, Radio, Spin } from 'antd';
import * as icons from '@ant-design/icons';
import { InfoCircleOutlined } from '@ant-design/icons';
import { message } from '@/utils/AntdGlobal';
import { IAction, IModalProp } from '@/pages/types';
@@ -10,6 +9,7 @@ import { getMenuList, addMenu, updateMenu, getPageList } from '@/api';
import { PageItem } from '@/api/pageMember';
import { arrayToTree } from '@/utils/util';
import CreatePage from '@/components/CreatePage';
import CustomIconOptions from '@/components/CustomIconList';

export default function CreateMenu(props: IModalProp<Menu.EditParams>) {
const [form] = Form.useForm();
@@ -32,9 +32,8 @@ export default function CreateMenu(props: IModalProp<Menu.EditParams>) {
setVisible(true);
setLoading(true);
// 获取菜单列表
const p1 = getMenus();
const p2 = getMyPageList();
await Promise.all([p1, p2]);
getMenus();
type === 'edit' && getMyPageList();
setLoading(false);
if (data && project_id) {
form.setFieldsValue({ ...data, project_id: parseInt(project_id), code: data.code?.split('_')[2] || '' });
@@ -89,8 +88,6 @@ export default function CreateMenu(props: IModalProp<Menu.EditParams>) {
setVisible(false);
form.resetFields();
};
// 获取所有的antd图标,动态渲染到下拉框中
const iconsList: { [key: string]: any } = icons;
return (
<>
<Modal
@@ -104,14 +101,14 @@ export default function CreateMenu(props: IModalProp<Menu.EditParams>) {
onCancel={handleCancel}
>
<Spin spinning={loading}>
<Form form={form} labelAlign="right" labelCol={{ span: 4 }} initialValues={{ type: 1, status: 1 }}>
<Form form={form} labelAlign="right" labelCol={{ span: 4 }} wrapperCol={{ span: 18 }} initialValues={{ type: 1, status: 1, is_create: 2 }}>
<Form.Item hidden name="id">
<Input />
</Form.Item>
<Form.Item hidden name="project_id">
<InputNumber />
</Form.Item>
<Form.Item label="上级菜单" name="parent_id">
<Form.Item label="父级菜单" name="parent_id">
<TreeSelect
placeholder="请选择父级菜单"
allowClear
@@ -149,68 +146,59 @@ export default function CreateMenu(props: IModalProp<Menu.EditParams>) {
{() => {
const type = form.getFieldValue('type');
return type === 2 ? (
<Form.Item label="权限标识" name="code" extra="同一个菜单下不要重名即可">
<Form.Item label="权限标识" name="code" extra="同一个菜单下按钮标识不要重复,请根据语义定义。">
<Input placeholder="权限标识,例如: create、edit、export" />
</Form.Item>
) : (
<>
{type === 1 ? (
<Form.Item label="菜单图标" name="icon">
<Select placeholder="请选择菜单图表" showSearch allowClear>
{Object.keys(icons)
.filter(
(item) => !['default', 'createFromIconfontCN', 'getTwoToneColor', 'setTwoToneColor', 'IconProvider'].includes(item),
)
.map((key) => {
return (
<Select.Option value={key} key={key}>
{React.createElement(iconsList[key], {
style: {
fontSize: '24px',
verticalAlign: 'middle',
},
})}
</Select.Option>
);
})}
</Select>
<CustomIconOptions />
</Form.Item>
) : null}
<Form.Item
label="关联页面"
tooltip="选择你创建的页面"
extra={
<span>
暂无页面?
<a
onClick={() => {
createRef.current?.open();
}}
>
去创建
</a>
</span>
}
name="page_id"
>
<Select
placeholder="请选择关联页面"
allowClear
showSearch
filterOption={(input, option) => (option?.name ?? '').toLowerCase().includes(input.toLowerCase())}
options={[...pageList, { name: '空页面', id: 0 }]}
fieldNames={{ label: 'name', value: 'id' }}
></Select>
</Form.Item>
{action === 'edit' ? (
<Form.Item
label="绑定页面"
extra={
<span>
该菜单可以解绑、修改、新增绑定页面。暂无页面?
<a
onClick={() => {
createRef.current?.open();
}}
>
去创建
</a>
</span>
}
name="page_id"
>
<Select
placeholder="请选择关联页面"
allowClear
showSearch
filterOption={(input, option) => (option?.name ?? '').toLowerCase().includes(input.toLowerCase())}
options={[...pageList, { name: '空页面', id: 0 }]}
fieldNames={{ label: 'name', value: 'id' }}
></Select>
</Form.Item>
) : (
<Form.Item label="生成页面" name="is_create" extra="如果你创建的是末级菜单,请给它生成一个页面,父菜单不需要生成。">
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={2}></Radio>
</Radio.Group>
</Form.Item>
)}
</>
);
}}
</Form.Item>

<Form.Item label="排序" name="sort_num" tooltip={{ title: '排序值越大越靠后', icon: <InfoCircleOutlined /> }}>
<Form.Item label="排序" name="sort_num" extra="排序值越大越靠后。">
<InputNumber placeholder="请输入排序值" />
</Form.Item>
<Form.Item label="菜单状态" name="status">
<Form.Item label="菜单状态" name="status" extra="停用后,菜单不会在admin系统中展示。">
<Radio.Group>
<Radio value={1}>启用</Radio>
<Radio value={2}>停用</Radio>
41 changes: 25 additions & 16 deletions packages/editor/src/pages/admin/menu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Form, Input, Button, Table, Space, Select } from 'antd';
import { Link, useParams } from 'react-router-dom';
import { Form, Input, Button, Table, Select, Badge } from 'antd';
import { Menu } from '@/api/types';
import { IAction } from '@/pages/types';
import { ColumnsType } from 'antd/es/table';
@@ -84,7 +84,7 @@ export default function MenuList() {
if (record.type == 3) text = '页面';
Modal.confirm({
title: '确认',
content: `确认删除该${text}?`,
content: `${text}删除后不可恢复,确认删除吗?`,
onOk() {
handleDelSubmit(record.id);
},
@@ -105,11 +105,13 @@ export default function MenuList() {
dataIndex: 'name',
key: 'name',
width: 200,
align: 'center',
},
{
title: '菜单图标',
dataIndex: 'icon',
key: 'icon',
align: 'center',
render(icon: string) {
if (!icon) return '-';
const iconsList: { [key: string]: any } = icons;
@@ -124,6 +126,7 @@ export default function MenuList() {
title: '菜单类型',
dataIndex: 'type',
key: 'type',
align: 'center',
render(type: number) {
return {
1: '菜单',
@@ -136,66 +139,71 @@ export default function MenuList() {
title: '权限标识',
dataIndex: 'code',
key: 'code',
align: 'center',
render(code: string) {
if (!code) return '-';
return code;
},
},
{
title: '关联页面',
title: '绑定页面',
dataIndex: 'page_id',
key: 'page_id',
align: 'center',
render(page_id: string) {
if (!page_id) return '-';
return page_id;
},
},
{
title: '排序值',
dataIndex: 'sort_num',
key: 'sort_num',
align: 'center',
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
render(status: number) {
return {
1: '正常',
2: '停用',
}[status];
if (status === 1) return <Badge status="success" text="正常" />;
if (status === 2) return <Badge status="error" text="停用" />;
},
},
{
title: '创建时间',
dataIndex: 'created_at',
key: 'created_at',
align: 'center',
},
{
title: '创建人',
dataIndex: 'user_name',
key: 'user_name',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 200,
width: 320,
align: 'center',
render(_, record) {
return (
<Space>
<Button type="text" onClick={() => handleCopy(record)}>
<>
<Button type="link" onClick={() => handleCopy(record)}>
复制
</Button>
<Button type="text" onClick={() => handleSubCreate(record)}>
<Button type="link" onClick={() => handleSubCreate(record)}>
新增
</Button>
<Button type="text" onClick={() => handleEdit(record)}>
<Button type="link" onClick={() => handleEdit(record)}>
编辑
</Button>
<Button type="text" danger onClick={() => handleDelete(record)}>
<Button type="link" danger onClick={() => handleDelete(record)}>
删除
</Button>
</Space>
{record.page_id > 0 && <Link to={`/editor/${record.page_id}/edit`}>去设计</Link>}
</>
);
},
},
@@ -225,6 +233,7 @@ export default function MenuList() {
</div>
<Table bordered rowKey="id" loading={loading} columns={columns} dataSource={data} pagination={false} />
</div>
{/* 新增菜单 */}
<CreateMenu mRef={menuRef} update={getMenus} />
</div>
);
10 changes: 8 additions & 2 deletions packages/editor/src/pages/admin/role/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Button, Table, Form, Input, Space } from 'antd';
import { Button, Table, Form, Input, Space, Tooltip } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { message, Modal } from '@/utils/AntdGlobal';
import SearchForm from '../components/SearchForm';
@@ -9,6 +9,7 @@ import SetPermission from './SetPermission';
import { getRoleList, delRoleById } from '@/api';
import { IAction } from '@/pages/types';
import { Role } from '@/api/types';
import { QuestionCircleOutlined } from '@ant-design/icons';
export default function RoleList() {
const [list, setList] = useState<Role.RoleItem[]>([]);
const [total, setTotal] = useState<number>(0);
@@ -141,7 +142,12 @@ export default function RoleList() {
</SearchForm>
<div className="base-table">
<div className="header-wrapper">
<div className="title">角色列表</div>
<Space>
<span>角色列表</span>
<Tooltip title="角色主要用来配置权限,一个用户对应一个角色,一个角色对应一批权限,从而实现菜单和按钮的显示控制。">
<QuestionCircleOutlined />
</Tooltip>
</Space>
<div className="action">
<Button type="primary" onClick={handleCreate}>
新增
10 changes: 8 additions & 2 deletions packages/editor/src/pages/admin/user/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useEffect, useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Form, Input, Button, Table, Space } from 'antd';
import { Form, Input, Button, Table, Space, Tooltip } from 'antd';
import { UserItem } from '@/api/types';
import { IAction } from '@/pages/types';
import { ColumnsType } from 'antd/es/table';
import { Modal, message } from '@/utils/AntdGlobal';
import CreateUser from './CreateUser';
import SearchForm from '../components/SearchForm';
import { getUserList, getRoleListAll, delUser } from '@/api';
import { QuestionCircleOutlined } from '@ant-design/icons';

/**
* 用户配置
@@ -151,7 +152,12 @@ export default function MenuList() {
</SearchForm>
<div className="base-table">
<div className="header-wrapper">
<div className="title">用户列表</div>
<Space>
<span>用户列表</span>
<Tooltip title="添加项目对应的用户,管理员默认具备该项目所有权限,普通用户可分配角色来精细化控制菜单和按钮。">
<QuestionCircleOutlined />
</Tooltip>
</Space>
<div className="action">
<Button type="primary" onClick={handleCreate}>
新增
4 changes: 2 additions & 2 deletions packages/editor/src/pages/editor/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { MouseEvent, useState, useEffect, useRef } from 'react';
import { useParams, useBlocker } from 'react-router-dom';
import { ConfigProvider, FloatButton, Image, Modal, Popover } from 'antd';
import { ConfigProvider, FloatButton, Image, Popover } from 'antd';
import { CommentOutlined, InfoCircleOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import { useDrop } from 'react-dnd';
import { useDebounceFn, useKeyPress } from 'ahooks';
@@ -11,7 +11,7 @@ import { createId, getElement } from '@/utils/util';
import storage from '@/utils/storage';
import { getPageDetail } from '@/api';
import Toolbar from '@/components/Toolbar/Toolbar';
import { message } from '@/utils/AntdGlobal';
import { message, Modal } from '@/utils/AntdGlobal';
import { usePageStore } from '@/stores/pageStore';
import { PageConfig } from '@/packages/Page';
import InfiniteViewer from 'react-infinite-viewer';
31 changes: 23 additions & 8 deletions packages/editor/src/pages/home/ProjectList.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { useEffect, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Col, Layout, Row, Pagination, Spin, Empty, Button, Form } from 'antd';
import { Card, Col, Layout, Row, Pagination, Spin, Empty, Button, Form, Tooltip } from 'antd';
import { UserOutlined, DeleteOutlined, LockOutlined, PlusOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import { getProjectList, delProject } from '@/api';
import { Project } from '@/api/types';
import { Modal, message } from '@/utils/AntdGlobal';
import SearchBar from '@/components/Searchbar/SearchBar';
import { ProjectCardItemProps } from '../types';
import CreateProject from '@/components/CreateProject';
import styles from './index.module.less';

/**
@@ -21,6 +22,7 @@ export default function Index() {
const [total, setTotal] = useState<number>(0);
const [current, setCurrent] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(12);
const createRef = useRef<{ open: () => void }>();
const navigate = useNavigate();

useEffect(() => {
@@ -68,14 +70,19 @@ export default function Index() {
setPageSize(size);
};

// 新建页面
const handleCreate = () => {
createRef.current?.open();
};

// 页面操作
const handleAction = async (id: number, isEdit: boolean) => {
if (!id) {
message.warning('该项目为私有项目');
return false;
}
if (!isEdit) {
message.warning('您不是该项目开发者,无权限操作');
message.warning('您不是该项目开发者,当前只有访问权限。');
return false;
}
navigate(`/project/${id}/config`);
@@ -90,10 +97,17 @@ export default function Index() {
// 项目卡片
const CardItem: React.FC<ProjectCardItemProps> = ({ item, isAuth }) => {
const getEnvTag = (env: 'stg' | 'pre' | 'prd', name: string) => {
const title = {
stg: '访问测试环境',
pre: '访问预发布环境',
prd: '访问生产环境',
}[env];
return (
<a href={`${import.meta.env.VITE_ADMIN_URL}/project/${env}/${item.id}`} target="_blank">
{name}
</a>
<Tooltip title={title}>
<a href={`${import.meta.env.VITE_ADMIN_URL}/project/${env}/${item.id}`} target="_blank">
{name}
</a>
</Tooltip>
);
};
return (
@@ -140,7 +154,7 @@ export default function Index() {
return (
<>
<Layout.Content className={styles.project}>
<SearchBar form={form} from="项目" submit={handleSearch} refresh={getList} onCreate={() => navigate('/project/0/config')} />
<SearchBar form={form} from="项目" submit={handleSearch} refresh={getList} onCreate={handleCreate} />
{total > 0 || loading ? (
<>
<div className={styles.projectList}>
@@ -170,13 +184,14 @@ export default function Index() {
) : (
!loading && (
<Empty style={{ marginTop: 100 }}>
<Button type="dashed" icon={<PlusOutlined />} onClick={() => navigate('/project/0/config')}>
<Button type="dashed" icon={<PlusOutlined />} onClick={handleCreate}>
新建项目
</Button>
</Empty>
)
)}
</Layout.Content>
<CreateProject ref={createRef} update={() => getList(1, pageSize)} />
</>
);
}

0 comments on commit d97fb2a

Please sign in to comment.