我正在参加「豆包MarsCode初体验」征文活动,活动链接:,豆包MarsCode体验官-{玩转AI}开启智能编程之旅,拿手机大奖 - 掘金 (juejin.cn)
光阴如梭,岁月如歌,哈哈,经典的作文开头哈,先讲起因,,18天前的某一天 在地铁上刷手机的时候看到字节跳动发布的新的编程工具MarsCode:6 月 26 日,字节跳动在北京发布了基于豆包大模型打造的智能开发工具 - 豆包MarsCode ,面向国内开发者免费开放。当时看到我就在想
当时我就在想不会是和其他的AI 工具一样吧,然后直接直接把豆包AI 应用在编程领域,直到我认真细细体验了下更改,这一体验,就不得了,国产的AI真是越来越牛批了,首先先看官网介绍:
豆包MarsCode(www.MarsCode.cn/home) 是基于字节跳动豆包大模型打造的更智能、更便捷的开发工具,提供 Cloud IDE 及 AI 编程助手两种使用形态。
作为豆包代码模型的具体应用, 豆包MarsCode 支持智能识别当前编码任务相关的上下文信息,同时将代码理解、生成、优化、推荐、补全、审查等多维能力融为一体,无缝嵌入研发流程的各个环节,帮助开发者提升代码开发质量和效率。
豆包 MarsCode 是一个集成了AI功能的编程助手和云端IDE,旨在提高开发效率和质量。它支持多种编程语言和IDE,提供智能代码补全、代码解释、单元测试生成和问题修复等功能,同时具备AI对话视图和开发工具。
一句话解释下,也就是说这是字节专门在编程领域的的大模型应用,豆包:你可以理解为通用的,而看MarsCode,这个关键词名,就知道, MarsCode 是一个很吊编程工具
我们先来看下官网:
一打开网页直接就是一个渐变字体,字体动画从下往上,表示 MarsCode要天天向上的精神,将来会越来越好
小技巧
快速插入
比如你问了MarsCode一个问题,这时候,你想要立刻看到效果,你可以点击这个图标,就会立刻将生成的代码,嵌入到你的编辑文件当中
如果你连文件都没创建的话,你就可以点击这个,MarsCode他就会为你创建一个新的文件,甚至贴心的为你连文件的类型都选择好了
先试试Python
- Python
在试试Java,不愧是大厂的工具,这种小细节都处理的很好
- Java
对话代码
我们在 MarsCode选择代码,你懂吧,就是那种右滑的选中,就会出现一个选项,每个选项都表示一个功能
我们点击第一个,对话代码,顾名思义就是把这段代码去请教AI,你可以把MarsCode 当成一个老师,你问他,为什么这么说呢,你甚至可以问它你多大了 ?你结婚没有?
哈哈,18岁就这么吊
如果你不满意,你还可以点击重试的图标
所以不愧是编程助手,这样才不会影响我们,心中无AI,编码自然神!
我们再来看第二个,解释代码
这个和上一个功能的区别就是,你如果有什么不懂的代码,就不用请教学长,或者同事,直接点击解释下,他就会给你解释
左侧就会出现解释对话框,嘎嘎详细
我们再来看下第三个功能,第三个功能嘎嘎吊,有个场景,你是一家新入职的员工,你接手了公司的新代码,但是这些代码,都没有写注释,老板跟你说,现在项目重购了,后面招聘新人你来培训,你最好给公司代码都加上注释,方便后人理解,这时候用到我们MarsCode,点击注释,这里的注释可不是说真的给你注释代码,哪有这么鸡肋
- 点击MarsCode注释后
-
完整效果
-
点击接受,就表示,我们要使用这次生成的注释
- 接受后
对话的最后一个小点就是单元测试, 这个单元测试含义就是,我们可以为代码,直接生成测试类,想象一个场景: 你们公司的代码之前没有写单测的习惯,在一个阳光明媚的下午,你的leader跟你说,小赵,公司的代码覆盖率有点低,你把代码写下单测,于是你看着几万个类陷入了沉思,**MarsCode 走来了! **
突然你的救星出现了
我们只需要点击单元测试
点击单元测试后, 一次性为你生成了两种单侧,我相信,Java程序员就秒懂了,知道我们两种用的比较多居然两种的生成了,好小子
-
main 函数方法
-
Test 单测方法
拆分代码编辑器
点这个小图标可以进行拆分代码编辑器 ,想象下,你写Vue,一边写template部分,一边写css,、一边写组件
快捷键大全
实战开发 学生管理
这节我们使用 Marscode 来完成开发一个学生管理系统功能案例
- 技术栈使用的是 经典的React 18+ typescirpt +Axios
最终效果参考下图 :
通过脚手架快速创建项目
yarn create react-app student-info-platform --template typescript
安装所需要的依赖
npm install antd axios react-router-dom @types/react-router-dom
创建以下文件和文件夹结构:
src/
|-- api/
| |-- studentApi.ts
|-- components/
| |-- StudentList.tsx
|-- pages/
| |-- Home.tsx
| |-- StudentPage.tsx
|-- App.tsx
|-- index.tsx
完整package.json如下
{
"name": "student-info-platform",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"antd": "^5.18.0",
"http-proxy-middleware": "^3.0.0",
"moment": "^2.30.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
在 src/api/studentApi.ts 中定义 API 请求:
import axios from 'axios';
const API_URL = 'http://localhost:8080';
export const getStudents = () => axios.get(`${API_URL}/students`);
export const getStudent = (id: number) => axios.get(`${API_URL}/students/${id}`);
export const createStudent = (student: any) => axios.post(`${API_URL}/students`, student);
export const updateStudent = (id: number, student: any) => axios.put(`${API_URL}/students/${id}`, student);
export const deleteStudent = (id: number) => axios.delete(`${API_URL}/students/${id}`);
当然你也可以用这种方式,取决于个人爱好,这是定义我们后端的接口
import axios from 'axios';
const instance = axios.create({
baseURL: 'http://localhost:8080'
});
export default instance;
- 编写组件
在 src/components/StudentList.tsx 中创建表单组件:
import React, { useEffect, useState } from 'react';
import { Table, Input, Button, Pagination, Modal, Form, message, Upload } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import moment from 'moment';
import { Student, PaginatedResponse } from '../types';
import axios from '../instance/axios_instance';
import { UploadOutlined, DownloadOutlined, DeleteOutlined } from '@ant-design/icons';
const StudentList: React.FC = () => {
const [students, setStudents] = useState<Student[]>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [loading, setLoading] = useState(false);
const [name, setName] = useState('');
const [classQuery, setClassQuery] = useState('');
const [isModalVisible, setIsModalVisible] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [selectedStudent, setSelectedStudent] = useState<Student | null>(null);
const [form] = Form.useForm();
const [photoUrl, setPhotoUrl] = useState<string | null>(null);
useEffect(() => {
fetchStudents();
}, [page, pageSize, name, classQuery]);
const fetchStudents = async () => {
setLoading(true);
try {
const response = await axios.get<PaginatedResponse>('/students', {
params: {
page,
page_size: pageSize,
name,
class: classQuery,
},
});
setStudents(response.data.data.students);
setTotal(response.data.data.totalItems);
} catch (error) {
message.error('Failed to fetch students');
}
setLoading(false);
};
const handleSearch = () => {
setPage(1);
fetchStudents();
};
const handleAdd = () => {
setIsEditMode(false);
setSelectedStudent(null);
form.resetFields();
setPhotoUrl(null);
setIsModalVisible(true);
};
const handleEdit = (student: Student) => {
console.log('student',student)
setIsEditMode(true);
setSelectedStudent(student);
form.setFieldsValue(student);
setPhotoUrl(student.photoUrl || null);
setIsModalVisible(true);
};
const handleDelete = async (id: number) => {
try {
await axios.delete(`/students/${id}`);
message.success('Student deleted successfully');
fetchStudents();
} catch (error) {
message.error('Failed to delete student');
}
};
const handleBatchDelete = async () => {
Modal.confirm({
title: '确认删除',
content: '确定要删除选中的学生吗?',
onOk: async () => {
try {
await axios.post('/students/batch', { ids: selectedRowKeys });
message.success('Students deleted successfully');
fetchStudents();
setSelectedRowKeys([]);
} catch (error) {
message.error('Failed to delete students');
}
},
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
if (values.age) {
values.age = Number(values.age);
}
const studentData = { ...values, photo_url: photoUrl };
console.log('studentData',studentData)
if (isEditMode && selectedStudent) {
await axios.put(`/students/${selectedStudent.id}`, studentData);
message.success('Student updated successfully');
} else {
await axios.post('/students', studentData);
message.success('Student added successfully');
}
fetchStudents();
setIsModalVisible(false);
} catch (error) {
message.error('Failed to save student');
}
};
const handleCancel = () => {
setIsModalVisible(false);
};
const handleExport = async () => {
try {
const response = await axios.get('/export', { responseType: 'blob' });
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'students.csv');
document.body.appendChild(link);
link.click();
link.remove();
message.success('CSV file downloaded successfully');
} catch (error) {
message.error('Failed to export students');
}
};
const handleUpload = async ({ file }: { file: any }) => {
const formData = new FormData();
formData.append('file', file);
try {
await axios.post('/import', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
message.success('Students imported successfully');
fetchStudents();
} catch (error) {
message.error('Failed to import students');
}
};
const handlePhotoUpload = async (info: any) => {
const formData = new FormData();
formData.append('photo', info.file);
try {
const response = await axios.post('/upload_photo', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
setPhotoUrl(response.data);
message.success('Photo uploaded successfully');
} catch (error) {
message.error('Failed to upload photo');
}
};
const columns: ColumnsType<Student> = [
{
title: '学号',
dataIndex: 'id',
key: 'id',
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '班级',
dataIndex: 'class',
key: 'class',
},
{
title: '照片',
dataIndex: 'photoUrl',
key: 'photoUrl',
render: (text) => <img src={text} alt="Student" style={{ width: 50, height: 50 }} />,
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
},
{
title: '更新时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
},
{
title: '操作',
key: 'actions',
render: (text, record) => (
<>
<Button onClick={() => handleEdit(record)} type="link">
编辑
</Button>
<Button onClick={() => handleDelete(record.id)} type="link" danger>
删除
</Button>
</>
),
},
];
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[]) => {
setSelectedRowKeys(selectedRowKeys as number[]);
},
};
return (
<div>
<h1 style={{ fontSize: '24px' }}>学生信息查询平台</h1>
<Input.Group compact style={{ marginBottom: 16 }}>
<Input
placeholder="按姓名搜索"
value={name}
onChange={(e) => setName(e.target.value)}
style={{ width: '40%' }}
/>
<Input
placeholder="按班级搜索"
value={classQuery}
onChange={(e) => setClassQuery(e.target.value)}
style={{ width: '40%' }}
/>
<Button type="primary" onClick={handleSearch}>
搜索
</Button>
</Input.Group>
<Button type="primary" onClick={handleAdd} style={{ marginBottom: 16, marginRight: 8 }}>
添加学生
</Button>
<Button
type="primary"
onClick={handleBatchDelete}
icon={<DeleteOutlined />}
disabled={selectedRowKeys.length === 0}
style={{ marginBottom: 16, marginRight: 8 }}
>
批量删除
</Button>
<Button type="primary" onClick={handleExport} icon={<DownloadOutlined />} style={{ marginBottom: 16, marginRight: 8 }}>
导出学生
</Button>
<Upload
accept=".csv"
showUploadList={false}
customRequest={handleUpload}
>
<Button icon={<UploadOutlined />}>选择 CSV 文件导入学生</Button>
</Upload>
<Table
columns={columns}
dataSource={students}
rowKey="id"
pagination={false}
loading={loading}
rowSelection={rowSelection}
/>
<Pagination
current={page}
pageSize={pageSize}
total={total}
onChange={(page, pageSize) => {
setPage(page);
setPageSize(pageSize);
}}
showSizeChanger
style={{ marginTop: 16 }}
/>
<Modal
title={isEditMode ? '编辑学生信息' : '添加学生信息'}
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<Form form={form} layout="vertical">
<Form.Item
name="name"
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input />
</Form.Item>
<Form.Item
name="age"
label="年龄"
rules={[{ required: true, message: '请输入年龄' }]}
>
<Input type="number" />
</Form.Item>
<Form.Item
name="class"
label="班级"
rules={[{ required: true, message: '请输入班级' }]}
>
<Input />
</Form.Item>
<Form.Item
name="photo"
label="照片"
rules={[{ required: false }]}
>
<Upload
listType="picture"
maxCount={1}
customRequest={handlePhotoUpload}
>
<Button icon={<UploadOutlined />}>上传照片</Button>
</Upload>
{photoUrl && <img src={photoUrl} alt="Student" style={{ width: 100, marginTop: 10 }} />}
</Form.Item>
</Form>
</Modal>
</div>
);
};
export default StudentList;
在这里我们定义后端接口的类型
types/index.ts
export interface Student {
id: number;
createdAt: string;
updatedAt: string;
name: string;
photoUrl: string;
age: number;
class: string;
}
export interface PaginatedResponse {
code: number;
message: string;
data: {
currentPage: number;
hasNextPage: boolean;
pageSize: number;
students: Student[];
totalItems: number;
totalPages: number;
};
}
Home.tsx页面 就是将组件导入在这里显示
import React from 'react';
import StudentList from '../components/StudentList';
const Home: React.FC = () => {
return (
<div>
<h1>学生列表</h1>
<StudentList />
</div>
);
};
export default Home;
在 src/pages/StudentPage.tsx 中创建学生页面组件:
import React from 'react';
import { useParams } from 'react-router-dom';
import StudentDetail from '../components/StudentDetail';
import StudentForm from '../components/StudentForm';
const StudentPage: React.FC = () => {
const { id } = useParams<{ id: string }>();
const isEditing = Boolean(id);
return (
<div>
<h1>{isEditing ? '编辑学生' : '添加学生'}</h1>
{isEditing ? <StudentDetail /> : <StudentForm onSuccess={() => {}} />}
</div>
);
};
export default StudentPage;
在 src/App.tsx 中设置路由:
import React, { useState } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import { SettingOutlined } from '@ant-design/icons';
import type { MenuProps, MenuTheme } from 'antd';
import { Menu, Switch, Layout } from 'antd';
import StudentList from './components/StudentList';
const { Header, Sider, Content } = Layout;
type MenuItem = Required<MenuProps>['items'][number];
const items: MenuItem[] = [
{
key: 'student-management',
label: '学生信息管理',
icon: <SettingOutlined />,
},
];
// 占位符组件
const Placeholder: React.FC = () => (
<div>请选择一个菜单项</div>
);
const App: React.FC = () => {
const [theme, setTheme] = useState<MenuTheme>('light');
const [current, setCurrent] = useState('student-management');
const [selectedComponent, setSelectedComponent] = useState<JSX.Element>(<StudentList />);
const changeTheme = (value: boolean) => {
setTheme(value ? 'dark' : 'light');
};
const onClick: MenuProps['onClick'] = (e) => {
setCurrent(e.key);
if (e.key === 'student-management') {
setSelectedComponent(<StudentList />);
} else {
setSelectedComponent(<Placeholder />); // 根据需求加载不同的组件
}
};
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider theme={theme} style={{ width: 256 }}>
<div style={{ padding: 16, textAlign: 'center', color: '#fff', fontSize: 16 }}>
菜单主题切换
</div>
<Switch
checked={theme === 'dark'}
onChange={changeTheme}
checkedChildren="Dark"
unCheckedChildren="Light"
style={{ margin: '16px' }}
/>
<Menu
theme={theme}
onClick={onClick}
defaultOpenKeys={['student-management']}
selectedKeys={[current]}
mode="inline"
items={items}
/>
</Sider>
<Layout>
<Header style={{ background: theme === 'dark' ? '#001529' : '#fff', padding: 0, textAlign: 'center', color: theme === 'dark' ? '#fff' : '#000', fontSize: 24 }}>
学生管理系统
</Header>
<Content style={{ margin: '16px', padding: 24, background: theme === 'dark' ? '#141414' : '#fff', minHeight: 280 }}>
{selectedComponent}
</Content>
</Layout>
</Layout>
);
};
const RootApp: React.FC = () => {
return (
<Router>
<App />
</Router>
);
};
export default RootApp;
直接yarn start 梭哈
完整显示
- 最终效果
查询
编辑
更换皮肤
删除
拆分细化组件
接下来我们使用Marscode,进行组件拆分下,让我们的项目更加完善,并且更加符合企业级项目
大家可以这样进行提问: 请将React 代码拆分为若干个组件,要求每个组件携带注释,并且功能完善最终输出每个组件内容,在输出完整代码 输入这个秘密武器后,你就会得到下方代码 , 将这个组件拆分为更小的、职责单一的组件,能够提高代码的可读性和可维护性。我们可以将它分为以下几个组件:
-
StudentTable: 表格组件,负责显示学生信息。 -
StudentFormModal: 表单弹窗组件,负责添加和编辑学生信息。 -
StudentSearch: 搜索组件,负责过滤学生信息。 -
StudentActions: 操作组件,负责添加、批量删除、导出和导入学生信息。
- 拆分后代码结构
src/
|-- components/
| |-- StudentTable.tsx
| |-- StudentFormModal.tsx
| |-- StudentSearch.tsx
| |-- StudentActions.tsx
|-- pages/
| |-- StudentList.tsx
StudentTable.tsx
import React from 'react';
import { Table, Button } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import moment from 'moment';
import { Student } from '../types';
interface StudentTableProps {
students: Student[];
loading: boolean;
selectedRowKeys: number[];
setSelectedRowKeys: (keys: number[]) => void;
onEdit: (student: Student) => void;
onDelete: (id: number) => void;
}
const StudentTable: React.FC<StudentTableProps> = ({ students, loading, selectedRowKeys, setSelectedRowKeys, onEdit, onDelete }) => {
const columns: ColumnsType<Student> = [
{
title: '学号',
dataIndex: 'id',
key: 'id',
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '班级',
dataIndex: 'class',
key: 'class',
},
{
title: '照片',
dataIndex: 'photoUrl',
key: 'photoUrl',
render: (text) => <img src={text} alt="Student" style={{ width: 50, height: 50 }} />,
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
},
{
title: '更新时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
render: (text) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
},
{
title: '操作',
key: 'actions',
render: (text, record) => (
<>
<Button onClick={() => onEdit(record)} type="link">
编辑
</Button>
<Button onClick={() => onDelete(record.id)} type="link" danger>
删除
</Button>
</>
),
},
];
const rowSelection = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[]) => {
setSelectedRowKeys(selectedRowKeys as number[]);
},
};
return (
<Table
columns={columns}
dataSource={students}
rowKey="id"
pagination={false}
loading={loading}
rowSelection={rowSelection}
/>
);
};
export default StudentTable;
StudentFormModal.tsx
import React from 'react';
import { Modal, Form, Input, Button, Upload, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
interface StudentFormModalProps {
visible: boolean;
isEditMode: boolean;
selectedStudent: any;
photoUrl: string | null;
setPhotoUrl: (url: string | null) => void;
onCancel: () => void;
onOk: (values: any) => void;
}
const StudentFormModal: React.FC<StudentFormModalProps> = ({ visible, isEditMode, selectedStudent, photoUrl, setPhotoUrl, onCancel, onOk }) => {
const [form] = Form.useForm();
const handlePhotoUpload = async (info: any) => {
const formData = new FormData();
formData.append('photo', info.file);
try {
const response = await axios.post('/upload_photo', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
setPhotoUrl(response.data);
message.success('Photo uploaded successfully');
} catch (error) {
message.error('Failed to upload photo');
}
};
return (
<Modal
title={isEditMode ? '编辑学生信息' : '添加学生信息'}
visible={visible}
onOk={async () => {
try {
const values = await form.validateFields();
if (values.age) {
values.age = Number(values.age);
}
const studentData = { ...values, photo_url: photoUrl };
onOk(studentData);
} catch (error) {
message.error('Failed to save student');
}
}}
onCancel={onCancel}
>
<Form form={form} layout="vertical" initialValues={selectedStudent}>
<Form.Item
name="name"
label="姓名"
rules={[{ required: true, message: '请输入姓名' }]}
>
<Input />
</Form.Item>
<Form.Item
name="age"
label="年龄"
rules={[{ required: true, message: '请输入年龄' }]}
>
<Input type="number" />
</Form.Item>
<Form.Item
name="class"
label="班级"
rules={[{ required: true, message: '请输入班级' }]}
>
<Input />
</Form.Item>
<Form.Item
name="photo"
label="照片"
>
<Upload
listType="picture"
maxCount={1}
customRequest={handlePhotoUpload}
>
<Button icon={<UploadOutlined />}>上传照片</Button>
</Upload>
{photoUrl && <img src={photoUrl} alt="Student" style={{ width: 100, marginTop: 10 }} />}
</Form.Item>
</Form>
</Modal>
);
};
export default StudentFormModal;
StudentSearch.tsx
import React from 'react';
import { Input, Button } from 'antd';
interface StudentSearchProps {
name: string;
setName: (name: string) => void;
classQuery: string;
setClassQuery: (classQuery: string) => void;
onSearch: () => void;
}
const StudentSearch: React.FC<StudentSearchProps> = ({ name, setName, classQuery, setClassQuery, onSearch }) => {
return (
<Input.Group compact style={{ marginBottom: 16 }}>
<Input
placeholder="按姓名搜索"
value={name}
onChange={(e) => setName(e.target.value)}
style={{ width: '40%' }}
/>
<Input
placeholder="按班级搜索"
value={classQuery}
onChange={(e) => setClassQuery(e.target.value)}
style={{ width: '40%' }}
/>
<Button type="primary" onClick={onSearch}>
搜索
</Button>
</Input.Group>
);
};
export default StudentSearch;
StudentActions.tsx
import React from 'react';
import { Button, Upload, message } from 'antd';
import { UploadOutlined, DownloadOutlined, DeleteOutlined } from '@ant-design/icons';
interface StudentActionsProps {
selectedRowKeys: number[];
onAdd: () => void;
onBatchDelete: () => void;
onExport: () => void;
onUpload: ({ file }: { file: any }) => void;
}
const StudentActions: React.FC<StudentActionsProps> = ({ selectedRowKeys, onAdd, onBatchDelete, onExport, onUpload }) => {
return (
<>
<Button type="primary" onClick={onAdd} style={{ marginBottom: 16, marginRight: 8 }}>
添加学生
</Button>
<Button
type="primary"
onClick={onBatchDelete}
icon={<DeleteOutlined />}
disabled={selectedRowKeys.length === 0}
style={{ marginBottom: 16, marginRight: 8 }}
>
批量删除
</Button>
<Button type="primary" onClick={onExport} icon={<DownloadOutlined />} style={{ marginBottom: 16, marginRight: 8 }}>
导出学生
</Button>
<Upload
accept=".csv"
showUploadList={false}
customRequest={onUpload}
>
<Button icon={<UploadOutlined />}>选择 CSV 文件导入学生</Button>
</Upload>
</>
);
};
export default StudentActions;
完整页面组件 StudentList.tsx
import React, { useEffect, useState } from 'react';
import { Pagination, message } from 'antd';
import axios from '../instance/axios_instance';
import { Student, PaginatedResponse } from '../types';
import StudentTable from '../components/StudentTable';
import
StudentFormModal from '../components/StudentFormModal';
import StudentSearch from '../components/StudentSearch';
import StudentActions from '../components/StudentActions';
const StudentList: React.FC = () => {
const [students, setStudents] = useState<Student[]>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [loading, setLoading] = useState(false);
const [name, setName] = useState('');
const [classQuery, setClassQuery] = useState('');
const [isModalVisible, setIsModalVisible] = useState(false);
const [isEditMode, setIsEditMode] = useState(false);
const [selectedStudent, setSelectedStudent] = useState<Student | null>(null);
const [photoUrl, setPhotoUrl] = useState<string | null>(null);
useEffect(() => {
fetchStudents();
}, [page, pageSize, name, classQuery]);
const fetchStudents = async () => {
setLoading(true);
try {
const response = await axios.get<PaginatedResponse>('/students', {
params: {
page,
page_size: pageSize,
name,
class: classQuery,
},
});
setStudents(response.data.data.students);
setTotal(response.data.data.totalItems);
} catch (error) {
message.error('Failed to fetch students');
}
setLoading(false);
};
const handleSearch = () => {
setPage(1);
fetchStudents();
};
const handleAdd = () => {
setIsEditMode(false);
setSelectedStudent(null);
setPhotoUrl(null);
setIsModalVisible(true);
};
const handleEdit = (student: Student) => {
setIsEditMode(true);
setSelectedStudent(student);
setPhotoUrl(student.photoUrl || null);
setIsModalVisible(true);
};
const handleDelete = async (id: number) => {
try {
await axios.delete(`/students/${id}`);
message.success('Student deleted successfully');
fetchStudents();
} catch (error) {
message.error('Failed to delete student');
}
};
const handleBatchDelete = async () => {
Modal.confirm({
title: '确认删除',
content: '确定要删除选中的学生吗?',
onOk: async () => {
try {
await axios.post('/students/batch', { ids: selectedRowKeys });
message.success('Students deleted successfully');
fetchStudents();
setSelectedRowKeys([]);
} catch (error) {
message.error('Failed to delete students');
}
},
});
};
const handleOk = async (studentData: any) => {
try {
if (isEditMode && selectedStudent) {
await axios.put(`/students/${selectedStudent.id}`, studentData);
message.success('Student updated successfully');
} else {
await axios.post('/students', studentData);
message.success('Student added successfully');
}
fetchStudents();
setIsModalVisible(false);
} catch (error) {
message.error('Failed to save student');
}
};
const handleCancel = () => {
setIsModalVisible(false);
};
const handleExport = async () => {
try {
const response = await axios.get('/export', { responseType: 'blob' });
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'students.csv');
document.body.appendChild(link);
link.click();
link.remove();
message.success('CSV file downloaded successfully');
} catch (error) {
message.error('Failed to export students');
}
};
const handleUpload = async ({ file }: { file: any }) => {
const formData = new FormData();
formData.append('file', file);
try {
await axios.post('/import', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
message.success('Students imported successfully');
fetchStudents();
} catch (error) {
message.error('Failed to import students');
}
};
return (
<div>
<h1 style={{ fontSize: '24px' }}>学生信息查询平台</h1>
<StudentSearch name={name} setName={setName} classQuery={classQuery} setClassQuery={setClassQuery} onSearch={handleSearch} />
<StudentActions
selectedRowKeys={selectedRowKeys}
onAdd={handleAdd}
onBatchDelete={handleBatchDelete}
onExport={handleExport}
onUpload={handleUpload}
/>
<StudentTable
students={students}
loading={loading}
selectedRowKeys={selectedRowKeys}
setSelectedRowKeys={setSelectedRowKeys}
onEdit={handleEdit}
onDelete={handleDelete}
/>
<Pagination
current={page}
pageSize={pageSize}
total={total}
onChange={(page, pageSize) => {
setPage(page);
setPageSize(pageSize);
}}
showSizeChanger
style={{ marginTop: 16 }}
/>
<StudentFormModal
visible={isModalVisible}
isEditMode={isEditMode}
selectedStudent={selectedStudent}
photoUrl={photoUrl}
setPhotoUrl={setPhotoUrl}
onCancel={handleCancel}
onOk={handleOk}
/>
</div>
);
};
export default StudentList;
看下效果~
当然你还可以使用Marscode,进行再次优化~ 真的很强
对比友商
我们来对比下隔壁友商 某 C*DN
提出经典编程问题, 两数之和 ,要求使用Python和Java 同时输出,并进行对比两数之和的效率,计算耗时
- MarsCode
import time
def two_sum(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]
# 测试数据
nums = [2, 7, 11, 15]
target = 9
# 记录开始时间
start_time = time.time()
# 调用两数之和函数
result = two_sum(nums, target)
# 记录结束时间
end_time = time.time()
# 计算运行时间
running_time = end_time - start_time
# 输出结果
print("两数之和的结果是:", result)
print("运行时间是:", running_time, "秒")
- java
public class TwoSum {
public static int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int target = 9;
// 记录开始时间
long start_time = System.nanoTime();
// 调用两数之和函数
int[] result = twoSum(nums, target);
// 记录结束时间
long end_time = System.nanoTime();
// 计算运行时间
long running_time = end_time - start_time;
// 输出结果
System.out.println("两数之和的结果是:" + java.util.Arrays.toString(result));
System.out.println("运行时间是:" + running_time + "纳秒");
}
}
可以看到不仅仅是输出了,并且还贴心的加上了注释,,代码也非常规范,我们再来看下某C的表现
- 某平台AI
import java.util.HashMap;
public class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No solution found");
}
}
def two_sum(nums, target):
num_map = {}
for i, num in enumerate(nums):
complement = target - num
if complement in num_map:
return [num_map[complement], i]
num_map[num] = i
raise ValueError("No solution found")
好好好,某C 你小子,注释不给我就给算了,居然连耗时也给我删除了,不按套路出牌,今天能删示例代码注释,明天就能删业务代码注释,这样我们广大掘友怎么能放心的CV
DEBUG 神器
DEBUG 最强的神器可以说是整个MarsCode 除AI外 最强、也最难开发的功能了,没有之一, 支持各种语言Debug ,目前光本人测试过的就有7种,下面给大家以Python为例,给大家演示一遍
和jetbrains一样的,我们点击 左侧行,记住是单击、不是双击,双击会取消的,
点击左侧的小虫子,Bug的小虫子,点击后,也是单击
点击后关注右侧红色框框的区域
紧接着我们访问这个Web 服务链接,这个这个项目就是一个Python的Web 服务,我们点击这个Url 即可进入断点,下方是进入断点的详情图
这里可以看到每个断点的变量的参数信息,
我们点击快捷键F10,也可以直接点击这个向下的勾勾箭头,进入下一步,
如果你想进入下一个断点可以输入快捷键F5,我们可以看到第一个断点在14行、第二个断点在18行,当你点击第一个图标就会进入下一个断点
如果你想一步一步调试则点击第3个图标,
如果进入了某个函数内部,你想要跳出来,你就点击第4个图标
重新开始和关闭的话,就点击第5、6个吧
如果是想要随时看到代码效果,不想去其他窗口就去点击这个小眼睛,嘎嘎清洗
- 调试配置
大家还记得我们在VsCode中有一个 json文件叫
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python 调试一", // 可自定义
"type": "debugpy",
"request": "launch",
"program": "运行脚本的程序", // 使用.py 脚本路径(相对路径)、which torchrun、which deepspeed等命令查看位置
"console": "integratedTerminal",
"justMyCode": false, // 调试允许进入他人的代码
"env": {
"PYTHONPATH": "${workspaceRoot}" // 设置vscode家路径为项目根路径, 搜索包时优先从该目录进行,防止发生import包错误
},
"args": [ // 参数,每个参数的参数值无论是否是数字都需用引号
"--参数1","值1",
"--model_name_or_path","facebook/opt-350m",
"--per_device_train_batch_size", "4",
"--per_device_eval_batch_size", "4"
]
}
]
}
命令行 python 进行执行脚本,构建launch.json 思路
- bash 为python执行脚本.py,直接修改"program"为 .py脚本相对路径
- 其他参数照抄
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python 调试",
"type": "debugpy",
"request": "launch",
"program": "self_instruct/bootstrap_instructions.py", // .py脚本文件相对路径位置
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceRoot}" // 设置vscode项目根路径,搜索包时优先从该目录进行,防止发生import包错误
},
"args": [
"--batch_dir","data/gpt3_generations_ceshi",// TODO 修改官方线上数据集为自己的路径
"--num_instructions_to_generate","5"
]
}
]
}
安装插件
没有插件就没有灵魂,marscode,提供了很多插件,如: Vue、 React、Html、css
是不是看着就很吊,妈妈再也不用担心我没有插件了,光Vue的插件就有1000多个、React 也是几千个
结语
在我们深入探讨了「豆包Marscode」这一创新的云端IDE后,不禁为科技的飞速进步和人工智能在编程领域的深远影响感到惊叹。从最初的代码编辑器到如今高度智能化的编程工具,技术的每一步革新都在重新定义编程的未来。
「豆包Marscode」集成了众多功能,涵盖了从代码调试、解释到优化等各个方面,堪称国产最强AI工具。它不仅提升了开发效率,还简化了编程过程,使得编程不再局限于少数专业人员。通过AI技术,程序员们能够更加专注于创新和创造,而不必为繁琐的细节所困扰。
我们希望在不久的将来,「豆包Marscode」能够成为各个培训机构的首选工具,让更多人有机会体验到这一国产AI IDE的强大功能。愿各个国家的程序员都能感受到「豆包Marscode」带来的便捷和高效,共同推动编程技术的不断进步。
光阴如梭,岁月如歌。在技术不断演进的时代,我们期待着「豆包Marscode」不断突破,续写更辉煌的篇章。让我们共同见证科技如何改变编程的未来,携手迈向更加智能、高效的开发新时代。