016 更新迭代 migrate-static-data-to-nitro-query 的 list-page-pattern 列表页改造规范,避免出现删改多余内容的情况
在以下文件内,增加以下严格规范:
openspec\changes\migrate-static-data-to-nitro-query\specs\migration-guide.mdopenspec\changes\migrate-static-data-to-nitro-query\specs\list-page-pattern\spec.md
修改列表页时,新增的严格规范如下:
1. 无条件的按照 fix-type-error 来处理类型错误
- 在处理列表页的类型替换和变量替换时,必须严格按照
.claude\agents\fix-type-error.md文档所述的要求来执行。不要自己胡乱发挥,乱写代码,胡乱改变原有的类型,导入不存在的,冗余的,多余的全局类型。
2. 不要删改破坏掉现有的弹框函数逻辑
每一个列表页都有这样的代码段。这些逻辑是列表页弹框逻辑必备的函数。不允许你删改。这不是你本次迁移改造任务的处理范围,不要动不属于你范围的代码!
ts
const { modeText, setMode, isAdd } = useMode();
const [isFetchingT, setIsLoadingT] = useToggle(false);
/** 模拟异步操作函数 */
async function testAsync() {
setIsLoadingT(true);
consola.log("模拟异步操作, isFetchingT ", isFetchingT.value);
await sleep(1300);
setIsLoadingT(false);
consola.log("模拟异步操作, isFetchingT ", isFetchingT.value);
}3. 不要删掉弹框实例代码,只负责做类型替换
不要随便删掉下面的弹框实例新建逻辑,这不是你要负责的内容。你只需要实现中文变量名替换、导入来自类型项目的业务类型,就可以了。不要做多余的操作!
ts
import { type 停车场表单Props, defaultForm, type 停车场表单_VO } from "./components/form";
import 停车场表单 from "./components/form.vue";
const 停车场表单Instance = ref<InstanceType<typeof 停车场表单> | null>(null);你的正确处理应该是这样的:
- 去类型项目导入
ParkingLotFormVO,导入形如xxxFormVO格式的表单类型,去替代来自相对路径的form.ts导出的停车场表单_VO中文类型。 - 把导入的中文变量名,换成英文名。
停车场表单应该换成ParkingLotForm换成形如xxxForm的组件变量名。 - 把本地的表单实例的中文变量名,换成英文名。
停车场表单Instance应该换成ParkingLotFormInstance。
ts
import type { ParkingLotFormVO } from "@01s-11comm/type";
import { type ParkingLotFormProps, defaultForm } from "./components/form";
import ParkingLotForm from "./components/form.vue";
const ParkingLotFormInstance = ref<InstanceType<typeof ParkingLotForm> | null>(null);以下处理方式是错误的。你把原来该有的表单实例全删除掉了。这不是你要负责改造的部分。
ts
import type { ParkingLotListItem } from "@01s-11comm/type";4. 不要胡乱删改打开弹框组件的处理逻辑
在列表页内,处理弹框组件已经有的逻辑时,以下的处理方式错的很离谱:
- 你删除掉了表单对象的业务类型约束,这是不对的。不要删掉已经有的代码逻辑。
- 深克隆函数,本来应该是克隆
defaultForm变量,结果你改成了一个{},这是完全错误的做法。不要删改本来就有的函数传参逻辑。 - 你多删除了
props和defaultValues,这两个变量是本来的业务逻辑,不要删除不属于你处理范围的代码。
ts
/** 业务对象 */
const parkingLotFormVO = isAdd.value
? structuredClone({})
: structuredClone({
...row,
parkingLotType: row?.parkingLotType || "地面停车场",
parkingSpaceType: row?.parkingSpaceType || "标准车位",
});原来被处理的代码如下:
你应该保留这些处理逻辑和结构,只负责更改代码的变量名,和使用的函数。不要删掉多余的代码结构。
ts
/** 业务对象 */
const 停车场表单对象: 停车场表单_VO = isAdd.value
? cloneDeep(defaultForm)
: cloneDeep({
...defaultForm,
...row,
停车场类型: row?.停车场类型 || defaultForm.停车场类型,
车位类型: row?.车位类型 || defaultForm.车位类型,
});
/** 表单组件需要的props */
const props: 停车场表单Props = {
form: 停车场表单对象,
defaultValues: 停车场表单对象,
};
/** 根据不同模式下 变化的表单默认重置对象 */
const defaultValues = props.defaultValues;正确的处理逻辑和处理结果如下:
- 变量名替换:
停车场表单对象->parkingLotFormVO停车场表单_VO->ParkingLotFormVO停车场表单Props->ParkingLotFormProps
- 函数替换:
cloneDeep->structuredClone
你只负责最基础的变量名替换成英文,深克隆函数 cloneDeep 换成统一的 structuredClone 即可。不要胡乱更改现有的代码逻辑。
ts
/** 业务对象 */
const parkingLotFormVO: ParkingLotFormVO = isAdd.value
? structuredClone(defaultForm)
: structuredClone({
...defaultForm,
...row,
parkingLotType: row?.parkingLotType || defaultForm.parkingLotType,
parkingSpaceType: row?.parkingSpaceType || defaultForm.parkingSpaceType,
});
/** 表单组件需要的props */
const props: ParkingLotFormProps = {
form: parkingLotFormVO,
defaultValues: parkingLotFormVO,
};5. 不要胡乱删改掉打开弹框函数 openDialog 本来就有的按钮配置逻辑
你的职责是完成中文变量名和中文类型名的替换,不要删改掉本来就写好的代码逻辑!
5.1. 原来的代码
ts
{
footerButtons: [
{
label: transformI18n($t("common.buttons.cancel")),
type: "info",
btnClick: async ({ dialog: { options, index }, button }) => {
const formComputed = 停车场表单Instance.value?.formComputed;
await useDoBeforeClose({ defaultValues, formComputed, index, options });
},
},
{
label: transformI18n($t("common.buttons.reset")),
type: "warning",
btnClick: ({ dialog: { options, index }, button }) => {
停车场表单Instance.value?.plusFormInstance?.handleReset();
},
},
{
label: transformI18n($t("common.buttons.submit")),
type: "success",
btnClick: async ({ dialog: { options, index }, button }) => {
const res = await 停车场表单Instance.value?.plusFormInstance?.handleSubmit();
if (res) {
button.btn.loading = true;
await testAsync();
button.btn.loading = false;
closeDialog(options, index);
}
},
},
],
}5.2. 错误的处理结果
这是你错误的处理结果:
- 不要删掉本来就有的
const formComputed变量。这个变量没有影响到你的任务。不要删减和你本次任务无关的代码。 - 不要删掉
useDoBeforeClose函数的调用逻辑。这和你的任务无关。 - 不要删掉重置按钮这整个配置对象。这和你的任务无关!、
ts
{
footerButtons: [
{
label: transformI18n($t("common.buttons.cancel")),
type: "info",
btnClick: async ({ dialog: { options, index }, button }) => {
closeDialog(options, index);
},
},
{
label: transformI18n($t("common.buttons.submit")),
type: "success",
btnClick: async ({ dialog: { options, index }, button }) => {
button.btn.loading = true;
await testAsync();
button.btn.loading = false;
closeDialog(options, index);
},
},
],
}5.3. 正确的处理结果
- 把中文变量名
停车场表单Instance换成ParkingLotFormInstance就行了。这就是你的职责。为什么你要额外的去修改掉其他本来就有的处理逻辑呢?
ts
footerButtons: [
{
label: transformI18n($t("common.buttons.cancel")),
type: "info",
btnClick: async ({ dialog: { options, index }, button }) => {
const formComputed = ParkingLotFormInstance.value?.formComputed;
await useDoBeforeClose({ defaultValues, formComputed, index, options });
},
},
{
label: transformI18n($t("common.buttons.reset")),
type: "warning",
btnClick: ({ dialog: { options, index }, button }) => {
ParkingLotFormInstance.value?.plusFormInstance?.handleReset();
},
},
{
label: transformI18n($t("common.buttons.submit")),
type: "success",
btnClick: async ({ dialog: { options, index }, button }) => {
const res = await ParkingLotFormInstance.value?.plusFormInstance?.handleSubmit();
if (res) {
button.btn.loading = true;
await testAsync();
button.btn.loading = false;
closeDialog(options, index);
}
},
},
],6. 不要更改掉 definePage 宏的排布顺序
- 在每个列表页内,
definePage宏必须排在最上面。不允许被修改位置。 - 不要影响
definePage宏的任何内容,不要影响其导入顺序。这不是你要处理的内容。
6.1. 错误的处理方式
这是你错误更改导入顺序的结果。
- 不可以把 definePage 宏放到 import 导入函数的下面。
ts
import { ref, computed } from "vue";
import { transformI18n } from "@/plugins/i18n";
import { getRouteRank } from "@/router/rank/getRouteRank";
import type { FieldValues, PlusColumn } from "plus-pro-components";
import type { TableColumns } from "@pureadmin/table";
import { defaultPureTableIndexColumn } from "@/config/constant";
import { useI18n } from "vue-i18n";
import { type MenuGroupListItem, type MenuGroupQueryParams, menuGroupStatusOptions } from "@01s-11comm/type";
import { useMenuGroupListQuery } from "@/api/dev-team/menu-manage/group";
definePage({
meta: {
title: "菜单组",
icon: "mdi:group",
roles: ["开发团队"],
rank: getRouteRank("devTeam.menuManage.group"),
},
});6.2. 正确的处理方式
- definePage 宏函数,在每个列表页内,永远在 import 导入函数之上。
ts
definePage({
meta: {
title: "菜单组",
icon: "mdi:group",
roles: ["开发团队"],
rank: getRouteRank("devTeam.menuManage.group"),
},
});
import { ref, computed } from "vue";
import { transformI18n } from "@/plugins/i18n";
import { getRouteRank } from "@/router/rank/getRouteRank";
import type { FieldValues, PlusColumn } from "plus-pro-components";
import type { TableColumns } from "@pureadmin/table";
import { defaultPureTableIndexColumn } from "@/config/constant";
import { useI18n } from "vue-i18n";
import { type MenuGroupListItem, type MenuGroupQueryParams, menuGroupStatusOptions } from "@01s-11comm/type";
import { useMenuGroupListQuery } from "@/api/dev-team/menu-manage/group";7. 表格列配置 columns 数组的类型约束,就是全局类型 TableColumnList ,不要换掉
不要换掉本来就使用好的 TableColumnList 类型约束,不要中途换成别的代码写法!这不是你本次任务的处理范畴,你不应该换掉这个全局类型。
7.1. 错误的代码写法
- 不要手动导入
TableColumns类型,把原来的全局类型TableColumnList换掉。你不应该去做这种类型替换。
ts
import type { TableColumns } from "@pureadmin/table";
/** 表格列配置 */
const columns = ref<TableColumns[]>([
// ...具体的表格列配置
]);7.2. 正确的代码写法
保持原样就可以了,不要添油加醋。TableColumnList 是全局类型,不是你要替换的业务类型!
ts
/** 表格列配置 */
const columns = ref<TableColumnList>([
// ...具体的表格列配置
]);8. 不要删掉本来就写好的全局类型约束 PureTableBarProps,保持原样即可
在列表页内,不要删掉本来就写好的全局类型约束 PureTableBarProps,保持原样即可。这不是你要删减替换的类型范围。
8.1. 错误的写法
- 删掉了本来就写好的,标准的类型约束
PureTableBarProps。
ts
/** 表格操作栏组件 配置 */
const pureTableBarProps = ref({
title: "菜单组",
columns: columns.value,
});8.2. 正确的写法
- 保留原样即可。
pureTableBarProps变量本来就是要写成ref对象的,而且类型约束就是全局类型PureTableBarProps。不要添油加醋。
ts
/** 表格操作栏组件 配置 */
const pureTableBarProps = ref<PureTableBarProps>({
title: "菜单组",
columns: columns.value,
});9. 不要增加本来就有的,definePage 宏专用的 getRouteRank 全局函数
不要添油加醋的增加多余的全局导入 getRouteRank 。这个函数不应该主动导入。
ts
// 不应该导入这个函数
import { getRouteRank } from "@/router/rank/getRouteRank";