签入版本
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 3.9 前端联调指引
|
||||
|
||||
:::tip 概述
|
||||
后端接口开发完成后,需要在前端创建对应的 API 模块和页面组件。本节以 example 模块为例,提供简要指引,详细内容参考[第 9 章](/zh/frontend/overview.html)。
|
||||
后端接口开发完成后,需要在前端创建对应的 API 模块和页面组件。本节以 example 模块为例,提供简要指引,详细内容参考 [第 9 章](/zh/frontend/overview.html)。
|
||||
:::
|
||||
|
||||
## 联调流程
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
## 步骤一:创建 API 模块
|
||||
|
||||
在 `ui/src/api/tool/` 下创建 `example.ts`(来自项目实际代码):
|
||||
在 `ui/src/api/tool/` 下创建 `example.ts`:
|
||||
|
||||
```typescript
|
||||
// ui/src/api/tool/example.ts
|
||||
@@ -31,7 +31,7 @@ import { http } from '@/utils/http/axios';
|
||||
* 获取案例演示分页列表
|
||||
*
|
||||
* @param params 查询参数,包含 pageNo、pageSize 及业务筛选条件
|
||||
* @returns 分页结果,含 records、total、size、current、pages
|
||||
* @returns 分页结果,含 records、total、current、size
|
||||
*/
|
||||
export function getExamplePage(params?: Record<string, any>) {
|
||||
return http.request({
|
||||
@@ -43,9 +43,6 @@ export function getExamplePage(params?: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 获取全部案例演示列表
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @returns 案例演示列表
|
||||
*/
|
||||
export function getExampleList(params?: Record<string, any>) {
|
||||
return http.request({
|
||||
@@ -57,11 +54,8 @@ export function getExampleList(params?: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 根据 ID 获取案例演示详情
|
||||
*
|
||||
* @param id 案例演示ID
|
||||
* @returns 案例演示详情数据
|
||||
*/
|
||||
export function getExampleDetail(id) {
|
||||
export function getExampleDetail(id: number) {
|
||||
return http.request({
|
||||
url: '/example/detail/' + id,
|
||||
method: 'get',
|
||||
@@ -69,10 +63,7 @@ export function getExampleDetail(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加案例演示
|
||||
*
|
||||
* @param data 案例演示数据
|
||||
* @returns 新记录的 ID
|
||||
* 添加案例演示(入参 camelCase,后端 FormRequest 自动转换)
|
||||
*/
|
||||
export function exampleAdd(data: any) {
|
||||
return http.request({
|
||||
@@ -83,10 +74,7 @@ export function exampleAdd(data: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新案例演示
|
||||
*
|
||||
* @param data 案例演示数据,需包含主键 id
|
||||
* @returns 操作结果
|
||||
* 更新案例演示(需包含主键 id)
|
||||
*/
|
||||
export function exampleUpdate(data: any) {
|
||||
return http.request({
|
||||
@@ -98,11 +86,8 @@ export function exampleUpdate(data: any) {
|
||||
|
||||
/**
|
||||
* 删除案例演示
|
||||
*
|
||||
* @param id 案例演示ID
|
||||
* @returns 操作结果
|
||||
*/
|
||||
export function exampleDelete(id) {
|
||||
export function exampleDelete(id: number) {
|
||||
return http.request({
|
||||
url: '/example/delete/' + id,
|
||||
method: 'DELETE',
|
||||
@@ -110,10 +95,9 @@ export function exampleDelete(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除案例演示
|
||||
* 批量删除案例演示(形如 { ids: [1, 2, 3] })
|
||||
*
|
||||
* @param data 含 ids 数组的对象,形如 { ids: [1, 2, 3] }
|
||||
* @returns 操作结果
|
||||
* 注意:批量删除后端路由为 DELETE(请求体仍传 ids 数组)。
|
||||
*/
|
||||
export function exampleBatchDelete(data: any) {
|
||||
return http.request({
|
||||
@@ -124,12 +108,9 @@ export function exampleBatchDelete(data: any) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入案例演示
|
||||
*
|
||||
* @param data 文件数据(FormData)
|
||||
* @returns 导入结果,含成功数量与失败明细
|
||||
* 导入案例演示(FormData 文件)
|
||||
*/
|
||||
export function exampleImport(data) {
|
||||
export function exampleImport(data: any) {
|
||||
return http.request({
|
||||
url: '/example/import',
|
||||
method: 'POST',
|
||||
@@ -138,12 +119,9 @@ export function exampleImport(data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出案例演示
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @returns 导出文件的 URL
|
||||
* 导出案例演示(返回文件 URL)
|
||||
*/
|
||||
export function exampleExport(params) {
|
||||
export function exampleExport(params?: Record<string, any>) {
|
||||
return http.request({
|
||||
url: '/example/export',
|
||||
method: 'GET',
|
||||
@@ -152,9 +130,13 @@ export function exampleExport(params) {
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
HTTP 封装(Token 携带、401 处理、统一错误提示、camel/snake 转换)由 `http` 实例统一完成,API 模块只描述"哪个地址、什么方法"。见 [9.4 HTTP 请求封装](/zh/frontend/http.html)。
|
||||
:::
|
||||
|
||||
## 步骤二:创建页面组件
|
||||
|
||||
在 `ui/src/views/tool/example/` 下创建以下 5 个文件:
|
||||
在 `ui/src/views/tool/example/` 下创建以下 5 个文件(与代码生成器输出结构一致):
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
@@ -165,7 +147,7 @@ export function exampleExport(params) {
|
||||
| `querySchemas.ts` | 搜索表单字段定义 |
|
||||
|
||||
:::tip 关于以下示例
|
||||
以下代码使用原生 `el-table` / `el-form` 简化展示核心逻辑。实际项目中应使用封装好的 `BasicTable` + `useForm` 等组合式组件,详见[第 9 章组件文档](/zh/frontend/overview.html)。
|
||||
以下代码使用原生 `el-table` / `el-form` 简化展示核心逻辑。实际项目中应使用封装好的 `BasicTable` + `useForm` 等组合式组件,详见 [第 9 章组件文档](/zh/frontend/overview.html)。
|
||||
:::
|
||||
|
||||
`index.vue`(列表页)示例:
|
||||
@@ -182,7 +164,7 @@ export function exampleExport(params) {
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择" clearable>
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="禁用" :value="0" />
|
||||
<el-option label="停用" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@@ -191,30 +173,29 @@ export function exampleExport(params) {
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-button type="primary" @click="handleAdd">新增</el-button>
|
||||
<el-button type="danger" :disabled="!selectedIds.length" @click="handleBatchDelete">
|
||||
批量删除
|
||||
</el-button>
|
||||
<!-- 操作按钮(v-perm 控制显示,与后端权限码一致) -->
|
||||
<el-button v-perm="['sys:example:add']" type="primary" @click="handleAdd">新增</el-button>
|
||||
<el-button v-perm="['sys:example:batchDelete']" type="danger"
|
||||
:disabled="!selectedIds.length" @click="handleBatchDelete">批量删除</el-button>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table :data="tableData" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="id" label="ID" width="80" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="typeText" label="类型" width="100" />
|
||||
<el-table-column prop="statusText" label="状态" width="100" />
|
||||
<el-table-column prop="sort" label="排序" width="80" />
|
||||
<el-table-column prop="createTime" label="创建时间" width="180" />
|
||||
<el-table-column label="操作" width="200">
|
||||
<template #default="{ row }">
|
||||
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
|
||||
<el-button v-perm="['sys:example:update']" size="small" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-perm="['sys:example:delete']" size="small" type="danger"
|
||||
@click="handleDelete(row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<!-- 分页(后端固定返回 records / total / current / size / pages) -->
|
||||
<el-pagination
|
||||
v-model:current-page="pageNo"
|
||||
v-model:page-size="pageSize"
|
||||
@@ -263,13 +244,25 @@ onMounted(() => fetchData());
|
||||
tool/example/index
|
||||
```
|
||||
|
||||
前端路由系统会自动将此路径映射到 `ui/src/views/tool/example/index.vue`。
|
||||
前端路由系统会自动将此路径映射到 `ui/src/views/tool/example/index.vue`(动态路由由后端菜单数据驱动)。
|
||||
|
||||
## 步骤四:测试联调
|
||||
|
||||
1. 确保后端服务运行:`php think run`
|
||||
2. 确保前端服务运行:`pnpm dev`
|
||||
3. 刷新前端页面,侧边栏应出现"案例演示"菜单
|
||||
4. 点击菜单,测试增删改查功能
|
||||
1. 确保后端服务运行:`php artisan serve`(或 `composer dev`)
|
||||
2. 确保前端服务运行:`cd ui && pnpm dev`(开发端口 8001)
|
||||
3. 为测试角色分配新菜单权限(见 [3.8 权限节点配置](/zh/guide/permission.html))
|
||||
4. 刷新前端页面,侧边栏应出现"案例演示"菜单
|
||||
5. 点击菜单,测试增删改查功能
|
||||
|
||||
详细前端开发内容请参考[第 9 章](/zh/frontend/overview.html)。
|
||||
### 联调自查顺序
|
||||
|
||||
```text
|
||||
接口 404 → 路由未注册 / URL、HTTP 方法与 routes/api.php 不一致
|
||||
接口 401 → Token 未携带或过期(看 http 封装是否注入 Authorization)
|
||||
接口 403 → 权限码未配置 / 角色未分配(见 3.8)
|
||||
接口 code=1 → 看 msg 与 data(FormRequest 字段错误明细)
|
||||
表格不显示 → 响应结构应为 data.records / data.total,检查绑定字段
|
||||
菜单不显示 → 组件路径错误 / 角色未分配菜单 / 前端 views 下无对应 .vue
|
||||
```
|
||||
|
||||
详细前端开发内容请参考 [第 9 章](/zh/frontend/overview.html)。
|
||||
|
||||
Reference in New Issue
Block a user