今天進入寫code環節!
先找一個不錯的頁面
http://yiming_chang.gitee.io/vue-pure-admin/#/system/role/index
發現這個看起來不錯~安排~~
我會下載兩份程式碼互相比對vue-pure-admin
功能多,不好入門pure-admin-thin
好入門,功能偏少
我想新增一個"角色管理頁面"流程如下
目錄截圖(片段)
雖然說是動態路由,其實應該說是新增左邊的菜單定義以較好懂
眼尖的觀眾應該猜到 itle: "menus.hssysManagement",
其實是作者多國語系的規範
這邊就略過不展開討論
把定義好的 systemRouter 放在 info
這樣一來系統一進去就可以拿到菜單了
因為我們前面定義的path='/system'
在mock命名也叫做system.ts
(實際上名稱取甚麼都ok不影響 MOCK API)
//\pure-admin-thin\mock\system.ts
import { MockMethod } from "vite-plugin-mock";
export default [
{
url: "/role",
method: "post",
response: () => {
return {
code: 0,
data: {
list: [
{
createTime: 1609837428000,
updateTime: 1645477701000,
creator: "admin",
updater: "",
deleted: false,
tenantId: 1,
id: 1,
name: "超级管理员",
code: "super_admin",
sort: 1,
status: 0,
type: 1,
remark: "超级管理员",
dataScope: 1,
dataScopeDeptIds: null
},
{
createTime: 1609837428000,
updateTime: 1645477700000,
creator: "admin",
updater: "",
deleted: false,
tenantId: 1,
id: 2,
name: "普通角色",
code: "common",
sort: 2,
status: 0,
type: 1,
remark: "普通角色",
dataScope: 2,
dataScopeDeptIds: null
},
{
createTime: 1609912175000,
updateTime: 1647698441000,
creator: "",
updater: "1",
deleted: false,
tenantId: 1,
id: 101,
name: "测试账号",
code: "test",
sort: 0,
status: 0,
type: 2,
remark: "132",
dataScope: 1,
dataScopeDeptIds: []
}
],
total: 3
}
};
}
}
] as MockMethod[];
同上 新增一個 system.ts
的檔案放在 /src/api
資料夾底下
//\pure-admin-thin\src\api\system.ts
import { http } from "../utils/http";
type Result = {
data?: {
list: Array<any>;
total: number;
};
code?: number;
msg?: string;
};
export const getRoleList = (data?: object) => {
return http.request<Result>("post", "/role", { data });
};
因為後面步驟會用到故先新增import { TableProBar } from "/@/components/ReTable";
值得一提的是 這邊我卡關一段時間,Icon有bug載入一直失敗
雖然不影響功能後來還是拔掉了 dropdown
相關插槽的程式碼
拔掉後就成功執行
//\pure-admin-thin\src\components\ReTable\src\bar.tsx
import { defineComponent, ref, PropType } from "vue";
import { IconifyIconOffline } from "../../ReIcon";
export const loadingSvg = `
<path class="path" d="
M 30 15
L 28 17
M 25.61 25.61
A 15 15, 0, 0, 1, 15 30
A 15 15, 0, 1, 1, 27.99 7.5
L 15 15
"
style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"
/>
`;
const props = {
// 標題
title: {
type: String,
default: "列表"
},
// data
dataList: {
type: Array,
default: () => {
return [];
}
},
// 摺疊
tableRef: {
type: Object as PropType<any>,
default() {
return {};
}
},
// loading 動畫
loading: {
type: Boolean,
default: false
}
};
export default defineComponent({
name: "TableProBar",
props,
emits: ["refresh"],
setup(props, { emit, slots, attrs }) {
const buttonRef = ref();
const checkList = ref([]);
const size = ref("default");
const isExpandAll = ref(true);
function onExpand() {
isExpandAll.value = !isExpandAll.value;
toggleRowExpansionAll(props.dataList, isExpandAll.value);
}
function toggleRowExpansionAll(data, isExpansion) {
data.forEach(item => {
props.tableRef.toggleRowExpansion(item, isExpansion);
if (item.children !== undefined && item.children !== null) {
toggleRowExpansionAll(item.children, isExpansion);
}
});
}
const reference = {
reference: () => (
<IconifyIconOffline
class="cursor-pointer"
icon="setting"
width="16"
color="text_color_regular"
onMouseover={e => (buttonRef.value = e.currentTarget)}
/>
)
};
return () => (
<>
<div
{...attrs}
class="w-[99/100] mt-6 p-2 bg-bg_color"
v-loading={props.loading}
element-loading-svg={loadingSvg}
element-loading-svg-view-box="-10, -10, 50, 50"
>
<div class="flex justify-between w-full h-[60px] p-4">
<p class="font-bold truncate">{props.title}</p>
<div class="flex items-center justify-around">
<div class="flex mr-4">{slots?.buttons()}</div>
{props.tableRef?.size ? (
<>
<el-tooltip
effect="dark"
content={isExpandAll.value ? "折叠" : "展开"}
placement="top"
>
<IconifyIconOffline
class="cursor-pointer"
icon={isExpandAll.value ? "unExpand" : "expand"}
width="16"
color="text_color_regular"
onClick={() => onExpand()}
/>
</el-tooltip>
<el-divider direction="vertical" />
</>
) : undefined}
<el-tooltip effect="dark" content="刷新" placement="top">
<IconifyIconOffline
class="cursor-pointer"
icon="refresh-right"
width="16"
color="text_color_regular"
onClick={() => emit("refresh")}
/>
</el-tooltip>
<el-divider direction="vertical" />
<el-popover v-slots={reference} width="200" trigger="click">
<el-checkbox-group v-model={checkList.value}>
<el-checkbox label="序号列" />
<el-checkbox label="勾选列" />
</el-checkbox-group>
</el-popover>
</div>
<el-tooltip
popper-options={{
modifiers: [
{
name: "computeStyles",
options: {
adaptive: false,
enabled: false
}
}
]
}}
placement="top"
virtual-ref={buttonRef.value}
virtual-triggering
trigger="hover"
content="列设置"
/>
</div>
{props.dataList.length > 0 ? (
slots.default({ size: size.value, checkList: checkList.value })
) : (
<el-empty description="暂无数据" />
)}
</div>
</>
);
}
});
// \pure-admin-thin\src\components\ReTable\index.ts
import tableProBar from "./src/bar";
import { withInstall } from "@pureadmin/utils";
/** table-crud */
export const TableProBar = withInstall(tableProBar);
// \pure-admin-thin\src\views\system\role\columns.tsx
import { ref } from "vue";
import dayjs from "dayjs";
import { ElMessageBox } from "element-plus";
import { Switch, message } from "@pureadmin/components";
export function useColumns() {
const switchLoadMap = ref({});
const columns = ref([
{
type: "selection",
width: 55,
hide: ({ checkList }) => !checkList.includes("勾选列")
},
{
label: "序号",
type: "index",
width: 70,
hide: ({ checkList }) => !checkList.includes("序号列")
},
{
label: "角色编号",
prop: "id"
},
{
label: "角色名称",
prop: "name"
},
{
label: "角色标识",
prop: "code"
},
{
label: "角色类型",
prop: "type",
cellRenderer: ({ row, props }) => (
<el-tag
size={props.size}
type={row.type === 1 ? "danger" : ""}
effect="plain"
>
{row.type === 1 ? "内置" : "自定义"}
</el-tag>
)
},
{
label: "显示顺序",
prop: "sort"
},
{
label: "状态",
prop: "status",
width: 130,
cellRenderer: scope => (
<Switch
size={scope.props.size === "small" ? "small" : "default"}
loading={switchLoadMap.value[scope.index]?.loading}
v-model:checked={scope.row.status}
checkedValue={1}
unCheckedValue={0}
checked-children="已开启"
un-checked-children="已关闭"
onChange={() => onChange(scope)}
/>
)
},
{
label: "创建时间",
width: 180,
prop: "createTime",
formatter: ({ createTime }) =>
dayjs(createTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "操作",
fixed: "right",
width: 180,
slot: "operation"
}
]);
function onChange({ row, index }) {
ElMessageBox.confirm(
`确认要<strong>${
row.status === 0 ? "停用" : "启用"
}</strong><strong style='color:var(--el-color-primary)'>${
row.name
}</strong>角色吗?`,
"系统提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
dangerouslyUseHTMLString: true,
draggable: true
}
)
.then(() => {
switchLoadMap.value[index] = Object.assign(
{},
switchLoadMap.value[index],
{
loading: true
}
);
setTimeout(() => {
switchLoadMap.value[index] = Object.assign(
{},
switchLoadMap.value[index],
{
loading: false
}
);
message.success("已成功修改角色状态");
}, 300);
})
.catch(() => {
row.status === 0 ? (row.status = 1) : (row.status = 0);
});
}
return {
columns
};
}
// \pure-admin-thin\src\views\system\role\index.vue
<script setup lang="ts">
import { useColumns } from "./columns";
import { getRoleList } from "/@/api/system";
import { reactive, ref, onMounted } from "vue";
import { TableProBar } from "/@/components/ReTable";
import { PaginationProps } from "@pureadmin/table";
import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
//一定要引入
import { PureTable } from "@pureadmin/table";
defineOptions({
name: "Role"
});
let dataList = ref([]);
let loading = ref(true);
const { columns } = useColumns();
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
function handleUpdate(row) {
console.log(row);
}
function handleDelete(row) {
console.log(row);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleSelectionChange(val) {
console.log("handleSelectionChange", val);
}
async function onSearch() {
loading.value = true;
let { data } = await getRoleList();
dataList.value = data.list;
pagination.total = data.total;
setTimeout(() => {
loading.value = false;
}, 500);
}
onMounted(() => {
onSearch();
});
</script>
<template>
<div class="main">
<TableProBar
title="角色列表"
:loading="loading"
:dataList="dataList"
@refresh="onSearch"
>
<template #buttons>
<el-button type="primary" :icon="useRenderIcon('add')">
新增角色
</el-button>
</template>
<template v-slot="{ size, checkList }">
<PureTable
border
align="center"
showOverflowTooltip
table-layout="auto"
:size="size"
:data="dataList"
:columns="columns"
:checkList="checkList"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
}"
@selection-change="handleSelectionChange"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
@click="handleUpdate(row)"
:icon="useRenderIcon('edits')"
>
修改
</el-button>
<el-popconfirm title="是否确认删除?">
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon('delete')"
@click="handleDelete(row)"
>
删除
</el-button>
</template>
</el-popconfirm>
<el-dropdown>
<el-button
class="ml-3"
link
type="primary"
:size="size"
@click="handleUpdate(row)"
:icon="useRenderIcon('more')"
/>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-button
class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link
type="primary"
:size="size"
:icon="useRenderIcon('menu')"
>
菜单权限
</el-button>
</el-dropdown-item>
<el-dropdown-item>
<el-button
class="reset-margin !h-[20px] !text-gray-500 dark:!text-white dark:hover:!text-primary"
link
type="primary"
:size="size"
:icon="useRenderIcon('database')"
>
数据权限
</el-button>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</PureTable>
</template>
</TableProBar>
</div>
</template>
<style scoped lang="scss">
// :deep(.el-dropdown-menu__item i) {
// margin: 0;
// }
</style>
這篇文章把程式碼都貼上來的用意是希望能夠"完整地"
將作者用心製作的 vue-pure-admin
部分功能頁面整合至 pure-admin-thin
因為在網路上要做這麼多截圖和複製程式碼不是簡單幾分鐘就能完成的~
希望這個流程對於有需要的讀者有所幫助囉!
今天發現在使用作者封裝的 PureTable
components 後開啟 Vue.js devtools
Win10 操作網頁變成非常卡頓!(還以為在看簡報)
關掉Vue.js devtools
後就正常了