chore: 完成多批次代码优化与重构

- 重构工作流模块目录结构,迁移代码文件
- 修复类型断言空值安全问题,添加 ! 操作符
- 优化样式类名,替换 flex-cc 为标准 flex 工具类
- 更新路由标签简化文案,移除冗余注释
- 调整 ruff 配置,放宽行长度限制
- 更新 README 与多语言文案,优化项目描述
- 修复表单、图表组件的类型与样式问题
- 简化搜索表单、数据卡片的布局代码
This commit is contained in:
zhangtao
2026-06-20 05:31:46 +08:00
parent 82b742620b
commit d34d4a4c50
378 changed files with 4149 additions and 6375 deletions
@@ -1,7 +1,7 @@
<!-- 示例 CRUD:与角色页同一套 Fa 布局;弹窗与 Crud 一致(FaDialog + crud-embed-dialog) -->
<template>
<div class="fa-full-height">
<FaSearchBarWithAudit
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -13,6 +13,7 @@
:show-search="true"
:disabled-search="false"
:default-expanded="false"
:include-audit="true"
@search="handleSearch"
@reset="onResetSearch"
/>
@@ -153,6 +154,7 @@
</template>
<script setup lang="ts">
import { h } from "vue";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@/utils/table";
import { useTable } from "@/hooks/core/useTable";
@@ -160,7 +162,7 @@ import { useImportExport } from "@/hooks/core/useImportExport";
import { useCrudDialog } from "@/hooks/core/useCrudDialog";
import { useTableSelection } from "@/hooks/core/useTableSelection";
import { confirmDelete, confirmBatchDelete, confirmAction } from "@/hooks/core/useConfirm";
import { cleanEmptyArrayParams, stripPaginationParams } from "@/utils/query";
import { stripPaginationParams } from "@/utils/query";
import type { IContentConfig, IObject } from "@/components/modal/types";
import type { AuditSearchFormParams } from "@/components/forms/fa-search-bar/auditSearchFormItems";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
@@ -172,7 +174,7 @@ import DemoAPI, {
type DemoTable,
} from "@/api/module_example/demo";
import { ResultEnum } from "@/enums/api/result.enum";
import { ElTag, ElMessage } from "element-plus";
import { ElMessage } from "element-plus";
defineOptions({
name: "Demo",
@@ -181,18 +183,34 @@ defineOptions({
const { hasAuth } = useAuth();
type DemoSearchFormParams = { name?: string; status?: string } & AuditSearchFormParams;
// 常量定义
const STATUS_OPTIONS = [
{ label: "启用", value: 0 },
{ label: "停用", value: 1 },
] as const;
function normalizeDemoQuery(params: Record<string, unknown>): DemoPageQuery {
return cleanEmptyArrayParams({ ...params }, [
"created_time",
"updated_time",
]) as unknown as DemoPageQuery;
}
const createInitialFormData = (): DemoForm => ({
id: undefined,
name: "",
status: 0,
description: undefined,
int_val: undefined,
bigint_val: undefined,
float_val: undefined,
bool_val: true,
date_val: undefined,
time_val: undefined,
datetime_val: undefined,
text_val: undefined,
json_val: undefined,
});
type DemoSearchFormParams = { name?: string; status?: number; tenant_id?: number } & AuditSearchFormParams;
const searchForm = ref<DemoSearchFormParams>({
name: undefined,
status: undefined,
tenant_id: undefined,
created_id: undefined,
updated_id: undefined,
created_time: [],
@@ -204,11 +222,8 @@ const showSearchBar = ref(true);
const searchBarRef = ref<{ validate: () => Promise<boolean> } | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
{ label: "启用", value: 0 },
{ label: "停用", value: 1 },
]);
/** 名称、状态;创建人/更新人/时间由 FaSearchBarWithAudit 追加 */
/** 名称、状态;创建人/更新人/时间由 FaSearchBar 的 includeAudit 属性追加 */
const demoBusinessSearchItems = computed(() => [
{
label: "名称",
@@ -224,7 +239,7 @@ const demoBusinessSearchItems = computed(() => [
type: "select",
props: {
placeholder: "请选择状态",
options: statusOptions.value,
options: STATUS_OPTIONS,
clearable: true,
},
span: 6,
@@ -268,12 +283,9 @@ const {
prop: "status",
label: "状态",
width: 88,
formatter: (row: DemoTable) => {
const ok = row.status === 0;
const cfg = ok
? { type: "success" as const, text: "启用" }
: { type: "info" as const, text: "停用" };
return h(ElTag, { type: cfg.type }, () => cfg.text);
status: {
0: { type: "success", text: "启用" },
1: { type: "info", text: "停用" },
},
},
{ prop: "int_val", label: "整数", minWidth: 88, showOverflowTooltip: true },
@@ -283,10 +295,10 @@ const {
prop: "bool_val",
label: "布尔",
width: 80,
formatter: (row: DemoTable) =>
h(ElTag, { type: row.bool_val ? "success" : "danger" }, () =>
row.bool_val ? "是" : "否"
),
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{ prop: "date_val", label: "日期", minWidth: 112, showOverflowTooltip: true },
{ prop: "time_val", label: "时间", minWidth: 96, showOverflowTooltip: true },
@@ -342,8 +354,7 @@ const demoCrudCols = computed(() =>
);
const exportQueryParams = computed(() => {
const sp = stripPaginationParams(searchParams as Record<string, unknown>);
return normalizeDemoQuery(sp);
return stripPaginationParams(searchParams as Record<string, unknown>);
});
const demoImportContentConfig = computed<IContentConfig>(() => ({
@@ -357,11 +368,11 @@ const demoExportContentConfig = computed(() => ({
permPrefix: "module_example:demo",
cols: demoCrudCols.value,
exportsBlobAction: async (params: IObject) => {
const merged = normalizeDemoQuery({
const merged = {
...(exportQueryParams.value as unknown as Record<string, unknown>),
...params,
} as Record<string, unknown>);
const res = await DemoAPI.exportDemo(merged as DemoPageQuery);
} as unknown as DemoPageQuery;
const res = await DemoAPI.exportDemo(merged);
return res.data as Blob;
},
}));
@@ -474,21 +485,7 @@ const demoDialogFormItems: FormItem[] = [
{ key: "json_val", label: "元数据", type: "input" /* 由 #json_val 插槽接管 */ },
];
const formData = ref<DemoForm>({
id: undefined,
name: "",
status: 0,
description: undefined,
int_val: undefined,
bigint_val: undefined,
float_val: undefined,
bool_val: true,
date_val: undefined,
time_val: undefined,
datetime_val: undefined,
text_val: undefined,
json_val: undefined,
});
const formData = ref<DemoForm>(createInitialFormData());
const rules = reactive({
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
@@ -506,27 +503,12 @@ const metadataList = ref<{ key: string; value: string }[]>([]);
const { importVisible, exportVisible, openImport, openExport } = useImportExport();
const initialFormData: DemoForm = {
id: undefined,
name: "",
status: 0,
description: undefined,
int_val: undefined,
bigint_val: undefined,
float_val: undefined,
bool_val: true,
date_val: undefined,
time_val: undefined,
datetime_val: undefined,
text_val: undefined,
json_val: undefined,
};
const handleSearch = async (params: DemoSearchFormParams) => {
await searchBarRef.value?.validate();
replaceSearchParams({
name: params.name,
status: params.status,
tenant_id: params.tenant_id,
created_id: params.created_id ?? undefined,
updated_id: params.updated_id ?? undefined,
created_time:
@@ -545,6 +527,7 @@ const onResetSearch = async () => {
searchForm.value = {
name: undefined,
status: undefined,
tenant_id: undefined,
created_id: undefined,
updated_id: undefined,
created_time: [],
@@ -600,8 +583,8 @@ async function openDetailDialog(row: DemoTable) {
async function openEditDialog(type: "add" | "edit", row?: DemoTable) {
dialogVisible.type = type === "add" ? "create" : "update";
if (type === "add") {
dialogVisible.title = "新增示例";
Object.assign(formData.value, initialFormData);
dialogVisible.title = "新增";
Object.assign(formData.value, createInitialFormData());
formData.value.id = undefined;
metadataList.value = [];
demoFormRenderKey.value += 1;
@@ -627,7 +610,7 @@ async function resetForm() {
dataFormRef.value.resetFields();
dataFormRef.value.clearValidate();
}
Object.assign(formData.value, initialFormData);
Object.assign(formData.value, createInitialFormData());
metadataList.value = [];
}