「豆包Marscode体验官」:云端IDE的进化,Marscode实战开发学生管理系统

6,755 阅读14分钟

我正在参加「豆包MarsCode初体验」征文活动,活动链接:,豆包MarsCode体验官-{玩转AI}开启智能编程之旅,拿手机大奖 - 掘金 (juejin.cn)

image.png

光阴如梭,岁月如歌,哈哈,经典的作文开头哈,先讲起因,,18天前的某一天 在地铁上刷手机的时候看到字节跳动发布的新的编程工具MarsCode:6 月 26 日,字节跳动在北京发布了基于豆包大模型打造的智能开发工具 - 豆包MarsCode ,面向国内开发者免费开放。当时看到我就在想

image.png

image.png

当时我就在想不会是和其他的AI 工具一样吧,然后直接直接把豆包AI 应用在编程领域,直到我认真细细体验了下更改,这一体验,就不得了,国产的AI真是越来越牛批了,首先先看官网介绍:

豆包MarsCode(www.MarsCode.cn/home) 是基于字节跳动豆包大模型打造的更智能、更便捷的开发工具,提供 Cloud IDE 及 AI 编程助手两种使用形态。

作为豆包代码模型的具体应用, 豆包MarsCode 支持智能识别当前编码任务相关的上下文信息,同时将代码理解、生成、优化、推荐、补全、审查等多维能力融为一体,无缝嵌入研发流程的各个环节,帮助开发者提升代码开发质量和效率。

豆包 MarsCode 是一个集成了AI功能的编程助手和云端IDE,旨在提高开发效率和质量。它支持多种编程语言和IDE,提供智能代码补全、代码解释、单元测试生成和问题修复等功能,同时具备AI对话视图和开发工具。

一句话解释下,也就是说这是字节专门在编程领域的的大模型应用,豆包:你可以理解为通用的,而看MarsCode,这个关键词名,就知道, MarsCode 是一个很吊编程工具

我们先来看下官网:

1.gif

一打开网页直接就是一个渐变字体,字体动画从下往上,表示 MarsCode要天天向上的精神,将来会越来越好

小技巧

快速插入

比如你问了MarsCode一个问题,这时候,你想要立刻看到效果,你可以点击这个图标,就会立刻将生成的代码,嵌入到你的编辑文件当中

image.png

如果你连文件都没创建的话,你就可以点击这个,MarsCode他就会为你创建一个新的文件,甚至贴心的为你连文件的类型都选择好了

先试试Python

  • Python image.png

在试试Java,不愧是大厂的工具,这种小细节都处理的很好

  • Java

image.png

对话代码

我们在 MarsCode选择代码,你懂吧,就是那种右滑的选中,就会出现一个选项,每个选项都表示一个功能

image.png

我们点击第一个,对话代码,顾名思义就是把这段代码去请教AI,你可以把MarsCode 当成一个老师,你问他,为什么这么说呢,你甚至可以问它你多大了 ?你结婚没有?

image.png

image.png

哈哈,18岁就这么吊

image.png

image.png

如果你不满意,你还可以点击重试的图标

image.png

所以不愧是编程助手,这样才不会影响我们,心中无AI,编码自然神!

image.png

我们再来看第二个,解释代码

这个和上一个功能的区别就是,你如果有什么不懂的代码,就不用请教学长,或者同事,直接点击解释下,他就会给你解释

image.png

左侧就会出现解释对话框,嘎嘎详细

image.png

我们再来看下第三个功能,第三个功能嘎嘎吊,有个场景,你是一家新入职的员工,你接手了公司的新代码,但是这些代码,都没有写注释,老板跟你说,现在项目重购了,后面招聘新人你来培训,你最好给公司代码都加上注释,方便后人理解,这时候用到我们MarsCode,点击注释,这里的注释可不是说真的给你注释代码,哪有这么鸡肋

image.png

  • 点击MarsCode注释后

image.png

  • 完整效果

  • 点击接受,就表示,我们要使用这次生成的注释

image.png

  • 接受后

image.png

对话的最后一个小点就是单元测试, 这个单元测试含义就是,我们可以为代码,直接生成测试类,想象一个场景: 你们公司的代码之前没有写单测的习惯,在一个阳光明媚的下午,你的leader跟你说,小赵,公司的代码覆盖率有点低,你把代码写下单测,于是你看着几万个类陷入了沉思,**MarsCode 走来了! **

突然你的救星出现了

image.png

我们只需要点击单元测试

image.png

点击单元测试后, 一次性为你生成了两种单侧,我相信,Java程序员就秒懂了,知道我们两种用的比较多居然两种的生成了,好小子

  • main 函数方法 image.png

  • Test 单测方法

image.png

拆分代码编辑器

点这个小图标可以进行拆分代码编辑器 ,想象下,你写Vue,一边写template部分,一边写css,、一边写组件

image.png

image.png

快捷键大全

image.png

实战开发 学生管理

这节我们使用 Marscode 来完成开发一个学生管理系统功能案例

  • 技术栈使用的是 经典的React 18+ typescirpt +Axios

最终效果参考下图 :

image.png

通过脚手架快速创建项目

image.png

yarn create react-app student-info-platform --template typescript

image.png

安装所需要的依赖

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 梭哈

完整显示

image.png

  • 最终效果

查询

image.png

编辑

image.png

更换皮肤

image.png

删除

image.png

拆分细化组件

接下来我们使用Marscode,进行组件拆分下,让我们的项目更加完善,并且更加符合企业级项目

大家可以这样进行提问: 请将React 代码拆分为若干个组件,要求每个组件携带注释,并且功能完善最终输出每个组件内容,在输出完整代码 输入这个秘密武器后,你就会得到下方代码 , 将这个组件拆分为更小的、职责单一的组件,能够提高代码的可读性和可维护性。我们可以将它分为以下几个组件:

  1. StudentTable: 表格组件,负责显示学生信息。

  2. StudentFormModal: 表单弹窗组件,负责添加和编辑学生信息。

  3. StudentSearch: 搜索组件,负责过滤学生信息。

  4. 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;

看下效果~

image.png

当然你还可以使用Marscode,进行再次优化~ 真的很强

image.png

对比友商

我们来对比下隔壁友商 某 C*DN

提出经典编程问题, 两数之和 ,要求使用Python和Java 同时输出,并进行对比两数之和的效率,计算耗时

  • MarsCode

image.png


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

image.png

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")

image.png

好好好,某C 你小子,注释不给我就给算了,居然连耗时也给我删除了,不按套路出牌,今天能删示例代码注释,明天就能删业务代码注释,这样我们广大掘友怎么能放心的CV

image.png

DEBUG 神器

DEBUG 最强的神器可以说是整个MarsCode 除AI外 最强、也最难开发的功能了,没有之一, 支持各种语言Debug ,目前光本人测试过的就有7种,下面给大家以Python为例,给大家演示一遍

image.png

和jetbrains一样的,我们点击 左侧行,记住是单击、不是双击,双击会取消的,

点击左侧的小虫子,Bug的小虫子,点击后,也是单击

image.png

点击后关注右侧红色框框的区域

image.png

紧接着我们访问这个Web 服务链接,这个这个项目就是一个Python的Web 服务,我们点击这个Url 即可进入断点,下方是进入断点的详情图

image.png

这里可以看到每个断点的变量的参数信息,

image.png

我们点击快捷键F10,也可以直接点击这个向下的勾勾箭头,进入下一步,

image.png

如果你想进入下一个断点可以输入快捷键F5,我们可以看到第一个断点在14行、第二个断点在18行,当你点击第一个图标就会进入下一个断点

image.png

如果你想一步一步调试则点击第3个图标,

image.png

如果进入了某个函数内部,你想要跳出来,你就点击第4个图标

image.png

重新开始和关闭的话,就点击第5、6个吧

image.png

如果是想要随时看到代码效果,不想去其他窗口就去点击这个小眼睛,嘎嘎清洗

image.png

  • 调试配置

大家还记得我们在VsCode中有一个 json文件叫 image.png


{
    // 使用 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

image.png

是不是看着就很吊,妈妈再也不用担心我没有插件了,光Vue的插件就有1000多个、React 也是几千个

image.png

image.png

image.png

结语

在我们深入探讨了「豆包Marscode」这一创新的云端IDE后,不禁为科技的飞速进步和人工智能在编程领域的深远影响感到惊叹。从最初的代码编辑器到如今高度智能化的编程工具,技术的每一步革新都在重新定义编程的未来。

「豆包Marscode」集成了众多功能,涵盖了从代码调试、解释到优化等各个方面,堪称国产最强AI工具。它不仅提升了开发效率,还简化了编程过程,使得编程不再局限于少数专业人员。通过AI技术,程序员们能够更加专注于创新和创造,而不必为繁琐的细节所困扰。

我们希望在不久的将来,「豆包Marscode」能够成为各个培训机构的首选工具,让更多人有机会体验到这一国产AI IDE的强大功能。愿各个国家的程序员都能感受到「豆包Marscode」带来的便捷和高效,共同推动编程技术的不断进步。

光阴如梭,岁月如歌。在技术不断演进的时代,我们期待着「豆包Marscode」不断突破,续写更辉煌的篇章。让我们共同见证科技如何改变编程的未来,携手迈向更加智能、高效的开发新时代。