本文是《DeepSeek 辅助编程实战》系列第 5 篇(完结篇),演示如何用 DeepSeek 实现航次计划系统的前端页面,包括项目搭建、4 个核心页面开发和前后端联调。

一、前端技术栈

技术 版本 用途
Vue 3 3.4 前端框架(Composition API)
Element Plus 2.7 UI 组件库
Vue Router 4.3 路由管理
Axios 1.6 HTTP 客户端
Vite 5.2 构建工具
dayjs 1.11 日期处理

选择 Element Plus 的理由:

  • 企业级中后台组件丰富(表格、表单、对话框)
  • 中文文档完善,社区活跃
  • 与 Vue 3 Composition API 完美配合

二、项目搭建

2.1 初始化项目

我的 Prompt:

请用 Vite 创建 Vue 3 + Element Plus 前端项目,要求:

1. 项目名:voyage-plan-frontend
2. 依赖:vue 3.4, element-plus 2.7, vue-router 4.3, axios 1.6, dayjs 1.11
3. 开发服务器端口:3000
4. API 代理:/api → http://localhost:5000
5. Element Plus 中文国际化

请给出 package.json、vite.config.js 和 main.js。

package.json:

{
  "name": "voyage-plan-frontend",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.4.0",
    "element-plus": "^2.7.0",
    "vue-router": "^4.3.0",
    "axios": "^1.6.0",
    "dayjs": "^1.11.0",
    "@element-plus/icons-vue": "^2.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.0.0",
    "vite": "^5.2.0"
  }
}

vite.config.js:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:5000',
        changeOrigin: true
      }
    }
  }
})

main.js:

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(ElementPlus, { locale: zhCn })
app.use(router)

// 注册所有图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

app.mount('#app')

2.2 项目结构

frontend/
├── index.html
├── package.json
├── vite.config.js
└── src/
    ├── main.js              # 入口
    ├── App.vue              # 根组件(布局)
    ├── router/
    │   └── index.js         # 路由配置
    ├── api/
    │   └── voyagePlan.js    # API 客户端
    └── views/
        ├── PlanList.vue     # 列表页
        ├── PlanDetail.vue   # 详情页
        ├── PlanCreate.vue   # 创建页
        └── PlanEdit.vue     # 编辑页

三、核心页面开发

3.1 应用布局(App.vue)

我的 Prompt:

请用 Element Plus 实现应用布局:

1. 顶部 Header:
   - 系统名称:"航次计划编制系统"
   - 蓝色渐变背景
   - 白色文字

2. 左侧 Sidebar:
   - 菜单项:计划列表、新建计划
   - 使用 el-menu 组件
   - 可折叠

3. 主内容区:
   - router-view 渲染子页面
   - 适当的内边距

使用 Vue 3 <script setup> 语法。
<template>
  <el-container class="app-container">
    <el-header class="app-header">
      <h1>航次计划编制系统</h1>
    </el-header>
    <el-container>
      <el-aside width="200px" class="app-aside">
        <el-menu :default-active="route.path" router>
          <el-menu-item index="/">
            <el-icon><List /></el-icon>
            <span>计划列表</span>
          </el-menu-item>
          <el-menu-item index="/create">
            <el-icon><Plus /></el-icon>
            <span>新建计划</span>
          </el-menu-item>
        </el-menu>
      </el-aside>
      <el-main class="app-main">
        <router-view />
      </el-main>
    </el-container>
  </el-container>
</template>

<style>
.app-header {
  background: linear-gradient(135deg, #1e3a5f 0%, #2c5f8a 100%);
  color: white;
  display: flex;
  align-items: center;
}
.app-header h1 { margin: 0; font-size: 20px; }
.app-aside { background: #fff; border-right: 1px solid #e6e6e6; }
.app-main { background: #f5f7fa; padding: 20px; }
</style>

3.2 API 客户端

我的 Prompt:

请用 Axios 封装 API 客户端,要求:

1. baseURL: /api/v1/voyage-plans
2. 响应拦截器:提取 data,统一错误处理
3. 导出所有 API 方法:
   - getAll() / getById(id) / getByPlanNumber(num)
   - getByVessel(name) / getByStatus(status)
   - create(data) / update(id, data)
   - issue(id, data) / initiateChange(id, data)
   - completeChange(id, changedBy) / cancel(id, data)
// api/voyagePlan.js
import axios from 'axios'

const api = axios.create({
  baseURL: '/api/v1/voyage-plans',
  timeout: 10000,
  headers: { 'Content-Type': 'application/json' }
})

// 响应拦截器
api.interceptors.response.use(
  response => response.data,
  error => {
    const msg = error.response?.data?.message || '请求失败'
    return Promise.reject(new Error(msg))
  }
)

export default {
  getAll: () => api.get(''),
  getById: (id) => api.get(`/${id}`),
  getByPlanNumber: (planNumber) => api.get(`/number/${planNumber}`),
  getByVessel: (vesselName) => api.get(`/vessel/${vesselName}`),
  getByStatus: (status) => api.get(`/status/${status}`),
  create: (data) => api.post('', data),
  update: (id, data) => api.put(`/${id}`, data),
  issue: (id, data) => api.post(`/${id}/issue`, data),
  initiateChange: (id, data) => api.post(`/${id}/initiate-change`, data),
  completeChange: (id, changedBy) => api.post(`/${id}/complete-change?changedBy=${changedBy}`),
  cancel: (id, data) => api.post(`/${id}/cancel`, data),
}

3.3 列表页(PlanList.vue)

我的 Prompt:

请用 Element Plus 实现航次计划列表页:

1. 顶部操作栏:
   - 状态筛选下拉框(全部/草稿/已发布/变更中/已取消)
   - 新建计划按钮

2. 表格列:
   - 计划编号、航次名称、船舶名称、起始港、目的港
   - 版本(V1, V2...)
   - 状态(Tag 标签,不同颜色)
   - 总航程
   - 创建时间
   - 操作列:详情/编辑/发布/变更/取消

3. 操作按钮根据状态显示:
   - 草稿:编辑、发布
   - 已发布:变更
   - 非取消:取消

4. 操作确认:
   - 发布:确认对话框
   - 变更/取消:输入原因

使用 Vue 3 <script setup> + Composition API。

核心代码片段:

<template>
  <el-card shadow="never">
    <template #header>
      <div class="card-header">
        <span>航次计划列表</span>
        <div>
          <el-select v-model="statusFilter" placeholder="按状态筛选" clearable @change="loadData">
            <el-option label="草稿" value="Draft" />
            <el-option label="已发布" value="Issued" />
            <el-option label="变更中" value="Changing" />
            <el-option label="已取消" value="Cancelled" />
          </el-select>
          <el-button type="primary" @click="$router.push('/create')">
            <el-icon><Plus /></el-icon> 新建计划
          </el-button>
        </div>
      </div>
    </template>

    <el-table :data="plans" v-loading="loading" stripe>
      <el-table-column prop="planNumber" label="计划编号" width="180" />
      <el-table-column prop="voyageName" label="航次名称" />
      <el-table-column prop="vesselName" label="船舶名称" width="120" />
      <el-table-column label="状态" width="100">
        <template #default="{ row }">
          <el-tag :type="statusTagType(row.status)" effect="dark" size="small">
            {{ row.statusDisplay }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="200" fixed="right">
        <template #default="{ row }">
          <el-button link type="primary" @click="$router.push(`/detail/${row.id}`)">详情</el-button>
          <el-button link type="success" v-if="row.status === 'Draft'" @click="handleIssue(row)">发布</el-button>
          <el-button link type="danger" v-if="row.status !== 'Cancelled'" @click="handleCancel(row)">取消</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-card>
</template>

3.4 详情页(PlanDetail.vue)

我的 Prompt:

请实现航次计划详情页,使用 Element Plus 组件展示:

1. 页面头部:返回按钮 + 计划编号 + 状态标签

2. 信息分区(el-card):
   - 基本信息:el-descriptions 展示编号、名称、船舶、版本、时间等
   - 港口信息:起始港/目的港并排展示
   - 航线段:el-table 展示各航段详情
   - 风险评估:el-statistic 展示四维度评分 + 综合风险等级
   - 燃油估算:el-descriptions 展示消耗量、安全系数等
   - 应急预案:联系人、电话、备用港口

3. 底部操作按钮:
   - 根据当前状态显示可用操作

使用 el-page-header 作为页面头部。

3.5 创建页(PlanCreate.vue)

我的 Prompt:

请实现航次计划创建表单页,要求:

1. 分区表单(多个 el-card):
   - 基本信息:航次名称、船舶名称、航次编号、出发/到达时间、创建人
   - 港口信息:起始港(UN/LOCODE、名称、国家)、目的港
   - 航线段:动态添加/删除航段(el-button + v-for)
   - 风险评估:4 个维度评分(el-input-number, 0-100)
   - 燃油估算:IFO/MGO 消耗、安全系数
   - 应急预案:联系人、电话、备用港口

2. 表单校验:
   - 必填字段:航次名称、船舶名称、港口代码/名称、创建人
   - 日期校验:到达时间 > 出发时间

3. 提交后跳转到详情页

航线段使用动态行,每行包含:起点、终点、距离、航速、时间、IFO、MGO、说明。

动态航线段的核心实现:

<el-card shadow="never">
  <template #header>
    <div class="section-header">
      <span>航线段</span>
      <el-button type="primary" size="small" @click="addSegment">
        <el-icon><Plus /></el-icon> 添加航段
      </el-button>
    </div>
  </template>

  <div v-for="(seg, idx) in form.routeSegments" :key="idx" class="segment-row">
    <el-row :gutter="12">
      <el-col :span="3">
        <el-input v-model="seg.fromPortCode" placeholder="起点" size="small" />
      </el-col>
      <el-col :span="3">
        <el-input v-model="seg.toPortCode" placeholder="终点" size="small" />
      </el-col>
      <el-col :span="3">
        <el-input-number v-model="seg.distanceNauticalMiles" :min="0" size="small" />
      </el-col>
      <!-- 更多字段... -->
      <el-col :span="1">
        <el-button type="danger" size="small" link @click="removeSegment(idx)">
          <el-icon><Delete /></el-icon>
        </el-button>
      </el-col>
    </el-row>
  </div>
</el-card>

3.6 编辑页(PlanEdit.vue)

我的 Prompt:

请实现航次计划编辑页,与创建页类似但有以下区别:

1. 进入页面时加载已有数据,填充表单
2. 航次编号不可修改(disabled)
3. 增加"修改人"字段
4. 提交调用 update API
5. 返回按钮跳转到详情页(而非列表页)

四、路由配置

我的 Prompt:

请配置 Vue Router,包含以下路由:

/ → PlanList(列表页)
/detail/:id → PlanDetail(详情页)
/create → PlanCreate(创建页)
/edit/:id → PlanEdit(编辑页)
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import PlanList from '../views/PlanList.vue'
import PlanDetail from '../views/PlanDetail.vue'
import PlanCreate from '../views/PlanCreate.vue'
import PlanEdit from '../views/PlanEdit.vue'

const routes = [
  { path: '/', component: PlanList },
  { path: '/detail/:id', component: PlanDetail },
  { path: '/create', component: PlanCreate },
  { path: '/edit/:id', component: PlanEdit },
]

export default createRouter({
  history: createWebHistory(),
  routes
})

五、前后端联调

5.1 启动服务

# 终端 1:启动后端
cd src/VoyagePlan.Api && dotnet run

# 终端 2:启动前端
cd frontend && npm install && npm run dev

5.2 联调验证

  1. 打开 http://localhost:3000,看到列表页
  2. 点击「新建计划」,填写表单,提交
  3. 创建成功后跳转到详情页,确认数据正确
  4. 返回列表页,确认新计划已显示
  5. 测试状态流转:发布 → 变更 → 完成变更 → 取消

5.3 常见问题

问题:跨域请求失败

我的 Prompt:

前端请求后端报 CORS 错误:
Access to XMLHttpRequest at 'http://localhost:5000/api/...'
from origin 'http://localhost:3000' has been blocked by CORS policy

如何解决?

DeepSeek 的解答:

Program.cs 中配置 CORS:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("http://localhost:3000")
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

// ...
app.UseCors("AllowFrontend");

或者使用 Vite 代理(推荐开发环境):

// vite.config.js
proxy: {
  '/api': {
    target: 'http://localhost:5000',
    changeOrigin: true
  }
}

六、Prompt 技巧总结

1. 描述页面布局时用视觉语言

❌ "做一个列表页"
✅ "做一个列表页,顶部有状态筛选和新建按钮,
   中间是 el-table 表格,操作列在右侧固定,
   不同状态用不同颜色的 Tag 显示"

2. 指定组件和交互方式

❌ "实现表单提交"
✅ "使用 el-form + el-form-item 实现表单,
   必填字段加 rules 校验,
   提交前调用 validate(),
   成功后用 ElMessage.success 提示并跳转"

3. 让 AI 处理边界情况

请处理以下边界情况:
1. 列表为空时显示空状态
2. 加载数据时显示 loading
3. 请求失败时显示错误提示
4. 删除/取消操作需要二次确认

七、系列总结

通过 5 篇博客,我们完整演示了如何用 DeepSeek 辅助完成一个航运业务系统的全栈开发:

阶段 工具 产出
需求调研 DeepSeek 对话 PRD 文档、功能列表
软件设计 DeepSeek 对话 架构图、领域模型、API 设计
领域编码 DeepSeek 生成代码 DDD 四层架构后端代码
后端测试 DeepSeek 生成测试 6 个单元测试 + 联调
前端开发 DeepSeek 生成代码 Vue 3 + Element Plus 4 个页面

核心心得:

  1. AI 是加速器,不是替代品:DeepSeek 帮你快速生成 80% 的代码,但剩余 20% 的审查、调试和业务适配需要人工完成
  2. Prompt 质量决定输出质量:越具体的 Prompt(包含技术栈、组件名、交互方式),输出越接近可用
  3. 分步迭代优于一步到位:按层/按模块逐步生成,每步验证后再进行下一步
  4. 让 AI 处理重复性工作:CRUD 代码、表单校验、测试用例这些重复性工作,AI 比人更高效

希望这个系列能帮助你在实际项目中更好地利用 DeepSeek 提升开发效率。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐