Compare commits

...

3 Commits

Author SHA1 Message Date
duanshuwen
2b3e6da35f chore(system-resource-page): 优化系统资源页面的模板代码与文案
格式化页面内所有组件的代码排版,统一换行与缩进提升可读性;移除页面顶部介绍中的「按 RuoYi 风格」文案;调整菜单列表的排序列展示为静态显示排序值
2026-08-27 10:39:13 +08:00
duanshuwen
041d65566e fix: correct menu activation status display 2026-08-27 10:26:12 +08:00
duanshuwen
1efd0d1857 fix: align dashboard lead presentation 2026-08-27 10:11:24 +08:00
5 changed files with 244 additions and 51 deletions

View File

@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
import { buildSystemTree, dataScopeLabel, filterSystemTree } from "@/lib/system-resource";
import { buildSystemTree, dataScopeLabel, filterSystemTree, hydrateMenuTree } from "@/lib/system-resource";
import type { SystemMenuItem, SystemMenuTreeItem } from "@/types";
describe("system resource tree helpers", () => {
const items = [
@@ -21,6 +22,28 @@ describe("system resource tree helpers", () => {
]);
});
it("hydrates menu tree nodes with status fields from the flat response", () => {
const flatItems = [{
id: "dashboard",
name: "仪表盘",
type: "page",
parentId: null,
sortOrder: 10,
isVisible: true,
isActive: true,
}] as SystemMenuItem[];
const tree = [{
id: "dashboard",
name: "仪表盘",
type: "page",
parentId: null,
sortOrder: 10,
children: [],
}] as unknown as SystemMenuTreeItem[];
expect(hydrateMenuTree(tree, flatItems)[0]).toMatchObject({ isVisible: true, isActive: true });
});
it("uses RuoYi-compatible Chinese labels for data scope", () => {
expect(dataScopeLabel("all")).toBe("全部数据");
expect(dataScopeLabel("dept_and_children")).toBe("本部门及以下");

View File

@@ -1,6 +1,6 @@
import { ref, watch, type Ref } from "vue";
import { getSystemResource } from "@/api/client";
import type { SystemRoleItem } from "@/types";
import type { SystemMenuItem, SystemMenuTreeItem, SystemRoleItem } from "@/types";
export type SystemResourceResponse = { items: unknown[] };
export type SystemResourceFetcher = (resource: string) => Promise<SystemResourceResponse>;
@@ -25,6 +25,18 @@ export function buildSystemTree<T extends TreeSource>(items: T[]): Array<SystemT
return roots;
}
export function hydrateMenuTree(tree: SystemMenuTreeItem[], items: readonly SystemMenuItem[]): SystemMenuTreeItem[] {
const itemMap = new Map(items.map((item) => [item.id, item]));
const hydrate = (nodes: SystemMenuTreeItem[]): SystemMenuTreeItem[] => nodes.map((node) => {
const item = itemMap.get(node.id);
return {
...(item ? { ...item, ...node } : node),
children: hydrate(node.children ?? []),
};
});
return hydrate(tree);
}
export function filterSystemTree<T extends TreeSource>(nodes: Array<SystemTreeNode<T>>, keyword: string): Array<SystemTreeNode<T>> {
const normalized = keyword.trim().toLowerCase();
if (!normalized) return nodes;

View File

@@ -0,0 +1,18 @@
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
describe("DashboardPage lead presentation", () => {
it("uses the same labels and date formatting as the leads page", async () => {
const source = await readFile(
fileURLToPath(new URL("./DashboardPage.vue", import.meta.url)),
"utf8",
);
expect(source).toContain('import { leadStatusLabel } from "@/lib/leads";');
expect(source).toContain('const formatDate = (value?: string | null) =>');
expect(source).toContain('row.contactName || "未填写联系人"');
expect(source).toContain("leadStatusLabel(row.status)");
expect(source).toContain("formatDate(row.createdAt)");
});
});

View File

@@ -2,6 +2,7 @@
import { onMounted, ref } from "vue";
import { ElMessage } from "element-plus";
import { getDashboard } from "@/api/client";
import { leadStatusLabel } from "@/lib/leads";
import type { Dashboard } from "@/types";
const data = ref<Dashboard | null>(null);
@@ -11,19 +12,85 @@ const error = ref("");
async function load() {
loading.value = true;
error.value = "";
try { data.value = await getDashboard(); } catch (err) { error.value = err instanceof Error ? err.message : "仪表盘加载失败"; ElMessage.error(error.value); } finally { loading.value = false; }
try {
data.value = await getDashboard();
} catch (err) {
error.value = err instanceof Error ? err.message : "仪表盘加载失败";
ElMessage.error(error.value);
} finally {
loading.value = false;
}
}
const formatDate = (value?: string | null) => {
if (!value) return "未填写";
const date = new Date(value);
return Number.isNaN(date.valueOf())
? value
: new Intl.DateTimeFormat("zh-CN", {
dateStyle: "medium",
timeStyle: "short",
}).format(date);
};
onMounted(load);
</script>
<template>
<div class="page-stack">
<div class="page-intro"><div><p class="eyebrow">TODAY / SNAPSHOT</p><h2>运营概览</h2><p>快速查看当前内容和需求线索的状态</p></div><el-button :loading="loading" @click="load">刷新数据</el-button></div>
<div class="page-intro">
<div>
<p class="eyebrow">TODAY / SNAPSHOT</p>
<h2>运营概览</h2>
<p>快速查看当前内容和需求线索的状态</p>
</div>
<el-button :loading="loading" @click="load">刷新数据</el-button>
</div>
<el-alert v-if="error" :title="error" type="error" show-icon :closable="false" />
<div v-if="loading" class="loading-grid"><el-skeleton v-for="item in 2" :key="item" animated /></div>
<div v-if="loading" class="loading-grid">
<el-skeleton v-for="item in 2" :key="item" animated />
</div>
<template v-else-if="data">
<div class="metric-grid"><el-card shadow="never" class="metric-card"><span>待处理线索</span><strong>{{ data.stats.newLeadCount }}</strong><small>需要及时跟进</small></el-card><el-card shadow="never" class="metric-card accent"><span>全部线索</span><strong>{{ data.stats.leadCount }}</strong><small>持续沉淀中的需求</small></el-card></div>
<el-card shadow="never" class="panel-card"><template #header><div class="panel-heading"><span>最近线索</span><el-tag type="info" effect="plain">最多 5 </el-tag></div></template><el-empty v-if="!data.recentLeads.length" description="暂无线索" /><el-table v-else :data="data.recentLeads" stripe><el-table-column prop="contactName" label="联系人" /><el-table-column prop="phone" label="联系方式" /><el-table-column prop="destination" label="目的地" /><el-table-column prop="status" label="状态" /><el-table-column prop="createdAt" label="提交时间" /></el-table></el-card>
<div class="metric-grid">
<el-card shadow="never" class="metric-card">
<span>待处理线索</span>
<strong>{{ data.stats.newLeadCount }}</strong>
<small>需要及时跟进</small>
</el-card>
<el-card shadow="never" class="metric-card accent">
<span>全部线索</span>
<strong>{{ data.stats.leadCount }}</strong>
<small>持续沉淀中的需求</small>
</el-card>
</div>
<el-card shadow="never" class="panel-card">
<template #header>
<div class="panel-heading">
<span>最近线索</span>
<el-tag type="info" effect="plain">最多 5 </el-tag>
</div>
</template>
<el-empty v-if="!data.recentLeads.length" description="暂无线索" />
<el-table v-else :data="data.recentLeads" stripe>
<el-table-column label="联系人">
<template #default="{ row }">
{{ row.contactName || "未填写联系人" }}
</template>
</el-table-column>
<el-table-column prop="phone" label="联系方式" />
<el-table-column prop="destination" label="目的地" />
<el-table-column label="状态">
<template #default="{ row }">
{{ leadStatusLabel(row.status) }}
</template>
</el-table-column>
<el-table-column label="提交时间">
<template #default="{ row }">
{{ formatDate(row.createdAt) }}
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</div>
</template>

View File

@@ -23,7 +23,7 @@ import {
import LayoutIcon from "@/components/layout/LayoutIcon.vue";
import SystemResourceEditor, { type SystemEditorSavePayload, type SystemResourceName } from "@/components/system/SystemResourceEditor.vue";
import { getMenuIconName } from "@/lib/menu-display";
import { buildSystemTree, dataScopeLabel, filterSystemTree } from "@/lib/system-resource";
import { buildSystemTree, dataScopeLabel, filterSystemTree, hydrateMenuTree } from "@/lib/system-resource";
import type {
SystemDeptCreate,
SystemDeptItem,
@@ -144,7 +144,8 @@ async function loadResource() {
if (resource.value === "menus") {
const result = await getSystemMenus();
menuItems.value = result.items;
menuTree.value = result.tree?.length ? result.tree : buildMenuTree(result.items);
const responseTree = result.tree?.length ? result.tree : buildMenuTree(result.items);
menuTree.value = hydrateMenuTree(responseTree, result.items);
items.value = result.items;
}
if (resource.value === "depts") {
@@ -358,39 +359,64 @@ onMounted(loadResource);
<template>
<div class="page-stack system-resource-page">
<div class="page-intro">
<div><p class="eyebrow">SYSTEM / RBAC</p><h2>{{ title }}</h2><p> RuoYi 风格维护系统{{ resourceLabel }}权限和数据范围</p></div>
<div>
<p class="eyebrow">SYSTEM / RBAC</p>
<h2>{{ title }}</h2>
<p>维护系统{{ resourceLabel }}权限和数据范围</p>
</div>
</div>
<el-card v-if="resource === 'menus'" shadow="never" class="panel-card system-filter-card">
<el-form inline @submit.prevent="searchResource">
<el-form-item label="菜单名称"><el-input v-model="menuQuery.name" clearable placeholder="请输入菜单名称、路径或权限" /></el-form-item>
<el-form-item label="菜单类型"><el-select v-model="menuQuery.type" clearable placeholder="全部类型" style="width: 150px"><el-option label="全部类型" value="" /><el-option label="目录" value="directory" /><el-option label="页面" value="page" /><el-option label="按钮" value="button" /></el-select></el-form-item>
<el-form-item label="状态"><el-select v-model="menuQuery.status" clearable placeholder="全部状态" style="width: 150px"><el-option label="全部状态" value="" /><el-option label="正常" value="enabled" /><el-option label="停用" value="disabled" /></el-select></el-form-item>
<el-form-item><el-button type="primary" @click="searchResource">搜索</el-button><el-button @click="resetMenuQuery">重置</el-button></el-form-item>
<el-form-item label="菜单名称"><el-input v-model="menuQuery.name" clearable
placeholder="请输入菜单名称、路径或权限" /></el-form-item>
<el-form-item label="菜单类型"><el-select v-model="menuQuery.type" clearable placeholder="全部类型"
style="width: 150px"><el-option label="全部类型" value="" /><el-option label="目录" value="directory" /><el-option
label="页面" value="page" /><el-option label="按钮" value="button" /></el-select></el-form-item>
<el-form-item label="状态"><el-select v-model="menuQuery.status" clearable placeholder="全部状态"
style="width: 150px"><el-option label="全部状态" value="" /><el-option label="正常" value="enabled" /><el-option
label="停用" value="disabled" /></el-select></el-form-item>
<el-form-item><el-button type="primary" @click="searchResource">搜索</el-button><el-button
@click="resetMenuQuery">重置</el-button></el-form-item>
</el-form>
</el-card>
<el-card v-else shadow="never" class="panel-card system-filter-card">
<el-form inline @submit.prevent="searchResource">
<template v-if="resource === 'users'">
<el-form-item label="用户名称"><el-input v-model="userQuery.keyword" clearable placeholder="请输入用户名称、邮箱" /></el-form-item>
<el-form-item label="角色"><el-select v-model="userQuery.roleId" clearable filterable placeholder="全部角色" style="width: 170px"><el-option label="全部角色" value="" /><el-option v-for="role in roles" :key="role.id" :label="role.name" :value="role.id" /></el-select></el-form-item>
<el-form-item label="部门"><el-select v-model="userQuery.deptId" clearable filterable placeholder="全部部门" style="width: 170px"><el-option label="全部部门" value="" /><el-option v-for="dept in depts" :key="dept.id" :label="dept.name" :value="dept.id" /></el-select></el-form-item>
<el-form-item label="状态"><el-select v-model="userQuery.status" clearable placeholder="全部状态" style="width: 140px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option label="停用" value="disabled" /></el-select></el-form-item>
<el-form-item label="用户名称"><el-input v-model="userQuery.keyword" clearable
placeholder="请输入用户名称、邮箱" /></el-form-item>
<el-form-item label="角色"><el-select v-model="userQuery.roleId" clearable filterable placeholder="全部角色"
style="width: 170px"><el-option label="全部角色" value="" /><el-option v-for="role in roles" :key="role.id"
:label="role.name" :value="role.id" /></el-select></el-form-item>
<el-form-item label="部门"><el-select v-model="userQuery.deptId" clearable filterable placeholder="全部部门"
style="width: 170px"><el-option label="全部部门" value="" /><el-option v-for="dept in depts" :key="dept.id"
:label="dept.name" :value="dept.id" /></el-select></el-form-item>
<el-form-item label="状态"><el-select v-model="userQuery.status" clearable placeholder="全部状态"
style="width: 140px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option
label="停用" value="disabled" /></el-select></el-form-item>
</template>
<template v-else-if="resource === 'roles'">
<el-form-item label="角色名称"><el-input v-model="roleQuery.keyword" clearable placeholder="请输入角色名称或编码" /></el-form-item>
<el-form-item label="状态"><el-select v-model="roleQuery.status" clearable placeholder="全部状态" style="width: 150px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option label="停用" value="disabled" /></el-select></el-form-item>
<el-form-item label="角色名称"><el-input v-model="roleQuery.keyword" clearable
placeholder="请输入角色名称或编码" /></el-form-item>
<el-form-item label="状态"><el-select v-model="roleQuery.status" clearable placeholder="全部状态"
style="width: 150px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option
label="停用" value="disabled" /></el-select></el-form-item>
</template>
<template v-else>
<el-form-item label="部门名称"><el-input v-model="deptQuery.keyword" clearable placeholder="请输入部门名称" /></el-form-item>
<el-form-item label="状态"><el-select v-model="deptQuery.status" clearable placeholder="全部状态" style="width: 150px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option label="停用" value="disabled" /></el-select></el-form-item>
<el-form-item label="部门名称"><el-input v-model="deptQuery.keyword" clearable
placeholder="请输入部门名称" /></el-form-item>
<el-form-item label="状态"><el-select v-model="deptQuery.status" clearable placeholder="全部状态"
style="width: 150px"><el-option label="全部状态" value="" /><el-option label="启用" value="enabled" /><el-option
label="停用" value="disabled" /></el-select></el-form-item>
</template>
<el-form-item><el-button type="primary" @click="searchResource">搜索</el-button><el-button @click="resetResourceQuery">重置</el-button></el-form-item>
<el-form-item><el-button type="primary" @click="searchResource">搜索</el-button><el-button
@click="resetResourceQuery">重置</el-button></el-form-item>
</el-form>
</el-card>
<el-alert v-if="error" :title="error" type="error" show-icon :closable="false"><template #default><el-button link type="primary" @click="loadResource">重试</el-button></template></el-alert>
<el-alert v-if="error" :title="error" type="error" show-icon :closable="false"><template #default><el-button link
type="primary" @click="loadResource">重试</el-button></template></el-alert>
<el-card shadow="never" class="panel-card system-list-card">
<el-skeleton v-if="loading" :rows="6" animated />
<el-empty v-else-if="!visibleCount" description="暂无数据" />
@@ -398,54 +424,101 @@ onMounted(loadResource);
<div class="system-table-heading">
<div><strong>{{ title }}列表</strong><span> {{ visibleCount }} 条记录</span></div>
<div class="system-action-bar">
<el-button v-permission="createPermission" type="primary" plain @click="openCreate()">新增{{ resourceLabel }}</el-button>
<el-button v-if="resource === 'menus'" v-permission="'system:menu:sort'" type="warning" plain :loading="saving" @click="saveMenuSort">保存排序</el-button>
<el-button v-if="resource === 'menus'" plain @click="toggleMenuTree">{{ menuExpanded ? '折叠' : '展开' }}</el-button>
<el-button v-if="resource === 'depts'" plain @click="toggleDeptTree">{{ deptExpanded ? '折叠' : '展开' }}</el-button>
<el-button v-permission="createPermission" type="primary" plain @click="openCreate()">新增{{ resourceLabel
}}</el-button>
<el-button v-if="resource === 'menus'" v-permission="'system:menu:sort'" type="warning" plain
:loading="saving" @click="saveMenuSort">保存排序</el-button>
<el-button v-if="resource === 'menus'" plain @click="toggleMenuTree">{{ menuExpanded ? '折叠' : '展开'
}}</el-button>
<el-button v-if="resource === 'depts'" plain @click="toggleDeptTree">{{ deptExpanded ? '折叠' : '展开'
}}</el-button>
</div>
</div>
<el-table v-if="resource === 'menus'" :key="menuTableKey" :data="filteredMenuTree" row-key="id" :tree-props="{ children: 'children' }" :default-expand-all="menuExpanded" stripe>
<el-table-column label="菜单名称" min-width="220"><template #default="{ row }"><div class="system-menu-name"><LayoutIcon :name="getMenuIconName(row)" :size="16" /><span>{{ row.name }}</span></div></template></el-table-column>
<el-table-column label="类型" width="90"><template #default="{ row }"><el-tag :type="menuTypeTag(row.type)" effect="plain">{{ menuTypeLabel(row.type) }}</el-tag></template></el-table-column>
<el-table-column label="排序" width="120"><template #default="{ row }"><el-input-number :model-value="row.sortOrder" :min="0" :step="1" controls-position="right" @update:model-value="updateMenuSort(row.id, $event)" /></template></el-table-column>
<el-table v-if="resource === 'menus'" :key="menuTableKey" :data="filteredMenuTree" row-key="id"
:tree-props="{ children: 'children' }" :default-expand-all="menuExpanded" stripe>
<el-table-column label="菜单名称" min-width="220"><template #default="{ row }">
<div class="system-menu-name">
<LayoutIcon :name="getMenuIconName(row)" :size="16" /><span>{{ row.name }}</span>
</div>
</template></el-table-column>
<el-table-column label="类型" width="90"><template #default="{ row }"><el-tag :type="menuTypeTag(row.type)"
effect="plain">{{ menuTypeLabel(row.type) }}</el-tag></template></el-table-column>
<el-table-column label="排序" width="120"><template #default="{ row }">{{ row.sortOrder
}}</template></el-table-column>
<el-table-column prop="path" label="路由路径" min-width="150" show-overflow-tooltip />
<el-table-column prop="permission" label="权限标识" min-width="170" show-overflow-tooltip />
<el-table-column prop="component" label="组件路径" min-width="150" show-overflow-tooltip />
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive && row.isVisible ? 'success' : 'info'" effect="plain">{{ row.isActive && row.isVisible ? '正常' : '停用' }}</el-tag></template></el-table-column>
<el-table-column label="操作" width="230" fixed="right"><template #default="{ row }"><el-button v-permission="updatePermission" link type="primary" @click="openEdit(row)">修改</el-button><el-button v-if="row.type !== 'button'" v-permission="createPermission" link type="primary" @click="openCreate(row.id)">新增</el-button><el-button v-permission="deletePermission" link type="danger" :loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag
:type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? '启用' : '停用'
}}</el-tag></template></el-table-column>
<el-table-column label="操作" width="230" fixed="right"><template #default="{ row }"><el-button
v-permission="updatePermission" link type="primary" @click="openEdit(row)">修改</el-button><el-button
v-if="row.type !== 'button'" v-permission="createPermission" link type="primary"
@click="openCreate(row.id)">新增</el-button><el-button v-permission="deletePermission" link type="danger"
:loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
</el-table>
<el-table v-else-if="resource === 'users'" :key="resourceTableKey" :data="filteredUsers" stripe>
<el-table-column prop="name" label="用户名称" min-width="145" />
<el-table-column prop="email" label="登录邮箱" min-width="215" show-overflow-tooltip />
<el-table-column label="角色" min-width="150" show-overflow-tooltip><template #default="{ row }">{{ userRoleLabel(row) }}</template></el-table-column>
<el-table-column label="部门" min-width="150" show-overflow-tooltip><template #default="{ row }">{{ userDeptLabel(row) }}</template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用" }}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt) }}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="220"><template #default="{ row }"><el-button v-permission="updatePermission" link type="primary" @click="openEdit(row)">编辑</el-button><el-button v-permission="updatePermission" link type="primary" @click="resetPassword(row)">重置密码</el-button><el-button v-permission="deletePermission" link type="danger" :loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
<el-table-column label="角色" min-width="150" show-overflow-tooltip><template #default="{ row }">{{
userRoleLabel(row) }}</template></el-table-column>
<el-table-column label="部门" min-width="150" show-overflow-tooltip><template #default="{ row }">{{
userDeptLabel(row) }}</template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag
:type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用"
}}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt)
}}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="220"><template #default="{ row }"><el-button
v-permission="updatePermission" link type="primary" @click="openEdit(row)">编辑</el-button><el-button
v-permission="updatePermission" link type="primary"
@click="resetPassword(row)">重置密码</el-button><el-button v-permission="deletePermission" link
type="danger" :loading="deletingId === row.id"
@click="removeItem(row)">删除</el-button></template></el-table-column>
</el-table>
<el-table v-else-if="resource === 'roles'" :key="resourceTableKey" :data="filteredRoles" stripe>
<el-table-column prop="name" label="角色名称" min-width="150" />
<el-table-column prop="code" label="角色编码" min-width="170" />
<el-table-column label="数据范围" min-width="145"><template #default="{ row }">{{ dataScopeLabel(row.dataScope) }}</template></el-table-column>
<el-table-column label="菜单权限" width="100"><template #default="{ row }">{{ row.menuIds.length }} </template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用" }}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt) }}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="150"><template #default="{ row }"><el-button v-permission="updatePermission" link type="primary" @click="openEdit(row)">编辑</el-button><el-button v-permission="deletePermission" link type="danger" :loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
<el-table-column label="数据范围" min-width="145"><template #default="{ row }">{{ dataScopeLabel(row.dataScope)
}}</template></el-table-column>
<el-table-column label="菜单权限" width="100"><template #default="{ row }">{{ row.menuIds.length }}
</template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag
:type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用"
}}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt)
}}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="150"><template #default="{ row }"><el-button
v-permission="updatePermission" link type="primary" @click="openEdit(row)">编辑</el-button><el-button
v-permission="deletePermission" link type="danger" :loading="deletingId === row.id"
@click="removeItem(row)">删除</el-button></template></el-table-column>
</el-table>
<el-table v-else :key="resourceTableKey" :data="filteredDeptTree" row-key="id" :tree-props="{ children: 'children' }" :default-expand-all="deptExpanded" stripe>
<el-table-column label="部门名称" min-width="220"><template #default="{ row }"><span class="system-tree-label">{{ row.name }}</span></template></el-table-column>
<el-table-column label="父级部门" min-width="160"><template #default="{ row }">{{ parentDeptLabel(row.parentId) }}</template></el-table-column>
<el-table v-else :key="resourceTableKey" :data="filteredDeptTree" row-key="id"
:tree-props="{ children: 'children' }" :default-expand-all="deptExpanded" stripe>
<el-table-column label="部门名称" min-width="220"><template #default="{ row }"><span class="system-tree-label">{{
row.name }}</span></template></el-table-column>
<el-table-column label="父级部门" min-width="160"><template #default="{ row }">{{ parentDeptLabel(row.parentId)
}}</template></el-table-column>
<el-table-column prop="sortOrder" label="排序" width="100" />
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag :type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用" }}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt) }}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="220"><template #default="{ row }"><el-button v-permission="createPermission" link type="primary" @click="openCreate(row.id)">新增下级</el-button><el-button v-permission="updatePermission" link type="primary" @click="openEdit(row)">编辑</el-button><el-button v-permission="deletePermission" link type="danger" :loading="deletingId === row.id" @click="removeItem(row)">删除</el-button></template></el-table-column>
<el-table-column label="状态" width="90"><template #default="{ row }"><el-tag
:type="row.isActive ? 'success' : 'info'" effect="plain">{{ row.isActive ? "启用" : "停用"
}}</el-tag></template></el-table-column>
<el-table-column label="更新时间" min-width="165"><template #default="{ row }">{{ formatDate(row.updatedAt)
}}</template></el-table-column>
<el-table-column label="操作" fixed="right" width="220"><template #default="{ row }"><el-button
v-permission="createPermission" link type="primary"
@click="openCreate(row.id)">新增下级</el-button><el-button v-permission="updatePermission" link
type="primary" @click="openEdit(row)">编辑</el-button><el-button v-permission="deletePermission" link
type="danger" :loading="deletingId === row.id"
@click="removeItem(row)">删除</el-button></template></el-table-column>
</el-table>
</template>
</el-card>
<SystemResourceEditor v-model="editorOpen" :resource="resource" :mode="editorMode" :item="editorItem" :initial-parent-id="initialParentId" :roles="roles" :menus="menus" :depts="depts" @save="save" />
<SystemResourceEditor v-model="editorOpen" :resource="resource" :mode="editorMode" :item="editorItem"
:initial-parent-id="initialParentId" :roles="roles" :menus="menus" :depts="depts" @save="save" />
</div>
</template>