refactor: 将组件前缀从Art统一替换为Fa

- 更新所有FA前缀的组件文件
- 新增Fa前缀的对应组件
- 更新所有引用路径和组件名
- 修改相关样式和变量名
- 调整部分组件目录结构
This commit is contained in:
zhangtao
2026-05-11 09:23:31 +08:00
parent 68b50359c5
commit 03a8151513
185 changed files with 2912 additions and 1283 deletions
+2 -2
View File
@@ -263,8 +263,8 @@ import { Camera } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n";
import { redirectToLogin } from "@utils/auth";
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import ArtCutterImg from "@/components/Core/media/art-cutter-img/index.vue";
import ArtSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import ArtCutterImg from "@/components/media/fa-cutter-img/index.vue";
import { dataURLToFile } from "@utils/file/dataUrl";
defineOptions({ name: "UserProfile" });
@@ -6,7 +6,7 @@
</div>
</div>
<div class="overflow-auto h-full">
<ArtTable
<FaTable
:data="products"
style="width: 100%"
size="large"
@@ -41,7 +41,7 @@
</span>
</template>
</ElTableColumn>
</ArtTable>
</FaTable>
</div>
</div>
</template>
@@ -14,7 +14,7 @@
<ElRadioButton value="今年" label="今年"></ElRadioButton>
</ElRadioGroup>
</div>
<ArtTable
<FaTable
class="w-full"
:data="tableData"
style="width: 100%"
@@ -51,7 +51,7 @@
</template>
</ElTableColumn>
</template>
</ArtTable>
</FaTable>
</div>
</template>
@@ -8,7 +8,7 @@
</div>
<ElScrollbar style="height: 21.55rem" class="w-full">
<ArtTable
<FaTable
:data="tableData"
style="margin-top: 0 !important"
:border="false"
@@ -49,7 +49,7 @@
</template>
</ElTableColumn>
</template>
</ArtTable>
</FaTable>
</ElScrollbar>
</div>
</template>
+4 -4
View File
@@ -149,7 +149,7 @@
class="workplace-quick-row__icon"
:style="{ color: getQuickLinkColor(getQuickLinkStableIndex(item)) }"
>
<MenuRouteIcon :icon="item.icon || 'menu'" />
<FaMenuRouteIcon :icon="item.icon || 'menu'" />
</div>
<div class="workplace-quick-row__text">
<span class="workplace-quick-row__title">{{ item.title }}</span>
@@ -348,7 +348,7 @@
</div>
</template>
<div class="workplace-ops-card__body workplace-ops-card__body--calendar">
<Calendar />
<FaCalendar />
</div>
</ElCard>
</ElCol>
@@ -364,8 +364,8 @@ defineOptions({
});
import { useUserStore } from "@stores/index";
import MenuRouteIcon from "@/components/MenuRouteIcon/index.vue";
import Calendar from "@/components/Calendar/index.vue";
import FaMenuRouteIcon from "@/components/others/fa-menu-routeIcon/index.vue";
import FaCalendar from "@/components/others/fa-calendar/index.vue";
import { greetings } from "@utils/common";
import type { MenuTable } from "@/api/module_system/menu";
import { ref, onMounted, onUnmounted, computed } from "vue";
@@ -14,6 +14,6 @@ defineOptions({ name: "DashboardMap" });
* 减少初始加载体积
*/
const ArtMapChart = defineAsyncComponent(
() => import("@/components/Core/charts/art-map-chart/index.vue")
() => import("@/components/charts/fa-map-chart/index.vue")
);
</script>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,574 @@
/**
* 功能验收手册:除「用户 / 角色」在 `index.vue` 中详述外,其余页用「完整性验收」结构展示。
*
* **何为完整性**:`notes` 与当前页**已实现**的界面与操作项对应,用于验收时逐条核对**是否漏项**(不评价交互好坏)。
* **与后端菜单对齐**:标题与 `sys_menu.json` 中菜单页 `component_path` 一致;壳层/静态页见各条说明。
* **`path` 字段**:默认可视为 `src/views/` 下相对路径;`../layouts` 与 `locales` 等见各条。
*/
export type CompactManualPage = {
anchor: string;
title: string;
path: string;
notes: string[];
};
export type ManualModuleSection = {
anchor: string;
heading: string;
pkgTag?: string;
pages: CompactManualPage[];
};
/** 系统管理模块内、接在「角色管理」后的页面 */
export const MANUAL_SYSTEM_TAIL_PAGES: CompactManualPage[] = [
{
anchor: "page-menu",
title: "菜单管理",
path: "module_system/menu/index.vue",
notes: [
"检索:FaSearchBar(菜单名称等)。",
"分区:Tab「PC 桌面菜单管理 / APP 移动端菜单管理」两套树数据。",
"主区:树形表格(勾选、行点击);展开/收起工具按钮。",
"工具栏:新增、批量删除、批量更多(patch)、刷新、列配置、显示搜索栏。",
"弹层:详情 Descriptions;新增/编辑 Drawer(目录 / 菜单 / 按钮 / 外链等类型与路由、图标、权限标识)。",
"权限:`module_system:menu:create|delete|patch` + 行级 detail/update/delete。",
],
},
{
anchor: "page-dept",
title: "部门管理",
path: "module_system/dept/index.vue",
notes: [
"检索:FaSearchBar。",
"主区:树形表格(勾选);展开/收起。",
"工具栏:新增、批量删除、批量更多(patch)、刷新、列配置、搜索栏切换。",
"弹层:详情;新增/编辑 Dialog(名称、编码、上级、状态等)。",
"权限:`module_system:dept:create|delete|patch` + 行 detail/update/delete。",
],
},
{
anchor: "page-position",
title: "岗位管理",
path: "module_system/position/index.vue",
notes: [
"检索:FaSearchBar(含创建人 UserTableSelect 槽)。",
"主区:分页表格。",
"工具栏:新增、导出、批量删除、批量更多(patch)、刷新、列配置。",
"弹层:详情;新增/编辑 Dialog;导出 FaExportDialog。",
"权限:`module_system:position:create|export|delete|patch` + 行 detail/update/delete。",
],
},
{
anchor: "page-dict",
title: "字典管理",
path: "module_system/dict/index.vue",
notes: [
"检索:字典类型 FaSearchBar + 分页表。",
"工具栏:新增类型、导出类型、批量删除、批量更多(patch)、刷新、列配置。",
"类型弹层:详情 / 新增编辑 Dialog。",
"子层:`DataDrawer` 维护某字典类型下的字典数据项(二级)。",
"权限:`module_system:dict_type:*` 与字典数据接口权限(见行内按钮)。",
],
},
{
anchor: "page-param",
title: "参数配置",
path: "module_system/param/index.vue",
notes: [
"检索:FaSearchBar + 分页表。",
"工具栏:新增、导出、批量删除、刷新、列配置(无 patch 批量入口)。",
"弹层:详情;新增/编辑 Dialog;内置参数标识与表单校验。",
"权限:`module_system:param:create|export|delete` + 行级权限。",
],
},
{
anchor: "page-notice",
title: "通知公告",
path: "module_system/notice/index.vue",
notes: [
"检索:FaSearchBar(含创建人 UserTableSelect)。",
"工具栏:新增、导出、批量删除、批量更多(patch)、刷新、列配置。",
"弹层:详情;新增/编辑 Dialog;正文为富文本 `ArtWangEditor`;HTML 预览。",
"权限:`module_system:notice:create|export|delete|patch` + 行级操作。",
],
},
{
anchor: "page-tenant",
title: "租户管理",
path: "module_system/tenant/index.vue",
notes: [
"检索:FaSearchBar + 分页表。",
"工具栏:新增、批量删除、刷新、列配置(无导出/更多 patch 于顶栏)。",
"弹层:详情;新增/编辑 Dialog(名称、编码、起止时间、状态、描述等)。",
"权限:`module_system:tenant:create|delete` + 行级 update/detail/delete。",
],
},
{
anchor: "page-log",
title: "操作日志",
path: "module_system/log/index.vue",
notes: [
"检索:FaSearchBar(含创建人 UserTableSelect);登录/操作日志类型在列或详情中区分。",
"工具栏:导出、批量删除、刷新、列配置(无新增)。",
"弹层:详情 Dialog(请求路径/方法、IP、状态码、耗时、入参出参等大字段)。",
"权限:`module_system:log:export|delete` + 行级查看/删除。",
],
},
{
anchor: "page-login",
title: "登录页",
path: "module_system/auth/login/index.vue",
notes: [
"面板切换:登录 / 注册 / 忘记密码(`setAuthPanel`)。",
"登录:账号表单;验证码;记住我;登录成功后 `redirect` 解析跳转。",
"静态路由:`/login`;与路由守卫白名单一致。",
"其他:注册与忘记密码提交接口;左侧背景与主题组件(视模板)。",
],
},
];
export const MANUAL_MODULES_AFTER_SYSTEM: ManualModuleSection[] = [
{
anchor: "mod-monitor",
heading: "二、监控管理",
pkgTag: "module_monitor",
pages: [
{
anchor: "page-online",
title: "在线用户",
path: "module_monitor/online/index.vue",
notes: [
"检索:FaSearchBar(IP、用户名、登录地点等)。",
"工具栏:「强退所有」(权限 `module_monitor:online:delete`);刷新、列配置、搜索栏。",
"行操作:单条会话「强退」。",
"主区:分页表格(session_id 等列);无批量勾选删除入口(仅有单条强退)。",
],
},
{
anchor: "page-cache",
title: "缓存管理",
path: "module_monitor/cache/index.vue",
notes: [
"Tab「监控信息」:Redis 监控指标 Descriptions(版本、内存、CPU、Key 数量等)。",
"Tab「缓存管理」:缓存列表/键值查看与按规则清理(与后端接口一致)。",
"完整性:两 Tab 均需点开核对是否加载成功、清理是否有二次确认。",
],
},
{
anchor: "page-resource",
title: "文件管理",
path: "module_monitor/resource/index.vue",
notes: [
"检索:FaSearchBar;路径面包屑导航进入子目录。",
"工具栏:上传、新建文件夹、下载、删除等(`module_monitor:resource:*` 按钮权限);刷新、列配置。",
"主区:文件表格;与后端资源浏览一致(菜单名「文件管理」,component `resource`)。",
],
},
{
anchor: "page-server",
title: "服务监控",
path: "module_monitor/server/index.vue",
notes: [
"布局:多卡片 Dashboard(CPU、内存、磁盘、JVM/服务器信息等,依接口返回)。",
"完整性:各卡片指标是否有数值;加载失败时占位或提示。",
],
},
],
},
{
anchor: "mod-task",
heading: "三、任务管理",
pkgTag: "module_task",
pages: [
{
anchor: "page-cronjob",
title: "调度器监控",
path: "module_task/cronjob/job/index.vue",
notes: [
"顶部状态区:调度器运行状态、任务数量;按钮:启动/暂停/恢复/关闭/清空任务/控制台/同步/刷新(各 `module_task:cronjob:job:*`)。",
"主区:任务卡片列表 — `getSchedulerJobs` 全量返回,名称与任务状态为前端筛选;单卡触发类型(Cron/间隔等)与暂停、恢复、调试、移除等行操作。",
"抽屉:当前任务的执行日志 — `useTable` + `getJobLogList` 分页,日志检索栏,批量删日志等(见页面)。",
],
},
{
anchor: "page-cronnode",
title: "节点管理",
path: "module_task/cronjob/node/index.vue",
notes: [
"检索:FaSearchBar + 分页表。",
"工具栏:新增、批量删除、刷新、列配置。",
"弹层:FaDialog + 分栏(表单 + 扩展配置区);编辑节点连接与执行参数。",
"权限:`module_task:cronjob:node:create|delete` + 行级 update/detail/delete。",
],
},
{
anchor: "page-workflow",
title: "流程编排",
path: "module_task/workflow/definition/index.vue",
notes: [
"检索:FaSearchBar(可展开)。",
"工具栏:新增、批量删除、刷新、列配置。",
"行操作:草稿「发布」;已发布「执行」下拉;「编辑」打开 `WorkflowDesignDrawer` 画布;删除。",
"权限:`module_task:workflow:definition:create|delete|update|execute` 等(见行内 v-hasPerm)。",
],
},
{
anchor: "page-nodetype",
title: "编排节点类型",
path: "module_task/workflow/node-type/index.vue",
notes: [
"检索:FaSearchBar(可展开)。",
"工具栏:新增、批量删除、刷新、列配置。",
"行操作:编辑(打开表单/脚本配置)、删除等(见 `node-type-operation` 槽)。",
"权限:`module_task:workflow:node-type:create|delete|update` + 行级操作。",
],
},
],
},
{
anchor: "mod-ai",
heading: "四、AI 模块",
pkgTag: "module_ai",
pages: [
{
anchor: "page-ai-chat",
title: "AI智能助手",
path: "module_ai/chat/index.vue",
notes: [
"布局:左侧 `Sidebar`(会话列表、新建会话);右侧 `ChatNavbar` + `ChatMessages` + `ChatInput`。",
"连接:`toggleConnection`、连接状态展示;清空对话、侧栏折叠。",
"完整性:发消息、收消息列表滚动、错误条展示与关闭;流式与否依赖后端/WebSocket 对接。",
],
},
{
anchor: "page-ai-fachat",
title: "会话聊天",
path: "module_ai/fachat/index.vue",
notes: [
"布局:左侧联系人列表(搜索、排序下拉、在线点);右侧头部「Art Bot」状态与语音/视频等图标按钮;中部消息气泡列表;底部输入框与发送。",
"完整性:选人切换会话、发送消息、滚动消息区;当前多为演示数据与本地发送逻辑。",
],
},
{
anchor: "page-ai-memory",
title: "会话记忆",
path: "module_ai/memory/index.vue",
notes: [
"检索:FaSearchBar + 分页表。",
"工具栏:新增、批量删除、刷新、列配置;权限锚点 `module_ai:chat:create|delete`(与后端标识一致)。",
"弹层:详情与表单 Drawer(会话记忆字段);完整性:CRUD 与分页均需验证。",
],
},
],
},
{
anchor: "mod-generator",
heading: "五、代码生成器",
pkgTag: "module_generator",
pages: [
{
anchor: "page-gencode",
title: "代码生成",
path: "module_generator/gencode/index.vue",
notes: [
"检索:FaSearchBar + 库表分页列表;勾选表格行。",
"工具栏:创建表、导入库表、批量删除、批量生成(`module_generator:gencode:*`)。",
"弹层:`CreateTableDialog`、导入 DB、`GenCodeDrawer` 多步(导入字段、生成配置、预览代码)。",
"完整性:预览、下载 zip、生成到磁盘等按钮是否随权限显示且可点。",
],
},
],
},
{
anchor: "mod-app",
heading: "六、应用管理",
pkgTag: "module_application",
pages: [
{
anchor: "page-portal",
title: "插件市场",
path: "module_application/portal/index.vue",
notes: [
"检索:FaSearchBar(含创建人、更新人 UserTableSelect)。",
"工具栏:标题「应用市场」+「创建应用」(`module_application:portal:create`);刷新、搜索栏。",
"主区:卡片网格(图标、名称、状态、描述);卡片脚编辑/删除(update/delete);底部分页器。",
"完整性:空列表 ElEmpty;卡片点击进入内部打开逻辑(见 `openAppInternal`)。",
],
},
],
},
{
anchor: "mod-example",
heading: "七、示例模块",
pkgTag: "module_example",
pages: [
{
anchor: "page-demo",
title: "示例管理",
path: "module_example/demo/index.vue",
notes: [
"标准列表 CRUD 示例页:检索、分页表、工具栏、行操作、弹窗表单(与本项目其它模块同一套 Art 组件)。",
"完整性:按页面可见按钮与表单字段逐项点验即可。",
],
},
{
anchor: "page-demo01",
title: "三级菜单",
path: "module_example/demo01/index.vue",
notes: [
"占位或简单展示的叶子页,用于验证多级菜单路由与 KeepAlive。",
"完整性:侧栏进入后路由正确、页面无报错即可。",
],
},
],
},
{
anchor: "mod-dashboard",
heading: "八、仪表盘",
pkgTag: "dashboard",
pages: [
{
anchor: "page-home",
title: "首页",
path: "dashboard/index.vue",
notes: [
"路由 `/home`:样式类 `workplace-page` — 问候与用户信息卡片、模块入口网格(按权限灰显)、其它工作台分区(与文件内组件一致)。",
"完整性:模块卡片点击跳转、无权限入口禁用或提示;接口失败时有容错。",
],
},
{
anchor: "page-profile",
title: "个人中心",
path: "current/profile.vue",
notes: [
"路由 `/profile`;左侧头像上传(ElUpload)、资料展示;右侧「基本设置」表单与「更改密码」三块。",
"完整性:保存基本信息、修改密码、头像上传回调与校验均已接线。",
],
},
{
anchor: "page-changelog",
title: "更新日志",
path: "changelog/index.vue",
notes: [
"静态路由 `/changelog`;列表遍历 mock `upgradeLogList`(版本、日期、明细、备注、需重登标签)。",
"另有 `module_system/changelog` 视图未挂路由;完整性以本页为准。",
],
},
{
anchor: "page-db-workplace",
title: "工作台",
path: "dashboard/workplace/index.vue",
notes: [
"仪表盘子路由 `dashboard/workplace`:独立 `dashboard-container` 布局(含 Github 角标、问候区、天气文案、统计卡片与图表等,以页面为准)。",
"与 `/home` 所用 `dashboard/index.vue` 不是同一文件;完整性需单独打开该路由逐项看区块是否渲染。",
],
},
{
anchor: "page-db-console",
title: "控制台",
path: "dashboard/console/index.vue",
notes: [
"控制台仪表盘分区(卡片/图表);meta.fixedTab 等影响标签钉扎行为。",
"完整性:各区块渲染与路由切换无报错。",
],
},
{
anchor: "page-db-analysis",
title: "分析页",
path: "dashboard/analysis/index.vue",
notes: ["图表与卡片布局演示页;完整性:各图表组件 mount 成功、无控制台报错。"],
},
{
anchor: "page-db-ecommerce",
title: "电子商务",
path: "dashboard/ecommerce/index.vue",
notes: ["电商风格区块演示;完整性:列表/卡片区块均可滚动与展示。"],
},
{
anchor: "page-db-map",
title: "地图",
path: "dashboard/map/index.vue",
notes: ["地图 SDK 示例;完整性:地图实例初始化、标记与交互事件可用。"],
},
{
anchor: "page-db-pricing",
title: "定价",
path: "dashboard/pricing/index.vue",
notes: ["定价页模板;完整性:价格表、按钮或跳转链接展示齐全。"],
},
{
anchor: "page-db-article",
title: "文章管理",
path: "dashboard/article/list/index.vue",
notes: [
"文章列表(当前多为 mock `ArticleList`);路由 path `dashboard/article/article-list`。",
"meta.authList:新增/编辑类权限标记;完整性:列表、分页、抽屉或编辑入口覆盖文章 CRUD 流程。",
],
},
{
anchor: "page-db-tutorial",
title: "教程",
path: "dashboard/tutorial/index.vue",
notes: [
"视频 Tab + 功能验收 Tab;正文含用户/角色详述与其余模块完整性清单。",
"完整性:目录筛选、锚点滚动、手册内链跳转可用。",
],
},
],
},
{
anchor: "mod-layout",
heading: "九、布局与通用功能",
pkgTag: "layouts",
pages: [
{
anchor: "layout-main",
title: "主布局",
path: "../layouts/index.vue",
notes: [
"RootLayout:嵌套 RouterView;组合侧栏、顶栏、工作区、设置抽屉等子布局组件。",
"完整性:登录后进主壳、子路由 outlet 渲染、响应式收缩侧栏。",
],
},
{
anchor: "layout-sidebar",
title: "侧栏菜单",
path: "../layouts/fa-menus/**",
notes: ["菜单折叠、搜索、递归子菜单;与路由 meta.icon/title 绑定。"],
},
{
anchor: "layout-header",
title: "顶栏",
path: "../layouts/fa-header-bar/**",
notes: ["面包屑、快速入口、全屏、通知铃铛区域。"],
},
{
anchor: "layout-worktab",
title: "标签页",
path: "../layouts/fa-work-tab/**",
notes: ["多标签打开、固定钉住、关闭其他;与 keep-alive 协同。"],
},
{
anchor: "layout-settings",
title: "设置面板",
path: "../layouts/fa-settings-panel/**",
notes: ["主题、色弱、标签栏、菜单布局等本地偏好持久化。"],
},
{
anchor: "layout-notification",
title: "通知",
path: "../layouts/fa-notification/**",
notes: ["通知下拉列表;已读状态;路由跳转。"],
},
{
anchor: "layout-search",
title: "全局搜索",
path: "../layouts/fa-global-search/**",
notes: ["Ctrl/⌘+K 打开全局搜索(`art-global-search` 监听 keydown)。"],
},
{
anchor: "layout-lock",
title: "锁屏",
path: "../layouts/fa-screen-lock/index.vue",
notes: [
"锁屏全屏页;背景随明暗主题切换(`@imgs/lock` → `src/assets/images/lock`);顶栏用户菜单进入。",
],
},
{
anchor: "layout-user",
title: "用户菜单",
path: "../layouts/fa-header-bar/**",
notes: ["头像下拉:文档、教程、锁屏、退出等。"],
},
{
anchor: "layout-theme",
title: "主题切换",
path: "../layouts/fa-settings-panel/**",
notes: ["明暗色、主题色;CSS 变量与 Element Plus 深色。"],
},
{
anchor: "layout-lang",
title: "语言切换",
path: "../locales/langs/**",
notes: ["`src/locales/langs/*.json` 与 i18n 实例;顶栏/设置内切换语言并持久化到本地存储。"],
},
],
},
{
anchor: "mod-exception",
heading: "十、异常页",
pkgTag: "exception",
pages: [
{
anchor: "page-401",
title: "401",
path: "exception/401/index.vue",
notes: [
"静态路由 `/401`;页面含返回/登录入口(见模板)。",
"完整性:守卫或 axios 拦截跳转至此页时按钮可用。",
],
},
{
anchor: "page-403",
title: "403",
path: "exception/403/index.vue",
notes: [
"静态路由 `/403`;无权限提示与返回首页等操作。",
"完整性:从路由 meta 或业务手动跳转后页面可退出。",
],
},
{
anchor: "page-404",
title: "404",
path: "exception/404/index.vue",
notes: [
"独立 `/404` 与 CatchAll `CatchAll404` 共用组件文件(路由 name 不同)。",
"完整性:非法路径落入 CatchAll、手动跳转 `/404` 均能展示。",
],
},
{
anchor: "page-500",
title: "500",
path: "exception/500/index.vue",
notes: [
"静态路由 `/500`;服务端错误提示页。",
"完整性:错误文案、返回或重试按钮(若有)可点击。",
],
},
],
},
{
anchor: "mod-swagger",
heading: "十一、接口文档(API)",
pkgTag: "module_swagger",
pages: [
{
anchor: "page-swagger",
title: "Swagger文档",
path: "module_swagger/docs/index.vue",
notes: [
"父级菜单「接口管理」;默认 iframe `VITE_APP_BASE_API + /docs`,可由 `IframeRouteManager` 覆盖 link。",
"完整性:iframe 加载、loading 消失;需后端文档地址可达。",
],
},
{
anchor: "page-redoc",
title: "Redoc文档",
path: "module_swagger/redoc/index.vue",
notes: [
"Redoc 文档 iframe 页;链接来自 env 或 iframe 路由 meta(与同模块 docs 一致范式)。",
"完整性:页面全高 iframe、加载完成。",
],
},
{
anchor: "page-ljdoc",
title: "LangJin文档",
path: "module_swagger/ljdoc/index.vue",
notes: [
"LangJin 文档 iframe;sys_menu 中节点类型可为 4(菜单页)。",
"完整性:同上,依赖后端或 meta 配置的文档 URL。",
],
},
],
},
];
@@ -0,0 +1,63 @@
/**
* 功能验收手册 — 侧栏「筛选目录」扩展词
* 含与 sys_menu 对齐前的俗称、简称,避免改名后搜不到。
*/
/** 模块级补充检索词 */
export const MANUAL_MODULE_SEARCH_ALIASES: Readonly<Record<string, readonly string[]>> = {
"mod-system": ["平台管理", "系统管理", "用户", "权限"],
"mod-monitor": ["监控"],
"mod-task": ["任务", "调度", "工作流", "cron"],
"mod-ai": ["AI", "智能", "会话", "记忆"],
"mod-generator": ["代码生成", "生成器"],
"mod-app": ["应用", "门户", "插件"],
"mod-example": ["示例", "案例", "demo"],
"mod-dashboard": ["仪表盘", "首页", "工作台", "教程"],
"mod-layout": ["布局", "顶栏", "侧栏", "主题", "锁屏"],
"mod-exception": ["错误页", "404", "403"],
"mod-swagger": ["接口", "API", "文档", "swagger", "redoc"],
};
/** 页面级补充检索词(anchor 与 MANUAL_TOC 一致) */
export const MANUAL_PAGE_SEARCH_ALIASES: Readonly<Record<string, readonly string[]>> = {
"page-resource": ["资源监控", "文件", "上传"],
"page-cronjob": ["定时任务", "调度器", "job", "cron"],
"page-cronnode": ["任务节点", "节点"],
"page-workflow": ["工作流", "流程", "编排"],
"page-nodetype": ["节点类型", "编排"],
"page-ai-chat": ["AI 聊天", "聊天", "chat"],
"page-ai-fachat": ["FA 聊天", "fachat"],
"page-ai-memory": ["记忆管理", "memory"],
"page-portal": ["应用门户", "portal"],
"page-demo": ["示例一", "demo"],
"page-demo01": ["示例二", "demo01", "三级"],
"page-swagger": ["Swagger", "swagger"],
"page-redoc": ["Redoc", "redoc"],
"page-ljdoc": ["LJDoc", "ljdoc", "LangJin"],
"page-db-article": ["文章", "article"],
"page-db-tutorial": ["操作手册", "手册", "教程"],
"page-login": ["登录", "auth"],
"page-changelog": ["日志", "版本", "release"],
"page-home": ["home", "入口"],
"page-profile": ["个人中心", "profile", "账号"],
};
function includesLoose(text: string, q: string): boolean {
return text.toLowerCase().includes(q.toLowerCase());
}
/** 模块是否在筛选下保留(标题、别名或任一子页命中) */
export function manualModuleMatchesQuery(modTitle: string, modAnchor: string, q: string): boolean {
if (includesLoose(modTitle, q)) return true;
const ma = MANUAL_MODULE_SEARCH_ALIASES[modAnchor];
if (ma?.some((a) => includesLoose(a, q))) return true;
return false;
}
/** 子页是否在筛选下保留 */
export function manualPageMatchesQuery(pageTitle: string, pageAnchor: string, q: string): boolean {
if (includesLoose(pageTitle, q)) return true;
const pa = MANUAL_PAGE_SEARCH_ALIASES[pageAnchor];
if (pa?.some((a) => includesLoose(a, q))) return true;
return false;
}
@@ -40,7 +40,7 @@
href="https://blog.csdn.net/weixin_46768253/article/details/149569141?spm=1001.2014.3001.5502"
target="_blank"
>
<ArtSvgIcon :icon="resolveIconForArtSvgIcon('csdn')" class="text-lg" />
<ArtSvgIcon :icon="resolveIconForFaSvgIcon('csdn')" class="text-lg" />
</ElLink>
</div>
</div>
@@ -55,21 +55,21 @@
<div class="mt-3 whitespace-nowrap">
<ElLink href="https://gitee.com/fastapiadmin/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('gitee')"
:icon="resolveIconForFaSvgIcon('gitee')"
class="text-lg text-[#F76560]"
/>
</ElLink>
<ElDivider direction="vertical" />
<ElLink href="https://github.com/fastapiadmin/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('github')"
:icon="resolveIconForFaSvgIcon('github')"
class="text-lg text-[#4080FF]"
/>
</ElLink>
<ElDivider direction="vertical" />
<ElLink href="https://gitcode.com/qq_36002987/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('gitcode')"
:icon="resolveIconForFaSvgIcon('gitcode')"
class="text-lg text-[#FF9A2E]"
/>
</ElLink>
@@ -83,22 +83,19 @@
<div class="flex justify-end space-x-4 overflow-x-auto">
<!-- 仓库图标 -->
<ElLink href="https://gitee.com/fastapiadmin/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('gitee')"
class="text-lg text-[#F76560]"
/>
<ArtSvgIcon :icon="resolveIconForFaSvgIcon('gitee')" class="text-lg text-[#F76560]" />
</ElLink>
<ElDivider direction="vertical" />
<ElLink href="https://github.com/fastapiadmin/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('github')"
:icon="resolveIconForFaSvgIcon('github')"
class="text-lg text-[#4080FF]"
/>
</ElLink>
<ElDivider direction="vertical" />
<ElLink href="https://gitcode.com/qq_36002987/FastapiAdmin" target="_blank">
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('gitcode')"
:icon="resolveIconForFaSvgIcon('gitcode')"
class="text-lg text-[#FF9A2E]"
/>
</ElLink>
@@ -136,7 +133,7 @@
</span>
</div>
<ArtSvgIcon
:icon="resolveIconForArtSvgIcon('people')"
:icon="resolveIconForFaSvgIcon('people')"
class="size-8 animate-[pulse_2s_infinite]"
/>
</div>
@@ -196,7 +193,7 @@
{{ formatGrowthRate(visitStatsData.uvGrowthRate) }}
</span>
</div>
<ArtSvgIcon :icon="resolveIconForArtSvgIcon('visitor')" class="size-8" />
<ArtSvgIcon :icon="resolveIconForFaSvgIcon('visitor')" class="size-8" />
</div>
<div class="flex items-center justify-between mt-2 text-sm text-g-600">
@@ -256,7 +253,7 @@
{{ formatGrowthRate(visitStatsData.pvGrowthRate) }}
</span>
</div>
<ArtSvgIcon :icon="resolveIconForArtSvgIcon('browser')" class="size-8" />
<ArtSvgIcon :icon="resolveIconForFaSvgIcon('browser')" class="size-8" />
</div>
<div class="flex items-center justify-between mt-2 text-sm text-g-600">
@@ -369,9 +366,9 @@ import {
TopRight,
UserFilled,
} from "@element-plus/icons-vue";
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import ArtSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import { greetings } from "@utils/common";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
const timefix = greetings();
const welcome = "祝你开心每一天!";
@@ -4,12 +4,12 @@
<button class="collapse-btn" @click="toggleSidebar">
<ArtSvgIcon
v-if="!props.isSidebarCollapsed"
:icon="resolveIconForArtSvgIcon('layout_leftbar_close_line')"
:icon="resolveIconForFaSvgIcon('layout_leftbar_close_line')"
class="size-6"
/>
<ArtSvgIcon
v-else
:icon="resolveIconForArtSvgIcon('layout_leftbar_open_line')"
:icon="resolveIconForFaSvgIcon('layout_leftbar_open_line')"
class="size-6"
/>
</button>
@@ -36,8 +36,8 @@
</template>
<script setup lang="ts">
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/remix";
import ArtSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/remix";
import { computed } from "vue";
import { Connection, Loading, Warning, Delete, Setting } from "@element-plus/icons-vue";
@@ -1,7 +1,7 @@
<!-- AI 会话记录:Art + useTable -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_ai:chat:create']"
:perm-delete="['module_ai:chat:delete']"
@@ -34,10 +34,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="loading"
:data="data"
@@ -61,10 +61,10 @@
<ElIcon class="edit-icon"><Edit /></ElIcon>
</span>
</template>
</ArtTable>
</FaTable>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="920px"
@@ -138,7 +138,7 @@
</ElScrollbar>
</template>
<template v-else>
<ArtForm
<FaForm
:key="memoryFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -164,7 +164,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -180,14 +180,14 @@ import { ElMessage, ElMessageBox } from "element-plus";
import AiChatAPI, { type ChatSession, type ChatSessionDetail } from "@/api/module_ai/chat";
import { formatToDateTime } from "@utils/common";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
@@ -213,7 +213,7 @@ const searchForm = ref<MemorySearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const { hasAuth } = useAuth();
@@ -259,7 +259,7 @@ const memorySearchItems = computed<SearchFormItem[]>(() => [
},
]);
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const memoryFormRenderKey = ref(0);
const memoryDialogFormItems = computed<FormItem[]>(() => [
@@ -275,7 +275,7 @@ const titleInputRef = ref();
const editingRowId = ref<string | null>(null);
const editingTitle = ref("");
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<ChatSession[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is string => Boolean(id))
@@ -295,7 +295,7 @@ function deleteSessionRow(id: string) {
.then(async () => {
await AiChatAPI.deleteSession([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -422,22 +422,7 @@ const {
},
});
const paginationBind = computed(() => {
const p = pagination as unknown as {
current?: number;
size?: number;
total?: number;
page_no?: number;
page_size?: number;
};
return {
current: p.current ?? p.page_no ?? 1,
size: p.size ?? p.page_size ?? 20,
total: p.total ?? 0,
};
});
const formData = reactive({
const formData = ref({
id: undefined as string | undefined,
title: "",
});
@@ -1,7 +1,7 @@
<!-- 我的应用管理:Art + useTable(卡片网格) -->
<template>
<div class="art-full-height portal-application-page flex flex-col min-h-0">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -32,13 +32,13 @@
@clear-click="afterUserSelectSearch"
/>
</template>
</ArtSearchBar>
</FaSearchBar>
<ElCard
class="flex flex-1 min-h-0 flex-col art-table-card"
:style="{ 'margin-top': showSearchBar ? '12px' : '0' }"
>
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
layout="search,refresh"
@@ -58,7 +58,7 @@
</ElButton>
</div>
</template>
</ArtTableHeader>
</FaTableHeader>
<div v-loading="loading" class="app-grid-container min-h-0 flex-1 overflow-auto">
<div v-if="!loading && data.length === 0" class="app-grid-empty">
@@ -135,14 +135,14 @@
</div>
</ElCard>
<ArtDrawer
<FaDrawer
v-model="dialogVisible"
:title="dialogTitle"
:size="drawerSize"
direction="rtl"
@close="handleCloseDialog"
>
<ArtForm
<FaForm
:key="portalFormRenderKey"
ref="formRef"
v-model="formData"
@@ -162,7 +162,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
<template #footer>
<div class="dialog-footer">
@@ -170,7 +170,7 @@
<ElButton type="primary" @click="handleSubmit">确定</ElButton>
</div>
</template>
</ArtDrawer>
</FaDrawer>
</div>
</template>
@@ -191,12 +191,12 @@ import ApplicationAPI, {
} from "@/api/module_application/portal";
import { formatToDateTime } from "@utils/common";
import { useTable } from "@/hooks/core/useTable";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import UserTableSelect from "@views/module_system/user/components/UserTableSelect.vue";
import type { ColumnOption } from "@/types/component";
@@ -226,7 +226,7 @@ const searchForm = ref<PortalSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -268,7 +268,7 @@ const portalSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const formRef = ref<InstanceType<typeof ArtForm> | null>(null);
const formRef = ref<InstanceType<typeof FaForm> | null>(null);
const portalFormRenderKey = ref(0);
const portalDrawerFormItems = computed<FormItem[]>(() => [
@@ -343,22 +343,7 @@ const {
},
});
const paginationBind = computed(() => {
const p = pagination as unknown as {
current?: number;
size?: number;
total?: number;
page_no?: number;
page_size?: number;
};
return {
current: p.current ?? p.page_no ?? 1,
size: p.size ?? p.page_size ?? 12,
total: p.total ?? 0,
};
});
const formData = reactive<ApplicationForm>({
const formData = ref<ApplicationForm>({
name: "",
access_url: "",
icon_url: "",
@@ -1,7 +1,7 @@
<!-- 示例 CRUD:与角色页同一套 Art 布局;弹窗与 Crud 一致(ArtDialog + crud-embed-dialog) -->
<!-- 示例 CRUD:与角色页同一套 Art 布局;弹窗与 Crud 一致(FaDialog + crud-embed-dialog) -->
<template>
<div class="art-full-height">
<ArtSearchBarWithAudit
<FaSearchBarWithAudit
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_example:demo:create']"
:perm-import="['module_example:demo:import']"
@@ -40,10 +40,10 @@
@more="runBatchStatus"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -54,7 +54,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="920px"
@@ -248,7 +248,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtImportDialog
v-model="importModalVisible"
@@ -257,7 +257,7 @@
@upload="handleCrudImportUpload"
/>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="demoExportContentConfig"
:query-params="exportQueryParams"
@@ -272,13 +272,13 @@ import { h, computed, ref } from "vue";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
import { useTable } from "@/hooks/core/useTable";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtImportDialog from "@/components/Core/modal/art-import-dialog/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/Core/modal/types";
import ArtSearchBarWithAudit from "@/components/Core/forms/art-search-bar/ArtSearchBarWithAudit.vue";
import type { AuditSearchFormParams } from "@/components/Core/forms/art-search-bar/auditSearchFormItems";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import ArtImportDialog from "@/components/modal/fa-import-dialog/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/modal/types";
import FaSearchBarWithAudit from "@/components/forms/fa-search-bar/FaSearchBarWithAudit.vue";
import type { AuditSearchFormParams } from "@/components/forms/fa-search-bar/auditSearchFormItems";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import JsonPretty from "@/components/JsonPretty/index.vue";
import type { ColumnOption } from "@/types/component";
import DemoAPI, {
@@ -317,13 +317,13 @@ const searchForm = ref<DemoSearchFormParams>({
/** 搜索区域默认展开展示 */
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBarWithAudit> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBarWithAudit> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
{ label: "启用", value: "0" },
{ label: "停用", value: "1" },
]);
/** 名称、状态;创建人/更新人/时间由 ArtSearchBarWithAudit 追加 */
/** 名称、状态;创建人/更新人/时间由 FaSearchBarWithAudit 追加 */
const demoBusinessSearchItems = computed(() => [
{
label: "名称",
@@ -346,7 +346,7 @@ const demoBusinessSearchItems = computed(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<DemoTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -510,7 +510,7 @@ const dialogVisible = reactive({
const detailFormData = ref<DemoTable>({});
const formData = reactive<DemoForm>({
const formData = ref<DemoForm>({
id: undefined,
name: "",
status: "0",
@@ -708,7 +708,7 @@ const deleteDemoRow = (row: DemoTable) => {
.then(async () => {
await DemoAPI.deleteDemo([row.id!]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {
@@ -729,7 +729,7 @@ function handleBatchDelete() {
batchDeleting.value = true;
await DemoAPI.deleteDemo(ids);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -754,7 +754,7 @@ function runBatchStatus(status: string) {
.then(async () => {
await DemoAPI.batchDemo({ ids, status });
ElMessage.success("操作成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshData();
})
.catch(() => {});
@@ -1,7 +1,7 @@
<!-- 示例01 CRUD:与 demo 同一套 Art 布局;权限与接口为 module_example:demo01 / Demo01API -->
<template>
<div class="art-full-height">
<ArtSearchBarWithAudit
<FaSearchBarWithAudit
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_example:demo01:create']"
:perm-import="['module_example:demo01:import']"
@@ -40,10 +40,10 @@
@more="runBatchStatus"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -54,7 +54,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="768px"
@@ -96,7 +96,7 @@
</template>
<template v-else>
<ElScrollbar max-height="70vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="demo01FormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -117,7 +117,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -130,7 +130,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtImportDialog
v-model="importModalVisible"
@@ -139,7 +139,7 @@
@upload="handleCrudImportUpload"
/>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="demo01ExportContentConfig"
:query-params="exportQueryParams"
@@ -154,15 +154,15 @@ import { h, computed, ref, reactive } from "vue";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
import { useTable } from "@/hooks/core/useTable";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtImportDialog from "@/components/Core/modal/art-import-dialog/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/Core/modal/types";
import ArtSearchBarWithAudit from "@/components/Core/forms/art-search-bar/ArtSearchBarWithAudit.vue";
import type { AuditSearchFormParams } from "@/components/Core/forms/art-search-bar/auditSearchFormItems";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import ArtImportDialog from "@/components/modal/fa-import-dialog/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/modal/types";
import FaSearchBarWithAudit from "@/components/forms/fa-search-bar/FaSearchBarWithAudit.vue";
import type { AuditSearchFormParams } from "@/components/forms/fa-search-bar/auditSearchFormItems";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import Demo01API, {
type Demo01Form,
@@ -204,7 +204,7 @@ const searchForm = ref<Demo01SearchFormParams>({
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBarWithAudit> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBarWithAudit> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -242,7 +242,7 @@ const demo01BusinessSearchItems = computed(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<Demo01Table[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -381,7 +381,7 @@ const dialogVisible = reactive({
const detailFormData = ref<Demo01Table>({});
const formData = reactive<Demo01Form>({
const formData = ref<Demo01Form>({
id: undefined,
name: "",
status: "0",
@@ -393,7 +393,7 @@ const rules = reactive({
status: [{ required: true, message: "请选择状态", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const demo01FormRenderKey = ref(0);
const demo01DialogFormItems = computed<FormItem[]>(() => [
@@ -564,7 +564,7 @@ const deleteDemo01Row = (row: Demo01Table) => {
.then(async () => {
await Demo01API.deleteDemo01([row.id!]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {
@@ -585,7 +585,7 @@ function handleBatchDelete() {
batchDeleting.value = true;
await Demo01API.deleteDemo01(ids);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -610,7 +610,7 @@ function runBatchStatus(status: string) {
.then(async () => {
await Demo01API.batchDemo01({ ids, status });
ElMessage.success("操作成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshData();
})
.catch(() => {});
@@ -1,5 +1,5 @@
<template>
<ArtDialog
<FaDialog
v-model="visible"
title="创建数据表"
width="min(800px, 94vw)"
@@ -165,7 +165,7 @@
<ElButton @click="handleCancel">取消</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</template>
<script setup lang="ts">
@@ -178,7 +178,7 @@ import type { CmComponentRef } from "codemirror-editor-vue3";
import { ElMessage } from "element-plus";
import { ArrowDown, CopyDocument } from "@element-plus/icons-vue";
import { useClipboard } from "@vueuse/core";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import { useSettingsStore } from "@stores";
import { ThemeMode } from "@/enums/settings/theme.enum";
import { buildSqlFromVisual } from "../utils/buildCreateTableSql";
@@ -1,5 +1,5 @@
<template>
<ArtDrawer
<FaDrawer
v-model="drawerVisible"
:title="'【代码生成】' + (info.table_name || '')"
size="90%"
@@ -89,7 +89,7 @@
</ElButton>
</ElTooltip>
</template>
</ArtDrawer>
</FaDrawer>
</template>
<script setup lang="ts">
@@ -99,7 +99,7 @@ import { Close, Right, FolderOpened, Back, Download, Finished } from "@element-p
import type { EditorConfiguration } from "codemirror";
import type { GenTableSchema } from "@/api/module_generator/gencode";
import type { DictTable } from "@/api/module_system/dict";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import type { TreeNode } from "../types";
import GenBasicStep from "./GenBasicStep.vue";
import GenColumnsStep from "./GenColumnsStep.vue";
@@ -46,7 +46,7 @@
/>
<ArtSvgIcon
v-else
:icon="resolveIconForArtSvgIcon(getFileTreeNodeIcon(data.label))"
:icon="resolveIconForFaSvgIcon(getFileTreeNodeIcon(data.label))"
class="inline shrink-0 text-base"
/>
<span class="ml-1" :title="data.full_path || data.label">
@@ -91,9 +91,9 @@ import { computed, inject, onUnmounted, ref, watch } from "vue";
import Codemirror from "codemirror-editor-vue3";
import type { EditorConfiguration } from "codemirror";
import type { CmComponentRef } from "codemirror-editor-vue3";
import ArtSvgIcon from "@/components/Core/base/art-svg-icon/index.vue";
import ArtSvgIcon from "@/components/base/fa-svg-icon/index.vue";
import { resolveLocalIconUrl } from "@utils/icons";
import { resolveIconForArtSvgIcon } from "@utils/menuIcon/index";
import { resolveIconForFaSvgIcon } from "@utils/menuIcon/index";
import { CopyDocument } from "@element-plus/icons-vue";
import { GENCODE_CM_KEY } from "../gencodeInjectionKeys";
import type { TreeNode } from "../types";
@@ -1,5 +1,5 @@
<template>
<ArtDialog ref="dialogRef" v-model="open" title="导入表" width="min(960px, 96vw)" append-to-body>
<FaDialog ref="dialogRef" v-model="open" title="导入表" width="min(960px, 96vw)" append-to-body>
<ElForm ref="importQueryRef" :model="query" :inline="true">
<ElFormItem label="表名称" prop="table_name">
<ElInput
@@ -86,14 +86,14 @@
<ElButton @click="open = false">取 消</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import type { FormInstance, TableInstance } from "element-plus";
import type { DBTableSchema, GenTablePageQuery } from "@/api/module_generator/gencode";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
defineOptions({ name: "ImportDbTableDialog" });
@@ -1,6 +1,6 @@
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -17,7 +17,7 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="tableLoading"
@@ -65,10 +65,10 @@
</ElButton>
</ElSpace>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="tableLoading"
:data="tableListData"
@@ -156,10 +156,10 @@ import { MenuTypeEnum } from "@/enums";
import { useSettingsStore } from "@stores";
import { ThemeMode } from "@/enums/settings/theme.enum";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import type { ColumnOption } from "@/types/component";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
@@ -181,8 +181,8 @@ interface FileData {
const cmRef = ref<CmComponentRef>();
const basicInfo = ref<FormInstance>();
const importDbDialogRef = ref<InstanceType<typeof ImportDbTableDialog>>();
/** ArtTable:勾选清空(删除后) */
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
/** FaTable:勾选清空(删除后) */
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
/** useTable 初始化前的占位,供同步/删除/导入等在文件中靠前定义的函数调用 */
const listRefresh = {
@@ -750,7 +750,7 @@ async function handleDelete(row?: GenTableSchema): Promise<void> {
});
await GencodeAPI.deleteTable(tableIds);
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await listRefresh.refreshRemove();
} catch (error) {
if (error !== "cancel") {
@@ -808,7 +808,7 @@ const searchForm = ref<GencodeSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const gencodeSearchItems = computed<SearchFormItem[]>(() => [
@@ -1,7 +1,7 @@
<!-- 在线用户:Art + useTable -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,7 +18,7 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@@ -35,9 +35,9 @@
强退所有
</ElButton>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
<FaTable
row-key="session_id"
:loading="loading"
:data="data"
@@ -58,11 +58,11 @@ defineOptions({
import { h, ref, computed } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtButtonTable from "@/components/Core/forms/art-button-table/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import ArtButtonTable from "@/components/forms/fa-button-table/index.vue";
import CopyButton from "@/components/CopyButton/index.vue";
import OnlineAPI, { type OnlineUserTable } from "@/api/module_monitor/online";
import type { ColumnOption } from "@/types/component";
@@ -92,7 +92,7 @@ const searchForm = ref<OnlineSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const onlineSearchItems = computed<SearchFormItem[]>(() => [
@@ -1,7 +1,7 @@
<!-- 资源管理:Art + useTable -->
<template>
<div class="art-full-height resource-monitor-page">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -42,7 +42,7 @@
</div>
</div>
<ArtTableHeader
<FaTableHeader
class="resource-toolbar shrink-0"
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
@@ -89,11 +89,11 @@
</ElCheckbox>
</ElSpace>
</template>
</ArtTableHeader>
</FaTableHeader>
<!-- 面包屑与表头已占用高度:表格高度须在独立 flex 子项内计算,否则分页会被挤出卡片 -->
<div class="resource-table-region min-h-0 flex flex-1 flex-col overflow-hidden pb-3">
<ArtTable
<FaTable
row-key="file_url"
:show-table-header="false"
:loading="loading"
@@ -107,7 +107,7 @@
</div>
</ElCard>
<ArtDialog
<FaDialog
v-model="uploadDialogVisible"
title="上传文件"
width="500px"
@@ -143,9 +143,9 @@
确定上传
</ElButton>
</template>
</ArtDialog>
</FaDialog>
<ArtDialog v-model="createDirDialogVisible" title="新建文件夹" width="400px">
<FaDialog v-model="createDirDialogVisible" title="新建文件夹" width="400px">
<ElForm :model="createDirForm" label-width="80px">
<ElFormItem label="文件夹名" required>
<ElInput
@@ -165,9 +165,9 @@
确定
</ElButton>
</template>
</ArtDialog>
</FaDialog>
<ArtDialog v-model="renameDialogVisible" title="重命名" width="400px">
<FaDialog v-model="renameDialogVisible" title="重命名" width="400px">
<ElForm :model="renameForm" label-width="80px">
<ElFormItem label="新名称" required>
<ElInput
@@ -187,7 +187,7 @@
确定
</ElButton>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -218,12 +218,12 @@ import {
UploadFilled,
} from "@element-plus/icons-vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtButtonTable from "@/components/Core/forms/art-button-table/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import ArtButtonTable from "@/components/forms/fa-button-table/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import { ResourceAPI, type ResourceItem } from "@/api/module_monitor/resource";
import type { ColumnOption } from "@/types/component";
import { useAuth } from "@/hooks/core/useAuth";
@@ -253,7 +253,7 @@ const searchForm = ref<ResourceSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const resourceSearchItems = computed<SearchFormItem[]>(() => [
@@ -1,7 +1,7 @@
<!-- 部门配置:Art + 树形表格(对齐 system/menu 模版) -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,7 +18,7 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@@ -26,7 +26,7 @@
>
<template #left>
<div class="inline-flex flex-wrap items-center gap-2">
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:dept:create']"
:perm-delete="['module_system:dept:delete']"
@@ -39,9 +39,9 @@
<ElButton @click="toggleExpand">{{ isExpanded ? "收起" : "展开" }}</ElButton>
</div>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
<FaTable
ref="tableRef"
row-key="id"
:loading="loading"
@@ -53,7 +53,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="640px"
@@ -95,7 +95,7 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="deptFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -116,7 +116,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -129,7 +129,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -141,14 +141,14 @@ import DeptAPI, {
type DeptPageQuery,
type DeptTable,
} from "@/api/module_system/dept";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import { ElMessage, ElMessageBox, ElTag } from "element-plus";
import { useAuth } from "@/hooks/core/useAuth";
import { useUserStore } from "@stores";
@@ -234,7 +234,7 @@ const searchForm = ref<DeptSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -362,7 +362,7 @@ const { columnChecks, columns } = useTableColumns<DeptTable>(() => [
const detailFormData = ref<DeptTable>({ code: "" });
const formData = reactive<DeptForm>({
const formData = ref<DeptForm>({
id: undefined,
name: undefined,
code: "",
@@ -404,7 +404,7 @@ const initialFormData: DeptForm = {
description: undefined,
};
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const deptFormRenderKey = ref(0);
const deptDialogFormItems = computed<FormItem[]>(() => [
@@ -515,10 +515,10 @@ async function handleOpenDialog(
}
} else {
dialogVisible.title = "新增部门";
Object.assign(formData, initialFormData);
formData.id = undefined;
Object.assign(formData.value, initialFormData);
formData.value.id = undefined;
if (parentId) {
formData.parent_id = parentId;
formData.value.parent_id = parentId;
}
}
deptFormRenderKey.value += 1;
@@ -528,12 +528,12 @@ async function handleOpenDialog(
async function handleSubmit() {
dataFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
const id = formData.id;
const id = formData.value.id;
try {
if (id) {
await DeptAPI.updateDept(id, { id, ...formData });
await DeptAPI.updateDept(id, { id, ...formData.value });
} else {
await DeptAPI.createDept(formData);
await DeptAPI.createDept(formData.value);
}
dialogVisible.visible = false;
await resetForm();
@@ -1,13 +1,13 @@
<!-- 字典数据抽屉:Art 搜索 + useTable;固定 dict_type / dict_type_id 由父级传入 -->
<template>
<ArtDrawer
<FaDrawer
v-model="drawerVisible"
:title="'【' + dictLabel + '】字典数据'"
direction="rtl"
:size="drawerSize"
>
<div class="drawer-content">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -27,14 +27,14 @@
class="art-table-card drawer-table-card"
:style="{ 'margin-top': showSearchBar ? '12px' : '0' }"
>
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:dict_data:create']"
:perm-export="['module_system:dict_data:export']"
@@ -47,10 +47,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -61,7 +61,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="720px"
@@ -112,7 +112,7 @@
</template>
<template v-else>
<ElScrollbar max-height="70vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="dictDataFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -211,7 +211,7 @@
:inactive-value="'1'"
/>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -224,9 +224,9 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="dictDataExportContentConfig"
:query-params="exportQueryParams"
@@ -234,21 +234,21 @@
:selection-data="selectedRows"
/>
</div>
</ArtDrawer>
</FaDrawer>
</template>
<script setup lang="ts">
import { h, computed, ref, reactive } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import DictAPI, {
type DictDataForm,
@@ -363,7 +363,7 @@ const searchForm = ref<DictDataSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -408,7 +408,7 @@ const dictDataSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<DictDataTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -554,7 +554,7 @@ const dialogVisible = reactive({
const detailFormData = ref<DictDataTable>({});
const formData = reactive<DictDataForm>({
const formData = ref<DictDataForm>({
id: undefined,
dict_sort: 1,
dict_label: "",
@@ -577,7 +577,7 @@ const rules = reactive({
is_default: [{ required: true, message: "请选择是否默认", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const dictDataFormRenderKey = ref(0);
const dictDataDialogFormItems = computed<FormItem[]>(() => [
@@ -728,11 +728,11 @@ async function handleOpenDialog(type: "create" | "update" | "detail", id?: numbe
}
} else {
dialogVisible.title = "新增字典数据";
Object.assign(formData, initialFormData);
formData.dict_type = props.dictType;
formData.dict_type_id = props.dictTypeId;
formData.status = "0";
formData.id = undefined;
Object.assign(formData.value, initialFormData);
formData.value.dict_type = props.dictType;
formData.value.dict_type_id = props.dictTypeId;
formData.value.status = "0";
formData.value.id = undefined;
}
dictDataFormRenderKey.value += 1;
dialogVisible.visible = true;
@@ -741,20 +741,20 @@ async function handleOpenDialog(type: "create" | "update" | "detail", id?: numbe
async function handleSubmit() {
dataFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
const id = formData.id;
const id = formData.value.id;
try {
if (id) {
await DictAPI.updateDictData(id, { id, ...formData });
await refreshUpdate();
} else {
await DictAPI.createDictData(formData);
await DictAPI.createDictData(formData.value);
await refreshCreate();
}
dialogVisible.visible = false;
await resetForm();
dictStore.clearDictData();
if (formData.dict_type) {
await dictStore.getDict([formData.dict_type]);
if (formData.value.dict_type) {
await dictStore.getDict([formData.value.dict_type]);
}
} catch (error: unknown) {
console.error(error);
@@ -812,7 +812,7 @@ function deleteDictDataRow(id: number) {
await dictStore.getDict([props.dictType]);
}
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -835,7 +835,7 @@ function handleBatchDelete() {
await dictStore.getDict([props.dictType]);
}
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,7 +1,7 @@
<!-- 字典类型:Art 布局;操作列最多 3 个外露 +「更多」 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:dict_type:create']"
:perm-export="['module_system:dict_type:export']"
@@ -38,10 +38,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -52,7 +52,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="640px"
@@ -87,7 +87,7 @@
</template>
<template v-else>
<ElScrollbar max-height="70vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="dictFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -108,7 +108,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -121,9 +121,9 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="dictTypeExportContentConfig"
:query-params="exportQueryParams"
@@ -144,14 +144,14 @@
<script setup lang="ts">
import { h, computed, ref, reactive } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import DictAPI, {
type DictForm,
@@ -194,7 +194,7 @@ const searchForm = ref<DictTypeSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -247,7 +247,7 @@ const dictTypeSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<DictTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -372,7 +372,7 @@ const dialogVisible = reactive({
const detailFormData = ref<DictTable>({});
const formData = reactive<DictForm>({
const formData = ref<DictForm>({
id: undefined,
dict_name: "",
dict_type: "",
@@ -386,7 +386,7 @@ const rules = reactive({
status: [{ required: true, message: "请选择字典状态", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const dictFormRenderKey = ref(0);
const dictDialogFormItems = computed<FormItem[]>(() => [
@@ -542,8 +542,8 @@ async function handleOpenDialog(type: "create" | "update" | "detail", id?: numbe
}
} else {
dialogVisible.title = "新增字典";
Object.assign(formData, initialFormData);
formData.id = undefined;
Object.assign(formData.value, initialFormData);
formData.value.id = undefined;
}
dictFormRenderKey.value += 1;
dialogVisible.visible = true;
@@ -552,20 +552,20 @@ async function handleOpenDialog(type: "create" | "update" | "detail", id?: numbe
async function handleSubmit() {
dataFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
const id = formData.id;
const id = formData.value.id;
try {
if (id) {
await DictAPI.updateDictType(id, { id, ...formData });
await DictAPI.updateDictType(id, { id, ...formData.value });
await refreshUpdate();
} else {
await DictAPI.createDictType(formData);
await DictAPI.createDictType(formData.value);
await refreshCreate();
}
dialogVisible.visible = false;
await resetForm();
dictStore.clearDictData();
if (formData.dict_type) {
await dictStore.getDict([formData.dict_type]);
if (formData.value.dict_type) {
await dictStore.getDict([formData.value.dict_type]);
}
} catch (error: unknown) {
console.error(error);
@@ -587,7 +587,7 @@ function deleteDictTypeRow(id: number) {
await dictStore.getDict(dictTypes);
}
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -611,7 +611,7 @@ function handleBatchDelete() {
await dictStore.getDict(dictTypes);
}
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,7 +1,7 @@
<!-- 日志管理:Art 布局 + useTable,与 dict 页一致 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -24,17 +24,17 @@
@clear-click="afterUserSelectSearch"
/>
</template>
</ArtSearchBar>
</FaSearchBar>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-export="['module_system:log:export']"
:perm-delete="['module_system:log:delete']"
@@ -43,10 +43,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -57,7 +57,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="960px"
@@ -130,9 +130,9 @@
<ElButton type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="logExportContentConfig"
:query-params="exportQueryParams"
@@ -145,14 +145,14 @@
<script setup lang="ts">
import { h, computed, ref, nextTick } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import JsonPretty from "@/components/JsonPretty/index.vue";
import CopyButton from "@/components/CopyButton/index.vue";
import type { ColumnOption } from "@/types/component";
@@ -204,7 +204,7 @@ const searchForm = ref<LogSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const logTypeOptions = ref([
@@ -255,7 +255,7 @@ const logSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<LogTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -483,7 +483,7 @@ function deleteLogRow(id: number) {
.then(async () => {
await LogAPI.deleteLog([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -533,7 +533,7 @@ function handleBatchDelete() {
batchDeleting.value = true;
await LogAPI.deleteLog(ids);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,7 +1,7 @@
<!-- 菜单管理:Art + 树形表格;操作列最多 3 个外露,其余「更多」 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -27,7 +27,7 @@
</ElTabs>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@@ -35,7 +35,7 @@
>
<template #left>
<div class="inline-flex flex-wrap items-center gap-2">
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:menu:create']"
:perm-delete="['module_system:menu:delete']"
@@ -48,9 +48,9 @@
<ElButton @click="toggleExpand">{{ isExpanded ? "收起" : "展开" }}</ElButton>
</div>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
<FaTable
ref="tableRef"
row-key="id"
:loading="loading"
@@ -63,7 +63,7 @@
/>
</ElCard>
<ArtDrawer
<FaDrawer
v-model="dialogVisible.visible"
:title="dialogVisible.title"
:size="drawerSize"
@@ -497,7 +497,7 @@
<ElButton @click="handleCloseDialog">取消</ElButton>
</div>
</template>
</ArtDrawer>
</FaDrawer>
</div>
</template>
@@ -521,12 +521,12 @@ import MenuAPI, {
import { MenuClientEnum, MenuTypeEnum } from "@/enums/system/menu.enum";
import { formatTree } from "@utils/common";
import MenuRouteIcon from "@/components/MenuRouteIcon/index.vue";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import { ElMessage, ElMessageBox, ElTag, ElTooltip } from "element-plus";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
@@ -628,7 +628,7 @@ const searchForm = ref<MenuSearchForm>({
created_time: undefined,
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -692,7 +692,7 @@ const createParentLocked = ref(false);
const detailFormData = ref<MenuTable>({});
const formData = reactive<MenuForm>({
const formData = ref<MenuForm>({
id: undefined,
name: undefined,
type: MenuTypeEnum.CATALOG,
@@ -1,7 +1,7 @@
<!-- 公告通知:Art 布局 + useTable,与 dict 页一致 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -24,17 +24,17 @@
@clear-click="afterUserSelectSearch"
/>
</template>
</ArtSearchBar>
</FaSearchBar>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:notice:create']"
:perm-export="['module_system:notice:export']"
@@ -47,10 +47,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -61,7 +61,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="920px"
@@ -113,8 +113,8 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<!-- ArtForm + items + 栅格;弹窗内关闭内置提交/重置,仍用底部按钮 -->
<ArtForm
<!-- FaForm + items + 栅格;弹窗内关闭内置提交/重置,仍用底部按钮 -->
<FaForm
:key="noticeFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -144,7 +144,7 @@
@update:model-value="(v: string) => (formData.notice_content = v)"
/>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -162,9 +162,9 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="noticeExportContentConfig"
:query-params="exportQueryParams"
@@ -177,14 +177,14 @@
<script setup lang="ts">
import { h, computed, ref, reactive, nextTick, onMounted } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import type { ColumnOption } from "@/types/component";
import NoticeAPI, {
type NoticeForm,
@@ -196,9 +196,9 @@ import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
import { useDictStore, useNoticeStore } from "@stores/index";
import UserTableSelect from "@views/module_system/user/components/UserTableSelect.vue";
import ArtWangEditor from "@/components/Core/forms/art-wang-editor/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import ArtWangEditor from "@/components/forms/fa-wang-editor/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
defineOptions({
name: "Notice",
@@ -240,7 +240,7 @@ const searchForm = ref<NoticeSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -309,7 +309,7 @@ const noticeSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<NoticeTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -463,7 +463,7 @@ const detailHasRenderableContent = computed(() => {
return plain.length > 0;
});
const formData = reactive<NoticeForm>({
const formData = ref<NoticeForm>({
id: undefined,
notice_title: "",
notice_type: "",
@@ -485,13 +485,13 @@ const rules = reactive({
status: [{ required: true, message: "请选择公告通知状态", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const submitLoading = ref(false);
/** 每次打开弹窗递增,令 ArtForm 重新挂载并同步初始 model(与示例页声明式 items 一致) */
/** 每次打开弹窗递增,令 FaForm 重新挂载并同步初始 model(与示例页声明式 items 一致) */
const noticeFormRenderKey = ref(0);
/** 公告编辑表单字段配置(ArtForm + items) */
/** 公告编辑表单字段配置(FaForm + items) */
const noticeDialogFormItems = computed<FormItem[]>(() => [
{
label: "标题",
@@ -660,7 +660,7 @@ function deleteNoticeRow(id: number) {
await NoticeAPI.deleteNotice([id]);
await noticeStore.getNotice();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -721,7 +721,7 @@ function handleBatchDelete() {
await NoticeAPI.deleteNotice(ids);
await noticeStore.getNotice();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -759,11 +759,7 @@ onMounted(async () => {
</script>
<style scoped lang="scss">
.art-table-card {
flex: 1;
}
/* ArtForm 底部预留的操作栏列在弹窗内不需要占位 */
/* FaForm 底部预留的操作栏列在弹窗内不需要占位 */
.crud-dialog-art-form :deep(.el-row > .el-col:last-child) {
display: none;
}
@@ -1,5 +1,5 @@
<template>
<ArtDrawer
<FaDrawer
v-model="drawerVisible"
title="配置中心"
:size="drawerSize"
@@ -281,7 +281,7 @@
保存
</ElButton>
</template>
</ArtDrawer>
</FaDrawer>
</template>
<script lang="ts" setup>
@@ -290,7 +290,7 @@ import ParamsAPI, { type ConfigTable } from "@/api/module_system/params";
import { useConfigStore } from "@stores";
import { useI18n } from "vue-i18n";
import { ElMessage, ElMessageBox } from "element-plus";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import SingleImageUpload from "@/components/Upload/SingleImageUpload.vue";
import { useAppStore } from "@stores/modules/app.store";
import { DeviceEnum } from "@/enums/settings/device.enum";
@@ -1,7 +1,7 @@
<!-- 系统配置:Art 布局 + useTable,与 notice 页一致 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:param:create']"
:perm-export="['module_system:param:export']"
@@ -36,10 +36,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -50,7 +50,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="640px"
@@ -88,7 +88,7 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="paramFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -109,7 +109,7 @@
<ElRadio :value="false">否</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -127,9 +127,9 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="paramExportContentConfig"
:query-params="exportQueryParams"
@@ -142,16 +142,16 @@
<script setup lang="ts">
import { h, computed, ref, reactive } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import ParamsAPI, {
type ConfigForm,
@@ -205,7 +205,7 @@ const searchForm = ref<ParamSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const builtinOptions = ref([
@@ -258,7 +258,7 @@ const paramSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<ConfigTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -370,7 +370,7 @@ const paginationBind = computed(() => {
const detailFormData = ref<ConfigTable>({} as ConfigTable);
const formData = reactive<ConfigForm>({
const formData = ref<ConfigForm>({
id: undefined,
config_name: "",
config_key: "",
@@ -392,7 +392,7 @@ const rules = reactive({
config_type: [{ required: true, message: "请选择系统配置类型", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const paramFormRenderKey = ref(0);
const paramDialogFormItems = computed<FormItem[]>(() => [
@@ -534,7 +534,7 @@ function deleteParamRow(id: number) {
configStore.isConfigLoaded = false;
await configStore.getConfig();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -596,7 +596,7 @@ function handleBatchDelete() {
configStore.isConfigLoaded = false;
await configStore.getConfig();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,7 +1,7 @@
<!-- 岗位管理:Art + useTable;操作列前 3 个为 ArtButtonTable,其余收入「更多」下拉 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -24,17 +24,17 @@
@clear-click="afterUserSelectSearch"
/>
</template>
</ArtSearchBar>
</FaSearchBar>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:position:create']"
:perm-export="['module_system:position:export']"
@@ -47,10 +47,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -61,7 +61,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="720px"
@@ -102,7 +102,7 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="positionFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -123,7 +123,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -141,9 +141,9 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="positionExportContentConfig"
:query-params="exportQueryParams"
@@ -156,17 +156,17 @@
<script setup lang="ts">
import { h, computed, ref, reactive, nextTick } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import ArtButtonTable from "@/components/Core/forms/art-button-table/index.vue";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import ArtButtonTable from "@/components/forms/fa-button-table/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import PositionAPI, {
type PositionForm,
@@ -341,7 +341,7 @@ const searchForm = ref<PositionSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -392,7 +392,7 @@ const positionSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<PositionTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -413,7 +413,7 @@ function deletePositionRow(id: number) {
await PositionAPI.deletePosition([id]);
await userStore.getUserInfo();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -537,7 +537,7 @@ const paginationBind = computed(() => {
const detailFormData = ref<PositionTable>({});
const formData = reactive<PositionForm>({
const formData = ref<PositionForm>({
id: undefined,
name: undefined,
order: 1,
@@ -565,7 +565,7 @@ const initialFormData: PositionForm = {
description: undefined,
};
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const positionFormRenderKey = ref(0);
const positionDialogFormItems = computed<FormItem[]>(() => [
@@ -707,7 +707,7 @@ function handleBatchDelete() {
await PositionAPI.deletePosition(ids);
await userStore.getUserInfo();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,6 +1,6 @@
<!-- 角色授权 -->
<template>
<ArtDrawer
<FaDrawer
v-model="drawerVisible"
:title="'【' + props.roleName + '】权限分配'"
:size="drawerSize"
@@ -143,14 +143,14 @@
<ElButton type="primary" :loading="loading" @click.stop="handleDrawerSave">确 定</ElButton>
</div>
</template>
</ArtDrawer>
</FaDrawer>
</template>
<script setup lang="ts">
import { computed, ref, watch, onMounted } from "vue";
import { QuestionFilled, Switch as SwitchIcon } from "@element-plus/icons-vue";
import type { TreeInstance } from "element-plus";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import { listToTree, formatTree } from "@utils/common";
import RoleAPI, {
permissionDataType,
@@ -1,7 +1,7 @@
<!-- 角色管理:Art + useTable;操作列最多 3 个外露 +「更多」 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:role:create']"
:perm-export="['module_system:role:export']"
@@ -38,10 +38,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -52,7 +52,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="720px"
@@ -113,7 +113,7 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="roleFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -134,7 +134,7 @@
<ElRadio value="1">停用</ElRadio>
</ElRadioGroup>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</template>
@@ -152,7 +152,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<PermissonDrawer
v-if="drawerVisible"
@@ -162,7 +162,7 @@
@saved="refreshData"
/>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="roleExportContentConfig"
:query-params="exportQueryParams"
@@ -175,17 +175,17 @@
<script setup lang="ts">
import { h, computed, ref, reactive } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
import type { IObject } from "@/components/Core/modal/types";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import type { IObject } from "@/components/modal/types";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import RoleAPI, {
type RoleForm,
@@ -345,7 +345,7 @@ const searchForm = ref<RoleSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -390,7 +390,7 @@ const roleSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<RoleTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -420,7 +420,7 @@ function deleteRoleRow(id: number) {
const userStore = useUserStore();
await userStore.getUserInfo();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -560,7 +560,7 @@ const paginationBind = computed(() => {
const detailFormData = ref<RoleTable>({} as RoleTable);
const formData = reactive<RoleForm>({
const formData = ref<RoleForm>({
id: undefined,
name: undefined,
order: 1,
@@ -591,7 +591,7 @@ const rules = reactive({
status: [{ required: true, message: "请选择状态", trigger: "blur" }],
});
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const roleFormRenderKey = ref(0);
const roleDialogFormItems = computed<FormItem[]>(() => [
@@ -744,7 +744,7 @@ function handleBatchDelete() {
const userStore = useUserStore();
await userStore.getUserInfo();
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -1,7 +1,7 @@
<!-- 租户管理:Art + useTable;操作列前 3 个为 ArtButtonTable,其余收入「更多」下拉 -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:tenant:create']"
:perm-delete="['module_system:tenant:delete']"
@@ -34,10 +34,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
:loading="loading"
:data="data"
:columns="columns"
@@ -48,7 +48,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="640px"
@@ -87,7 +87,7 @@
</template>
<template v-else>
<ElScrollbar max-height="75vh" :view-style="{ overflowX: 'hidden' }">
<ArtForm
<FaForm
:key="tenantFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -119,22 +119,22 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
<script setup lang="ts">
import { h, computed, ref, reactive } from "vue";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtButtonTable from "@/components/Core/forms/art-button-table/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import ArtButtonTable from "@/components/forms/fa-button-table/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import type { ColumnOption } from "@/types/component";
import TenantAPI, {
type TenantCreateForm,
@@ -300,7 +300,7 @@ const searchForm = ref<TenantSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -353,7 +353,7 @@ const tenantSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<TenantTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -373,7 +373,7 @@ function deleteTenantRow(id: number) {
.then(async () => {
await TenantAPI.deleteTenant([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -455,7 +455,7 @@ const detailFormData = ref<TenantTable>({ code: "", name: "", status: "0" });
const currentEditId = ref<number | null>(null);
const formData = reactive<TenantForm>({
const formData = ref<TenantForm>({
name: "",
code: "",
status: "0",
@@ -502,7 +502,7 @@ const initialFormData: TenantForm = {
end_time: undefined,
};
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const submitLoading = ref(false);
const tenantFormRenderKey = ref(0);
@@ -672,7 +672,7 @@ function handleBatchDelete() {
batchDeleting.value = true;
await TenantAPI.deleteTenant(ids);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
} finally {
batchDeleting.value = false;
@@ -15,8 +15,8 @@
</template>
<script setup lang="ts">
import type { ISelectConfig } from "@/components/TableSelect/index.vue";
import UserAPI from "@/api/module_system/user";
import type { ISelectConfig } from "@/components/others/fa-table-select/index.vue";
import UserAPI, { UserPageQuery } from "@/api/module_system/user";
// 父组件双向绑定的值(选中用户ID)
const props = defineProps<{ modelValue?: number }>();
@@ -29,7 +29,7 @@ const emit = defineEmits<{
const selectConfig: ISelectConfig = {
pk: "id",
/** 与 ArtSearchBar 栅格内 ElInput 一致,占满表单项内容区 */
/** 与 FaSearchBar 栅格内 ElInput 一致,占满表单项内容区 */
width: "100%",
placeholder: "请选择用户",
popover: {
@@ -54,7 +54,7 @@ const selectConfig: ISelectConfig = {
],
},
],
indexAction(params) {
indexAction(params: UserPageQuery) {
// 映射查询参数到后端接口
const query: any = { ...params };
// 清理空字符串/空值,避免后端 422
@@ -22,7 +22,7 @@
</div>
<div class="user-main-panel flex flex-col flex-grow min-w-0 min-h-0">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -45,20 +45,17 @@
@clear-click="afterUserSelectSearch"
/>
</template>
</ArtSearchBar>
</FaSearchBar>
<ElCard
class="flex flex-col flex-1 min-h-0 art-table-card"
:style="{ 'margin-top': showSearchBar ? '12px' : '0' }"
>
<ArtTableHeader
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_system:user:create']"
:perm-import="['module_system:user:import']"
@@ -74,10 +71,10 @@
@more="handleMoreClick"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="loading"
:data="data"
@@ -91,7 +88,7 @@
</div>
</div>
<ArtDrawer
<FaDrawer
v-model="dialogVisible.visible"
:title="dialogVisible.title"
append-to-body
@@ -294,7 +291,7 @@
<ElButton v-else type="primary" @click="handleCloseDialog">确定</ElButton>
</div>
</template>
</ArtDrawer>
</FaDrawer>
<ArtImportDialog
v-model="importModalVisible"
@@ -304,7 +301,7 @@
@upload="handleImportUpload"
/>
<ArtExportDialog
<FaExportDialog
v-model="exportModalVisible"
:content-config="userExportContentConfig"
:query-params="exportQueryParams"
@@ -326,15 +323,15 @@ import { useAppStore } from "@stores/modules/app.store";
import { DeviceEnum } from "@/enums/settings/device.enum";
import { ResultEnum } from "@/enums/api/result.enum";
import { useTable } from "@/hooks/core/useTable";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import ArtImportDialog from "@/components/Core/modal/art-import-dialog/index.vue";
import ArtExportDialog from "@/components/Core/modal/art-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/Core/modal/types";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import ArtImportDialog from "@/components/modal/fa-import-dialog/index.vue";
import FaExportDialog from "@/components/modal/fa-export-dialog/index.vue";
import type { IContentConfig, IObject } from "@/components/modal/types";
import UserAPI, {
type UserForm,
type UserInfo,
@@ -479,7 +476,7 @@ const searchForm = ref<UserSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const statusOptions = ref([
@@ -538,7 +535,7 @@ const userSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<UserInfo[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => id != null && !Number.isNaN(id))
@@ -579,7 +576,7 @@ function deleteUserRow(id: number) {
} else {
ElMessage.success("删除成功");
}
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -732,22 +729,7 @@ const userExportContentConfig = computed(() => ({
},
}));
const paginationBind = computed(() => {
const p = pagination as unknown as {
current?: number;
size?: number;
total?: number;
page_no?: number;
page_size?: number;
};
return {
current: p.current ?? p.page_no ?? 1,
size: p.size ?? p.page_size ?? 20,
total: p.total ?? 0,
};
});
const formData = reactive<UserForm>({
const formData = ref<UserForm>({
id: undefined,
username: undefined,
name: undefined,
@@ -1,7 +1,7 @@
<!-- 调度任务:Art + useTable(主列表卡片;抽屉内表格) -->
<template>
<div class="art-full-height job-page flex flex-col min-h-0">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -21,7 +21,7 @@
class="flex flex-1 min-h-0 flex-col art-table-card"
:style="{ 'margin-top': showSearchBar ? '12px' : '0' }"
>
<ArtTableHeader
<FaTableHeader
v-model:columns="jobColumnChecks"
v-model:showSearchBar="showSearchBar"
layout="search,refresh"
@@ -120,7 +120,7 @@
</div>
</div>
</template>
</ArtTableHeader>
</FaTableHeader>
<div v-loading="jobLoading" class="job-cards-container min-h-0 flex-1 overflow-auto">
<ElEmpty
@@ -254,7 +254,7 @@
</div>
</ElCard>
<ArtDialog v-model="consoleVisible" title="调度器控制台" width="900px">
<FaDialog v-model="consoleVisible" title="调度器控制台" width="900px">
<div class="terminal-wrapper">
<Terminal name="scheduler-console" :show-header="false" theme="dark" />
</div>
@@ -263,11 +263,11 @@
<ElButton @click="handleClearConsole">清空</ElButton>
<ElButton type="primary" @click="consoleVisible = false">关闭</ElButton>
</template>
</ArtDialog>
</FaDialog>
<ArtDrawer v-model="executionLogDrawerVisible" title="执行记录" direction="rtl" size="80%">
<FaDrawer v-model="executionLogDrawerVisible" title="执行记录" direction="rtl" size="80%">
<div class="execution-log-drawer flex flex-col min-h-0">
<ArtSearchBar
<FaSearchBar
ref="logSearchBarRef"
v-model="logSearchForm"
:items="logSearchItems"
@@ -282,23 +282,23 @@
@reset="onLogResetSearch"
/>
<ElCard class="art-table-card log-table-card mt-3 flex flex-1 min-h-0 flex-col">
<ArtTableHeader
<FaTableHeader
v-model:columns="logColumnChecks"
layout="search,refresh"
:loading="logLoading"
@refresh="refreshLogData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="logSelectedIds"
:perm-delete="['module_task:cronjob:job:delete']"
:delete-loading="logBatchDeleting"
@delete="handleLogBatchDelete"
/>
</template>
</ArtTableHeader>
<ArtTable
ref="logArtTableRef"
</FaTableHeader>
<FaTable
ref="logFaTableRef"
row-key="id"
:loading="logLoading"
:data="logTableData"
@@ -331,17 +331,17 @@
删除
</ElButton>
</template>
</ArtTable>
</FaTable>
</ElCard>
</div>
</ArtDrawer>
</FaDrawer>
<ArtDialog v-model="jobStateVisible" title="执行元数据" width="800px">
<FaDialog v-model="jobStateVisible" title="执行元数据" width="800px">
<JsonPretty :value="jobStateData" height="400px" />
<template #footer>
<ElButton type="primary" @click="jobStateVisible = false">关闭</ElButton>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -352,13 +352,13 @@ defineOptions({
});
import JobAPI, { SchedulerStatus, SchedulerJob, JobLogTable } from "@/api/module_task/cronjob/job";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtDrawer from "@/components/Core/modal/art-drawer/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaDrawer from "@/components/modal/fa-drawer/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import JsonPretty from "@/components/JsonPretty/index.vue";
import { useTable } from "@/hooks/core/useTable";
import type { ColumnOption } from "@/types/component";
@@ -391,7 +391,7 @@ const searchForm = ref<JobSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const jobSearchItems = computed<SearchFormItem[]>(() => [
@@ -429,39 +429,50 @@ async function loadSchedulerStatus() {
}
}
const {
data: jobList,
loading: jobLoading,
columnChecks: jobColumnChecks,
getData: getJobList,
replaceSearchParams: replaceJobSearchParams,
resetSearchParams: resetJobSearchParams,
refreshData: refreshJobList,
} = useTable({
core: {
apiFn: JobAPI.getSchedulerJobs,
apiParams: {
page_no: 1,
page_size: 10,
},
columnsFactory: (): ColumnOption<SchedulerJob>[] => [
{ type: "selection", width: 48, fixed: "left" },
{ type: "globalIndex", width: 56, label: "序号" },
{ prop: "id", label: "任务ID", minWidth: 80, showOverflowTooltip: true },
{ prop: "name", label: "任务名称", minWidth: 140, showOverflowTooltip: true },
{ prop: "trigger", label: "触发器", minWidth: 120, showOverflowTooltip: true },
{ prop: "next_run_time", label: "下次执行时间", minWidth: 200, showOverflowTooltip: true },
{ prop: "status", label: "状态", minWidth: 80, showOverflowTooltip: true },
],
},
hooks: {
onSuccess: () => {
void loadSchedulerStatus();
},
},
});
/** 调度器任务列表为全量列表接口,无分页;筛选在前端完成 */
const jobList = ref<SchedulerJob[]>([]);
const jobLoading = ref(false);
/** 主区域为卡片列表无表格列配置,仅占位满足 FaTableHeader v-model */
const jobColumnChecks = ref<ColumnOption<SchedulerJob>[]>([]);
async function handleJobSearchBarSearch(params: JobSearchForm) {
function matchesJobStatusFilter(jobStatus: string | undefined, filter?: string): boolean {
if (!filter) return true;
const map: Record<string, string[]> = {
运行中: ["运行中"],
暂停: ["暂停", "暂停中"],
停止: ["停止", "已停止"],
};
const aliases = map[filter];
if (!aliases) return true;
const s = jobStatus ?? "";
return aliases.some((a) => s === a || s.includes(a));
}
async function fetchSchedulerJobs() {
jobLoading.value = true;
try {
const res = await JobAPI.getSchedulerJobs();
const raw = res.data?.data;
const list: SchedulerJob[] = Array.isArray(raw) ? raw : [];
const nameQ = searchForm.value.name?.trim();
const statusQ = searchForm.value.status;
jobList.value = list.filter((j) => {
if (nameQ && !(j.name ?? "").includes(nameQ)) return false;
if (!matchesJobStatusFilter(j.status, statusQ)) return false;
return true;
});
await loadSchedulerStatus();
} catch (error: unknown) {
console.error(error);
jobList.value = [];
} finally {
jobLoading.value = false;
}
}
const refreshJobList = fetchSchedulerJobs;
async function handleJobSearchBarSearch() {
await searchBarRef.value?.validate?.();
replaceJobSearchParams(buildJobReplaceParams(params));
getJobList();
@@ -492,7 +503,7 @@ const logSearchForm = ref<LogSearchForm>({
trigger_type: undefined,
});
const logSearchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const logSearchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const logSearchBarRules: Record<string, unknown> = {};
const logSearchItems = computed<SearchFormItem[]>(() => [
@@ -533,7 +544,7 @@ const logSearchItems = computed<SearchFormItem[]>(() => [
]);
const currentLogJobId = ref<string | undefined>(undefined);
const logArtTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const logFaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const logSelectedRows = ref<JobLogTable[]>([]);
const logSelectedIds = computed(() =>
logSelectedRows.value.map((r) => r.id).filter((id): id is number => typeof id === "number")
@@ -659,7 +670,7 @@ function deleteLogRow(id: number | undefined) {
.then(async () => {
await JobAPI.deleteJobLog([id]);
ElMessage.success("删除成功");
logArtTableRef.value?.elTableRef?.clearSelection();
logFaTableRef.value?.elTableRef?.clearSelection();
await refreshLogRemove();
})
.catch(() => {});
@@ -1,7 +1,7 @@
<!-- 定时任务节点:Art + useTable -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_task:cronjob:node:create']"
:perm-delete="['module_task:cronjob:node:delete']"
@@ -34,10 +34,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="loading"
:data="data"
@@ -49,7 +49,7 @@
/>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible.visible"
:title="dialogVisible.title"
width="1000px"
@@ -59,7 +59,7 @@
<ElSplitter direction="horizontal" style="height: 500px">
<ElSplitterPanel size="300px" :min="200" :max="400">
<ElScrollbar style="height: 100%">
<ArtForm
<FaForm
:key="nodeFormRenderKey"
ref="dataFormRef"
v-model="formData"
@@ -144,7 +144,7 @@
:max="10"
/>
</template>
</ArtForm>
</FaForm>
</ElScrollbar>
</ElSplitterPanel>
@@ -172,15 +172,15 @@
<ElButton type="primary" :loading="submitLoading" @click="handleSubmit">确定</ElButton>
</div>
</template>
</ArtDialog>
</FaDialog>
<ArtDialog
<FaDialog
v-model="executeDialogVisible"
title="调试节点"
width="700px"
@close="handleCloseExecuteDialog"
>
<ArtForm
<FaForm
:key="executeFormRenderKey"
ref="executeFormRef"
v-model="executeFormData"
@@ -255,13 +255,13 @@
/>
</template>
</template>
</ArtForm>
</FaForm>
<template #footer>
<ElButton @click="handleCloseExecuteDialog">取消</ElButton>
<ElButton type="primary" :loading="submitLoading" @click="handleExecuteNode">确认</ElButton>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -273,14 +273,14 @@ defineOptions({
import NodeAPI, { NodeTable, NodeForm, TriggerType } from "@/api/module_task/cronjob/node";
import { useDictStore } from "@stores/index";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import type { ColumnOption } from "@/types/component";
import { useAuth } from "@/hooks/core/useAuth";
import { renderTableOperationCell, type TableOperationAction } from "@utils/table";
@@ -321,7 +321,7 @@ const searchForm = ref<NodeSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const nodeSearchItems = computed<SearchFormItem[]>(() => [
@@ -343,7 +343,7 @@ const nodeSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<NodeTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => typeof id === "number")
@@ -364,7 +364,7 @@ function deleteNodeRow(id: number | undefined) {
.then(async () => {
await NodeAPI.deleteNode([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -539,8 +539,8 @@ const codeEditorOptions: EditorConfiguration = {
autofocus: false,
};
const dataFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const executeFormRef = ref<InstanceType<typeof ArtForm> | null>(null);
const dataFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const executeFormRef = ref<InstanceType<typeof FaForm> | null>(null);
const nodeFormRenderKey = ref(0);
const executeFormRenderKey = ref(0);
const submitLoading = ref(false);
@@ -598,7 +598,7 @@ const defaultCodeBlock = `def handler(*args, **kwargs):
}
`;
const formData = reactive<NodeForm>({
const formData = ref<NodeForm>({
id: undefined,
name: "",
code: undefined,
@@ -8,7 +8,7 @@
</div>
<div class="panel-content">
<ArtForm
<FaForm
v-model="formData"
:items="edgeFormItems"
label-width="80px"
@@ -23,7 +23,7 @@
<template #color>
<ElColorPicker v-model="formData.color" />
</template>
</ArtForm>
</FaForm>
<div class="panel-actions">
<ElButton type="primary" size="small" @click="handleSave">保存</ElButton>
@@ -37,7 +37,7 @@
import { ref, watch, computed } from "vue";
import { ElButton, ElColorPicker, ElMessage, ElIcon } from "element-plus";
import { Close } from "@element-plus/icons-vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
const props = defineProps({
edge: {
@@ -8,7 +8,7 @@
</div>
<div class="panel-content">
<ArtForm
<FaForm
v-model="formData"
:items="nodePanelFormItems"
label-width="80px"
@@ -45,7 +45,7 @@
<div class="field-hint">JSON 格式的关键字参数</div>
</div>
</template>
</ArtForm>
</FaForm>
<div class="panel-actions">
<ElButton type="primary" size="small" @click="handleSave">保存</ElButton>
@@ -59,8 +59,8 @@
import { ref, watch, onMounted, computed } from "vue";
import { ElButton, ElInput, ElSelect, ElOption, ElMessage, ElIcon } from "element-plus";
import { Close } from "@element-plus/icons-vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import WorkflowNodeTypeAPI, {
type WorkflowNodeTypeOption,
} from "@/api/module_task/workflow/node-type";
@@ -13,7 +13,7 @@
<ElScrollbar style="height: 100%">
<div class="panel-section">
<div class="section-title">基础信息</div>
<ArtForm
<FaForm
ref="formRef"
v-model="formData"
:items="workflowBaseFormItems"
@@ -201,8 +201,8 @@ import "element-plus/dist/index.css";
import DynamicNode from "./DynamicNode.vue";
import NodeConfigPanel from "./NodeConfigPanel.vue";
import EdgeConfigPanel from "./EdgeConfigPanel.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import WorkflowDefinitionAPI, {
type WorkflowTable,
type WorkflowForm,
@@ -227,10 +227,10 @@ const props = defineProps({
const emit = defineEmits(["update:visible", "refresh"]);
const formRef = ref<InstanceType<typeof ArtForm> | null>(null);
const formRef = ref<InstanceType<typeof FaForm> | null>(null);
const workflowId = ref<number>();
const formData = reactive<Partial<WorkflowForm>>({
const formData = ref<Partial<WorkflowForm>>({
code: "",
name: "",
description: "",
@@ -1,7 +1,7 @@
<!-- 工作流定义:Art + useTable -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_task:workflow:definition:create']"
:perm-delete="['module_task:workflow:definition:delete']"
@@ -34,10 +34,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="loading"
:data="data"
@@ -97,7 +97,7 @@
</ElButton>
</ElSpace>
</template>
</ArtTable>
</FaTable>
</ElCard>
<WorkflowDesignDrawer
@@ -115,11 +115,11 @@ defineOptions({
});
import WorkflowDefinitionAPI, { type WorkflowTable } from "@/api/module_task/workflow/definition";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import { useTable } from "@/hooks/core/useTable";
import type { ColumnOption } from "@/types/component";
import { ArrowDown } from "@element-plus/icons-vue";
@@ -150,7 +150,7 @@ const searchForm = ref<WorkflowSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const workflowSearchItems = computed<SearchFormItem[]>(() => [
@@ -187,7 +187,7 @@ const workflowSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<WorkflowTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => typeof id === "number")
@@ -208,7 +208,7 @@ function deleteWorkflowRow(id: number | undefined) {
.then(async () => {
await WorkflowDefinitionAPI.deleteWorkflow([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -1,7 +1,7 @@
<!-- 工作流节点类型:Art + useTable -->
<template>
<div class="art-full-height">
<ArtSearchBar
<FaSearchBar
v-show="showSearchBar"
ref="searchBarRef"
v-model="searchForm"
@@ -18,14 +18,14 @@
/>
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
<FaTableHeader
v-model:columns="columnChecks"
v-model:showSearchBar="showSearchBar"
:loading="loading"
@refresh="refreshData"
>
<template #left>
<ArtTableHeaderLeft
<FaTableHeaderLeft
:remove-ids="selectedIds"
:perm-create="['module_task:workflow:node-type:create']"
:perm-delete="['module_task:workflow:node-type:delete']"
@@ -34,10 +34,10 @@
@delete="handleBatchDelete"
/>
</template>
</ArtTableHeader>
</FaTableHeader>
<ArtTable
ref="artTableRef"
<FaTable
ref="FaTableRef"
row-key="id"
:loading="loading"
:data="data"
@@ -71,17 +71,17 @@
</ElButton>
</ElSpace>
</template>
</ArtTable>
</FaTable>
</ElCard>
<ArtDialog
<FaDialog
v-model="dialogVisible"
:title="dialogTitle"
width="720px"
destroy-on-close
@close="handleCloseDialog"
>
<ArtForm
<FaForm
:key="nodeTypeFormRenderKey"
ref="formRef"
v-model="form"
@@ -99,7 +99,7 @@
<ElButton @click="dialogVisible = false">取消</ElButton>
<ElButton type="primary" :loading="submitting" @click="submitForm">保存</ElButton>
</template>
</ArtDialog>
</FaDialog>
</div>
</template>
@@ -113,14 +113,14 @@ import WorkflowNodeTypeAPI, {
type WorkflowNodeTypeForm,
type WorkflowNodeTypeTable,
} from "@/api/module_task/workflow/node-type";
import ArtSearchBar from "@/components/Core/forms/art-search-bar/index.vue";
import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue";
import ArtTable from "@/components/Core/tables/art-table/index.vue";
import ArtTableHeader from "@/components/Core/tables/art-table-header/index.vue";
import ArtTableHeaderLeft from "@/components/Core/tables/art-table-header-left/index.vue";
import ArtDialog from "@/components/Core/modal/art-dialog/index.vue";
import ArtForm from "@/components/Core/forms/art-form/index.vue";
import type { FormItem } from "@/components/Core/forms/art-form/index.vue";
import FaSearchBar from "@/components/forms/fa-search-bar/index.vue";
import type { SearchFormItem } from "@/components/forms/fa-search-bar/index.vue";
import FaTable from "@/components/tables/fa-table/index.vue";
import FaTableHeader from "@/components/tables/fa-table-header/index.vue";
import FaTableHeaderLeft from "@/components/tables/fa-table-header-left/index.vue";
import FaDialog from "@/components/modal/fa-dialog/index.vue";
import FaForm from "@/components/forms/fa-form/index.vue";
import type { FormItem } from "@/components/forms/fa-form/index.vue";
import { useTable } from "@/hooks/core/useTable";
import type { ColumnOption } from "@/types/component";
import { ElMessage, ElMessageBox, ElTag } from "element-plus";
@@ -150,7 +150,7 @@ const searchForm = ref<NodeTypeSearchForm>({
});
const showSearchBar = ref(true);
const searchBarRef = ref<InstanceType<typeof ArtSearchBar> | null>(null);
const searchBarRef = ref<InstanceType<typeof FaSearchBar> | null>(null);
const searchBarRules: Record<string, unknown> = {};
const nodeTypeSearchItems = computed<SearchFormItem[]>(() => [
@@ -188,7 +188,7 @@ const nodeTypeSearchItems = computed<SearchFormItem[]>(() => [
},
]);
const artTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const FaTableRef = ref<{ elTableRef?: { clearSelection: () => void } } | null>(null);
const selectedRows = ref<WorkflowNodeTypeTable[]>([]);
const selectedIds = computed(() =>
selectedRows.value.map((r) => r.id).filter((id): id is number => typeof id === "number")
@@ -219,7 +219,7 @@ function deleteNodeTypeRow(id: number | undefined) {
.then(async () => {
await WorkflowNodeTypeAPI.deleteWorkflowNodeType([id]);
ElMessage.success("删除成功");
artTableRef.value?.elTableRef?.clearSelection();
FaTableRef.value?.elTableRef?.clearSelection();
await refreshRemove();
})
.catch(() => {});
@@ -365,7 +365,7 @@ const dialogVisible = ref(false);
const dialogTitle = ref("新增节点类型");
const editingId = ref<number | null>(null);
const submitting = ref(false);
const formRef = ref<InstanceType<typeof ArtForm> | null>(null);
const formRef = ref<InstanceType<typeof FaForm> | null>(null);
const nodeTypeFormRenderKey = ref(0);
const nodeTypeDialogFormItems = computed<FormItem[]>(() => [