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
@@ -81,15 +81,19 @@
:scrollbar="false"
>
<template #type="{ row }">
<ElTag v-if="row?.type === MenuTypeEnum.CATALOG" type="warning">目录</ElTag>
<ElTag v-if="row?.type === MenuTypeEnum.MENU" type="success">菜单</ElTag>
<ElTag v-if="row?.type === MenuTypeEnum.BUTTON" type="danger">按钮</ElTag>
<ElTag v-if="row?.type === MenuTypeEnum.EXTLINK" type="info">外链</ElTag>
<FaStatusTag v-if="row?.type === MenuTypeEnum.CATALOG" type="warning" label="目录" />
<FaStatusTag v-if="row?.type === MenuTypeEnum.MENU" type="success" label="菜单" />
<FaStatusTag v-if="row?.type === MenuTypeEnum.BUTTON" type="danger" label="按钮" />
<FaStatusTag v-if="row?.type === MenuTypeEnum.EXTLINK" type="info" label="外链" />
</template>
<template #client="{ row }">
<ElTag v-if="row?.client === MenuClientEnum.PC" type="primary">PC</ElTag>
<ElTag v-else-if="row?.client === MenuClientEnum.APP" type="success">APP</ElTag>
<ElTag v-else type="info">{{ row?.client || "—" }}</ElTag>
<FaStatusTag v-if="row?.client === MenuClientEnum.PC" type="primary" label="PC" />
<FaStatusTag
v-else-if="row?.client === MenuClientEnum.APP"
type="success"
label="APP"
/>
<FaStatusTag v-else type="info" :label="(row as unknown as MenuTable)?.client || '—'" />
</template>
<template #icon="{ row }">
<template v-if="row?.icon">
@@ -332,6 +336,7 @@
</template>
<script setup lang="ts">
import { h } from "vue";
defineOptions({
name: "SysMenu",
inheritAttrs: false,
@@ -349,13 +354,13 @@ import MenuAPI, {
import { MenuClientEnum, MenuTypeEnum } from "@/enums/system/menu.enum";
import { formatTree } from "@utils/common";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils";
import { renderTableOperationCell, type TableOperationAction, resolveStatusColumns } from "@utils";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import type FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import FaMenuRouteIcon from "@/components/others/fa-menu-routeIcon/index.vue";
import { ElTag, ElMessage, ElMessageBox } from "element-plus";
import type FaForm from "@/components/forms/fa-form/index.vue";
import FaMenuRouteIcon from "@/components/others/fa-menu-route-icon/index.vue";
import { ElMessage, ElMessageBox } from "element-plus";
const { hasAuth } = useAuth();
const appStore = useAppStore();
@@ -363,7 +368,7 @@ const userStore = useUserStore();
type MenuSearchForm = {
name?: string;
status?: string;
status?: number;
created_time?: string[];
};
@@ -376,25 +381,6 @@ function buildMenuListQuery(p: MenuSearchForm): MenuPageQuery {
};
}
function menuTypeTag(row: MenuTable) {
const t = row.type;
if (t === MenuTypeEnum.CATALOG) return h(ElTag, { type: "warning" }, () => "目录");
if (t === MenuTypeEnum.MENU) return h(ElTag, { type: "success" }, () => "菜单");
if (t === MenuTypeEnum.BUTTON) return h(ElTag, { type: "danger" }, () => "按钮");
if (t === MenuTypeEnum.EXTLINK) return h(ElTag, { type: "info" }, () => "外链");
return h("span", "—");
}
function menuClientTag(row: MenuTable) {
if (row.client === MenuClientEnum.PC) return h(ElTag, { type: "primary" }, () => "PC");
if (row.client === MenuClientEnum.APP) return h(ElTag, { type: "success" }, () => "APP");
return h(ElTag, { type: "info" }, () => String(row.client ?? "—"));
}
function ynTag(v: boolean | undefined, yes = "是", no = "否") {
return h(ElTag, { type: v ? "success" : "danger" }, () => (v ? yes : no));
}
function buildMenuRowActions(
row: MenuTable,
ctx: {
@@ -885,118 +871,159 @@ const opCtx = {
onDelete: deleteMenuRow,
};
const { columnChecks, columns } = useTableColumns<MenuTable>(() => [
{ type: "selection", width: 48, fixed: "left" },
{ type: "index", label: "序号", width: 60, fixed: "left" },
{ prop: "name", label: "菜单名称", minWidth: 200, showOverflowTooltip: true },
{
prop: "icon",
label: "图标",
width: 72,
align: "center",
formatter: (row: MenuTable) =>
row.icon
? h(FaMenuRouteIcon, { icon: row.icon, style: { verticalAlign: "-0.15em" } })
: h("span", { class: "text-g-400" }, "—"),
},
{
prop: "status",
label: "状态",
width: 88,
formatter: (row: MenuTable) =>
h(ElTag, { type: row.status === 0 ? "success" : "danger" }, () =>
row.status === 0 ? "启用" : "停用"
),
},
{ prop: "type", label: "类型", width: 88, align: "center", formatter: menuTypeTag },
{ prop: "client", label: "终端", width: 88, align: "center", formatter: menuClientTag },
{
prop: "scope",
label: "可见范围",
width: 96,
align: "center",
formatter: (row: MenuTable) =>
row.scope
? h(ElTag, { type: row.scope === "platform" ? "warning" : "success" }, () =>
row.scope === "platform" ? "仅平台" : "租户可用"
)
: h("span", { class: "text-g-400" }, "—"),
},
{ prop: "order", label: "排序", width: 80 },
{ prop: "route_name", label: "路由名称", minWidth: 100, showOverflowTooltip: true },
{ prop: "route_path", label: "路由路径", minWidth: 140, showOverflowTooltip: true },
{ prop: "permission", label: "权限标识", minWidth: 160, showOverflowTooltip: true },
{ prop: "component_path", label: "组件路径", minWidth: 140, showOverflowTooltip: true },
{ prop: "active_path", label: "激活路径", minWidth: 100, showOverflowTooltip: true },
{ prop: "redirect", label: "重定向", minWidth: 100, showOverflowTooltip: true },
{ prop: "link", label: "外链地址", minWidth: 140, showOverflowTooltip: true },
{
prop: "keep_alive",
label: "是否缓存",
width: 96,
formatter: (row: MenuTable) => ynTag(row.keep_alive),
},
{
prop: "hidden",
label: "是否隐藏",
width: 96,
formatter: (row: MenuTable) => ynTag(row.hidden),
},
{
prop: "always_show",
label: "显示根路由",
width: 108,
formatter: (row: MenuTable) => ynTag(row.always_show),
},
{
prop: "affix",
label: "固定路由",
width: 96,
formatter: (row: MenuTable) => ynTag(row.affix),
},
{ prop: "title", label: "菜单标题", minWidth: 100, showOverflowTooltip: true },
{
prop: "is_iframe",
label: "嵌入iframe",
width: 100,
formatter: (row: MenuTable) => ynTag(row.is_iframe),
},
{
prop: "is_hide_tab",
label: "隐藏标签页",
width: 100,
formatter: (row: MenuTable) => ynTag(row.is_hide_tab),
},
{
prop: "show_badge",
label: "红点角标",
width: 96,
formatter: (row: MenuTable) => ynTag(row.show_badge),
},
{ prop: "show_text_badge", label: "文字角标", width: 100, showOverflowTooltip: true },
{
prop: "params",
label: "路由参数",
minWidth: 100,
formatter: (row: MenuTable) =>
row.params == null
? "—"
: typeof row.params === "object"
? JSON.stringify(row.params)
: String(row.params),
},
{ prop: "description", label: "描述", minWidth: 140, showOverflowTooltip: true },
{ prop: "created_time", label: "创建时间", width: 168, showOverflowTooltip: true },
{ prop: "updated_time", label: "更新时间", width: 168, showOverflowTooltip: true },
{
prop: "operation",
label: "操作",
width: 220,
fixed: "right",
align: "right",
formatter: (row: MenuTable) => formatMenuOperationCell(row, opCtx),
},
]);
const { columnChecks, columns } = useTableColumns<MenuTable>(
resolveStatusColumns(() => [
{ type: "selection", width: 48, fixed: "left" },
{ type: "index", label: "序号", width: 60, fixed: "left" },
{ prop: "name", label: "菜单名称", minWidth: 200, showOverflowTooltip: true },
{
prop: "icon",
label: "图标",
width: 72,
align: "center",
formatter: (row: MenuTable) =>
row.icon
? h(FaMenuRouteIcon, { icon: row.icon, style: { verticalAlign: "-0.15em" } })
: h("span", { class: "text-g-400" }, "—"),
},
{
prop: "status",
label: "状态",
width: 88,
status: {
0: { type: "success", text: "启用" },
1: { type: "danger", text: "停用" },
},
},
{
prop: "type",
label: "类型",
width: 88,
align: "center",
status: {
1: { type: "warning", text: "目录" },
2: { type: "success", text: "菜单" },
3: { type: "danger", text: "按钮" },
4: { type: "info", text: "外链" },
},
},
{
prop: "client",
label: "终端",
width: 88,
align: "center",
status: {
pc: { type: "primary", text: "PC" },
app: { type: "success", text: "APP" },
},
},
{
prop: "scope",
label: "可见范围",
width: 96,
align: "center",
status: {
platform: { type: "warning", text: "仅平台" },
tenant: { type: "success", text: "租户可用" },
},
},
{ prop: "order", label: "排序", width: 80 },
{ prop: "route_name", label: "路由名称", minWidth: 100, showOverflowTooltip: true },
{ prop: "route_path", label: "路由路径", minWidth: 140, showOverflowTooltip: true },
{ prop: "permission", label: "权限标识", minWidth: 160, showOverflowTooltip: true },
{ prop: "component_path", label: "组件路径", minWidth: 140, showOverflowTooltip: true },
{ prop: "active_path", label: "激活路径", minWidth: 100, showOverflowTooltip: true },
{ prop: "redirect", label: "重定向", minWidth: 100, showOverflowTooltip: true },
{ prop: "link", label: "外链地址", minWidth: 140, showOverflowTooltip: true },
{
prop: "keep_alive",
label: "是否缓存",
width: 96,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{
prop: "hidden",
label: "是否隐藏",
width: 96,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{
prop: "always_show",
label: "显示根路由",
width: 108,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{
prop: "affix",
label: "固定路由",
width: 96,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{ prop: "title", label: "菜单标题", minWidth: 100, showOverflowTooltip: true },
{
prop: "is_iframe",
label: "嵌入iframe",
width: 100,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{
prop: "is_hide_tab",
label: "隐藏标签页",
width: 100,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{
prop: "show_badge",
label: "红点角标",
width: 96,
status: {
true: { type: "success", text: "是" },
false: { type: "danger", text: "否" },
},
},
{ prop: "show_text_badge", label: "文字角标", width: 100, showOverflowTooltip: true },
{
prop: "params",
label: "路由参数",
minWidth: 100,
formatter: (row: MenuTable) =>
row.params == null
? "—"
: typeof row.params === "object"
? JSON.stringify(row.params)
: String(row.params),
},
{ prop: "description", label: "描述", minWidth: 140, showOverflowTooltip: true },
{ prop: "created_time", label: "创建时间", width: 168, showOverflowTooltip: true },
{ prop: "updated_time", label: "更新时间", width: 168, showOverflowTooltip: true },
{
prop: "operation",
label: "操作",
width: 220,
fixed: "right",
align: "right",
formatter: (row: MenuTable) => formatMenuOperationCell(row, opCtx),
},
])
);
const rules = reactive({
name: [