新的框架的描述
基本的增删改查已经被限制住了,这里的逻辑大致分成了
index.tsx
: 用于展示数据列表,搜索过滤等功能form.tsx
: 用于处理数据的新增和编辑detail.tsx
: 用于展示数据的详情
这样的好处就是,尽量的关注业务,一些重复的细节可以忽略掉
基础建设
已经把基础的页面布局,以及常用的按钮等封装到私有的 npm
仓库,前期需要熟悉一下如何使用
拿几个组件来举例子,这个 BasicPage
是我们封装的,我们只需传递后端资源的地址,就可以完成对资源的获取,分页等功能已经内置了
然后就是表格的列定义,这里面定义了多少列,页面上就会支持筛选多少列
// index.tsx
import type { ProColumns } from '@ant-design/pro-table/es/typing'
import type { PageRef } from '@/starter'
import { BasicPage, DeleteButton } from '@/starter'
import { createRoutePage } from '@/starter'
import { Button, Space } from 'antd'
import { useRef } from 'react'
import Form from './form'
export default createRoutePage({
title: '商品属性',
component: () => {
const pageRef = useRef<PageRef>(null)
const columns: ProColumns<Api.GoodsAttrs>[] = [
{ dataIndex: ['id'], title: 'ID', fixed: 'left', width: 60, hideInForm: true },
{ dataIndex: ['name'], title: '名称' },
{ dataIndex: ['sort'], title: '排序值', hideInSearch: true },
{ dataIndex: ['created_at'], title: '创建时间', hideInForm: true, hideInSearch: true },
{
dataIndex: ['action'],
title: '操作',
fixed: 'right',
width: 120,
hideInDescriptions: true,
hideInForm: true,
hideInSearch: true,
align: 'center',
render: (_, record, _index, action) => {
return (
<Space>
<Button
icon={<IconLucideSquarePen />}
type="text"
onClick={() => pageRef.current?.showEditForm(record.id)}
/>
<DeleteButton
resource="goods-specs"
resourceName="商品规格"
id={record.id}
onSuccess={() => action?.reload()}
/>
</Space>
)
},
},
]
return (
<BasicPage<Api.GoodsAttrs>
resource="goods-attrs"
resourceName="商品属性"
columns={columns}
ref={pageRef}
Form={Form}
basicDetailProps={{
variant: 'modal',
width: 400,
title: record => record.name,
}}
basicFormProps={{
variant: 'modal',
}}
basicTableProps={{ scroll: undefined, virtual: false, params: { sorters: [{ field: 'id', order: 'desc' }] } }}
/>
)
},
})
form.tsx
的栗子如下
import { ProFormDigit, ProFormSwitch, ProFormText, ProFormTextArea } from '@ant-design/pro-components'
import { ResourceTreeSelect } from '@kiyoung/starter'
import { Space, Tag } from 'antd'
import { memo } from 'react'
function form() {
return (
<>
<ProFormText
label="名称"
name={['name']}
rules={[{ required: true }]}
/>
<ResourceTreeSelect
label="分类"
resource="goods-categories"
name={['cate_id']}
/>
<ProFormDigit label="排序值" name={['sort']} width={120} />
</>
)
}
export default memo(form)
form
中也是按照资源去获取 options
,以及根据 name
来回显字段等等,都已经在上层组件中封装好了
前后端的沟通成本
听说后端是对表中字段的监控,从而实现各种各样的需求,从前端的角度理解的话,这样会少些很多接口
例如
如果我想改某个数据的状态从 未签收 => 已签收
那么按照之前的经验,可能会有专门的接口用于处理这个逻辑
但是现在,我可以通过 put 请求,通过修改状态,后端通过监控这个字段的状态,来实现这个逻辑
看一下这个按钮的实现
<EditButton
icon={<IconLucideClipboardX />}
resource="delivery-orders"
resourceName="撤销发货"
tooltip="撤销发货"
type="text"
id={record.id}
params={{ status: 2 }}
onSuccess={() => {
window.$message?.success('撤销发货成功')
}}
/>
这是一个修改状态的按钮,上面 resource
定义了请求那个资源, params
中定义了要改那个字段,当然这里的状态使用的硬编码,这是不对的,那么就讲一下枚举值的定义吧
枚举值的定义
以下代码是定义一个枚举值的栗子
import type { ConstantEnum } from '@/utils/common'
import { transformRecordToOption } from '@/utils/common'
/**
* 接单状态
*/
export type ReceiveStatus = 0 | 1 | 2 | 3
export const ReceiveStatusUnreceived = 0
export const ReceiveStatusReceived = 1
export const ReceiveStatusPartiallyReceived = 2
export const ReceiveStatusError = 3
export const RECEIVE_STATUS: ConstantEnum<ReceiveStatus> = {
[ReceiveStatusUnreceived]: '未接单',
[ReceiveStatusReceived]: '已接单',
[ReceiveStatusPartiallyReceived]: '部分接单',
[ReceiveStatusError]: '异常',
}
export const RECEIVE_STATUS_OPTIONS = transformRecordToOption(RECEIVE_STATUS) // 第二个形参传递 tag[] 的颜色
其中有好处也有坏处
好处就是
- 如果后端私自动了某一个枚举值,但是没通知你,那么就是后端的问题了
- 结构直观明显,标签的枚举的话也会自动给你分配颜色
- 一次定义,受益的很
- ts 类型会检测问题
坏处
- 麻烦,定义一次要敲很多代码,不过,可以给 ai 来帮你处理
上层组件 bug 的反馈和更新
因为现在这套脚手架,基建还不是很完善,会有一些 bug,还有新的组件需要封装等等因素,所以导致我们私有的 start
经常需要更新
所以经常需要以下操作
- 拉取
origin/main
分支合并到自己的分支上 - 删除本地依赖
- 重新安装依赖
- 启动开发服务器
当然这些操作可以用脚本来跑
#!/bin/bash
# 提示用户是否合并 origin/develop 分支
read -p "是否需要合并 origin/develop 分支?(Y/n): " ans
# 如果输入为空,默认 Y
ans=${ans:-Y}
ans=$(echo "$ans" | tr '[:upper:]' '[:lower:]') # 转小写
if [[ "$ans" == "y" || "$ans" == "yes" ]]; then
echo "🚀 正在合并 origin/develop 分支..."
git pull --no-rebase origin develop
if [ $? -ne 0 ]; then
echo "❌ 合并失败,请检查冲突后重试。"
exit 1
fi
else
echo "⚠️ 跳过合并分支。"
fi
echo "🗑️ 正在删除 node_modules 文件夹..."
rm -rf node_modules
echo "📦 正在安装依赖 (pnpm i)..."
pnpm i
echo "🔧 启动开发环境 (pnpm run dev)..."
pnpm run dev