feat: 🚀 修改控制台输出

This commit is contained in:
Bunny 2024-05-12 02:05:33 +08:00
parent 8504a8bc6c
commit d6a36abc47
34 changed files with 1513 additions and 1395 deletions

View File

@ -1,8 +0,0 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"

View File

@ -1,9 +0,0 @@
#!/bin/sh
command_exists () {
command -v "$1" >/dev/null 2>&1
}
# Workaround for Windows 10, Git Bash and Pnpm
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi

View File

@ -1,10 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
. "$(dirname -- "$0")/_/husky.sh"
[ -n "$CI" ] && exit 0
PATH="/usr/local/bin:$PATH"
# Perform lint check on files in the staging area through .lintstagedrc configuration
pnpm exec lint-staged
pnpm exec lint-staged

View File

@ -2,7 +2,7 @@
/** @type {import("prettier").Config} */
export default {
printWidth: 230,
printWidth: 200,
bracketSpacing: true,
singleQuote: false,
arrowParens: "avoid",

View File

@ -4,13 +4,13 @@ import dayjs, { type Dayjs } from "dayjs";
import duration from "dayjs/plugin/duration";
import gradientString from "gradient-string";
import boxen, { type Options as BoxenOptions } from "boxen";
dayjs.extend(duration);
const welcomeMessage = gradientString("cyan", "magenta").multiline(
`您好! 欢迎使用 pure-admin 开源项目
https://pure-admin.github.io/pure-admin-doc
https://pure-admin-utils.netlify.app`
`您好! 欢迎使用 bunny-admin 后台管理
访
http://localhost:8848/`
);
const boxenOptions: BoxenOptions = {
@ -42,16 +42,7 @@ export function viteBuildInfo(): Plugin {
getPackageSize({
folder: outDir,
callback: (size: string) => {
console.log(
boxen(
gradientString("cyan", "magenta").multiline(
`🎉 恭喜打包完成(总用时${dayjs
.duration(endTime.diff(startTime))
.format("mm分ss秒")}${size}`
),
boxenOptions
)
);
console.log(boxen(gradientString("cyan", "magenta").multiline(`🎉 恭喜打包完成(总用时${dayjs.duration(endTime.diff(startTime)).format("mm分ss秒")},打包后的大小为${size}`), boxenOptions));
}
});
}

View File

@ -1,35 +1,73 @@
// @ts-check
// @see: https://cz-git.qbenben.com/zh/guide
/** @type {import('cz-git').UserConfig} */
/** @type {import("@commitlint/types").UserConfig} */
export default {
ignores: [commit => commit.includes("init")],
extends: ["@commitlint/config-conventional"],
rules: {
// @see: https://commitlint.js.org/#/reference-rules
"body-leading-blank": [2, "always"],
"footer-leading-blank": [1, "always"],
"header-max-length": [2, "always", 108],
"subject-empty": [2, "never"],
"type-empty": [2, "never"],
"type-enum": [
2,
"always",
[
"feat",
"fix",
"perf",
"style",
"docs",
"test",
"refactor",
"build",
"ci",
"chore",
"revert",
"wip",
"workflow",
"types",
"release"
]
]
"subject-case": [0],
"type-enum": [2, "always", ["feat", "fix", "media", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert", "wip", "workflow", "types", "release"]]
},
prompt: {
messages: {
type: "选择你要提交的类型 :",
scope: "选择一个提交范围(可选):",
customScope: "请输入自定义的提交范围 :",
subject: "填写简短精炼的变更描述 :\n",
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
footerPrefixsSelect: "选择关联issue前缀可选:",
customFooterPrefixs: "输入自定义issue前缀 :",
footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
confirmCommit: "是否提交或修改commit ?"
},
types: [
{ value: "feat", name: "特性: 🚀 新增功能", emoji: "🚀" },
{ value: "media", name: "媒体: 🎁 新增媒体资源", emoji: "🎁" },
{ value: "fix", name: "修复: 🧩 修复缺陷", emoji: "🧩" },
{ value: "docs", name: "文档: 📚 文档变更", emoji: "📚" },
{ value: "style", name: "格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" },
{ value: "refactor", name: "重构: ♻️ 代码重构(不包括 bug 修复、功能新增)", emoji: "♻️" },
{ value: "perf", name: "性能: ⚡️ 性能优化", emoji: "⚡️" },
{ value: "test", name: "测试: ✅ 添加疏漏测试或已有测试改动", emoji: "✅" },
{ value: "build", name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)", emoji: "📦️" },
{ value: "ci", name: "集成: 🎡 修改 CI 配置、脚本", emoji: "🎡" },
{ value: "revert", name: "回退: ⏪️ 回滚 commit", emoji: "⏪️" },
{ value: "chore", name: "其他: 🔨 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)", emoji: "🔨" }
],
useEmoji: true,
themeColorCode: "",
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: "bottom",
customScopesAlias: "custom",
emptyScopesAlias: "empty",
upperCaseSubject: false,
allowBreakingChanges: ["feat", "fix"],
breaklineNumber: 100,
breaklineChar: "|",
skipQuestions: [],
issuePrefixs: [{ value: "closed", name: "closed: ISSUES has been processed" }],
customIssuePrefixsAlign: "top",
emptyIssuePrefixsAlias: "skip",
customIssuePrefixsAlias: "custom",
allowCustomIssuePrefixs: true,
allowEmptyIssuePrefixs: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: "",
defaultIssues: "",
defaultScope: "",
defaultSubject: ""
}
};

View File

@ -1,87 +1,87 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<head>
<meta charset="UTF-8"/>
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"/>
<meta content="webkit" name="renderer"/>
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
name="viewport"
/>
<title>vue-pure-admin</title>
<link rel="icon" href="/favicon.ico" />
<title>bunny-admin</title>
<link href="/favicon.ico" rel="icon"/>
<script>
window.process = {};
window.process = {};
</script>
</head>
</head>
<body>
<div id="app">
<style>
<body>
<div id="app">
<style>
html,
body,
#app {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
overflow: hidden;
align-items: center;
display: flex;
height: 100%;
justify-content: center;
overflow: hidden;
position: relative;
width: 100%;
}
.loader,
.loader::before,
.loader::after {
width: 2.5em;
height: 2.5em;
border-radius: 50%;
animation: load-animation 1.8s infinite ease-in-out;
animation-fill-mode: both;
animation: load-animation 1.8s infinite ease-in-out;
animation-fill-mode: both;
border-radius: 50%;
height: 2.5em;
width: 2.5em;
}
.loader {
position: relative;
top: 0;
margin: 80px auto;
font-size: 10px;
color: #406eeb;
text-indent: -9999em;
transform: translateZ(0);
transform: translate(-50%, 0);
animation-delay: -0.16s;
animation-delay: -0.16s;
color: #406eeb;
font-size: 10px;
margin: 80px auto;
position: relative;
text-indent: -9999em;
top: 0;
transform: translate(-50%, 0);
transform: translateZ(0);
}
.loader::before,
.loader::after {
position: absolute;
top: 0;
content: "";
content: "";
position: absolute;
top: 0;
}
.loader::before {
left: -3.5em;
animation-delay: -0.32s;
animation-delay: -0.32s;
left: -3.5em;
}
.loader::after {
left: 3.5em;
left: 3.5em;
}
@keyframes load-animation {
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
0%,
80%,
100% {
box-shadow: 0 2.5em 0 -1.3em;
}
40% {
box-shadow: 0 2.5em 0 0;
}
40% {
box-shadow: 0 2.5em 0 0;
}
}
</style>
<div class="loader"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</style>
<div class="loader"></div>
</div>
<script src="/src/main.ts" type="module"></script>
</body>
</html>

8
lint-staged.config.js Normal file
View File

@ -0,0 +1,8 @@
export default {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": ["prettier --write--parser json"],
"package.json": ["prettier --write"],
"*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
"*.{scss,less,styl,html}": ["stylelint --fix", "prettier --write"],
"*.md": ["prettier --write"]
};

View File

@ -180,6 +180,10 @@ menus:
pureMindMap: Mind Map
pureMenuOverflow: Menu Overflow Show Tooltip Text
pureChildMenuOverflow: Child Menu Overflow Show Tooltip Text
bills: Ledger management
billRecord: Billing record
billHistory: Billing History
billCount: Billing Count
status:
pureLoad: Loading...
pureMessage: Message

View File

@ -180,6 +180,10 @@ menus:
pureMindMap: 思维导图
pureMenuOverflow: 目录超出显示 Tooltip 文字提示
pureChildMenuOverflow: 菜单超出显示 Tooltip 文字提示
bills: 台账管理
billRecord: 账单记录
billHistory: 历史账单
billCount: 账单统计
status:
pureLoad: 加载中...
pureMessage: 消息

View File

@ -1,6 +1,6 @@
// 模拟后端动态生成路由
import { defineFakeRoute } from "vite-plugin-fake-server/client";
import { frame, monitor, permission, system, tabs } from "@/router/enums";
import { bills, frame, monitor, permission, system, tabs } from "@/router/enums";
/**
* roles "admin""common"
@ -303,20 +303,20 @@ const about = {
path: "/about",
meta: {
icon: "ri:bookmark-2-line",
title: "menus.pureAbout",
rank: tabs
title: "menus.pureAbout"
},
children: [
{
path: "/about/index",
name: "about",
name: "About",
meta: {
title: "menus.pureAbout",
roles: ["admin", "common"]
icon: "ri:bookmark-2-line",
title: "menus.pureAbout"
}
}
]
};
export default defineFakeRoute([
{
url: "/get-async-routes",
@ -324,7 +324,7 @@ export default defineFakeRoute([
response: () => {
return {
success: true,
data: [systemManagementRouter, systemMonitorRouter, permissionRouter, frameRouter, about /*tabsRouter*/]
data: [systemManagementRouter, systemMonitorRouter, permissionRouter, frameRouter, about, /*tabsRouter*/]
};
}
}

View File

@ -45,7 +45,8 @@
"lint:stylelint": "stylelint --cache --fix \"**/*.{html,vue,css,scss}\" --cache-location node_modules/.cache/stylelint/",
"lint": "pnpm lint:eslint && pnpm lint:prettier && pnpm lint:stylelint",
"prepare": "husky",
"preinstall": "npx only-allow pnpm"
"preinstall": "npx only-allow pnpm",
"commit": "git pull && git add -A && git-cz && git push"
},
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
@ -135,7 +136,10 @@
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.19",
"boxen": "^7.1.1",
"commitizen": "^4.2.4",
"commitlint": "^17.0.1",
"cssnano": "^7.0.1",
"cz-git": "^1.3.2",
"dagre": "^0.8.5",
"eslint": "^9.2.0",
"eslint-config-prettier": "^9.1.0",
@ -143,7 +147,7 @@
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-vue": "^9.25.0",
"gradient-string": "^2.0.2",
"husky": "^9.0.11",
"husky": "^8.0.1",
"lint-staged": "^15.2.2",
"postcss": "^8.4.38",
"postcss-html": "^1.7.0",
@ -188,5 +192,10 @@
"eslint": "9"
}
}
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -110,7 +110,7 @@ export default defineComponent({
isIndeterminate.value = false;
dynamicColumns.value = cloneDeep(props?.columns);
checkColumnList = [];
checkColumnList = await getKeyList(cloneDeep(props?.columns), "label");
checkColumnList = getKeyList(cloneDeep(props?.columns), "label");
checkedColumns.value = getKeyList(cloneDeep(filterColumns), "label");
}
@ -157,7 +157,7 @@ export default defineComponent({
dynamicColumns.value.splice(newIndex, 0, currentRow);
}
});
});
}).then();
};
const isFixedColumn = (label: string) => {
@ -221,7 +221,10 @@ export default defineComponent({
{checkColumnList.map((item, index) => {
return (
<div class="flex items-center">
<DragIcon class={["drag-btn w-[16px] mr-2", isFixedColumn(item) ? "!cursor-no-drop" : "!cursor-grab"]} onMouseenter={(event: { preventDefault: () => void }) => rowDrop(event)} />
<DragIcon
class={["drag-btn w-[16px] mr-2", isFixedColumn(item) ? "!cursor-no-drop" : "!cursor-grab"]}
onMouseenter={(event: { preventDefault: () => void }) => rowDrop(event)}
/>
<el-checkbox key={index} label={item} value={item} onChange={value => handleCheckColumnListChange(value, item)}>
<span title={transformI18n(item)} class="inline-block w-[120px] truncate hover:text-text_color_primary">
{transformI18n(item)}

View File

@ -1,7 +1,7 @@
import dayjs from "dayjs";
import { message } from "@/utils/message";
import { getOnlineLogsList } from "@/api/system";
import { reactive, ref, onMounted, toRaw } from "vue";
import { onMounted, reactive, ref, toRaw } from "vue";
import type { PaginationProps } from "@pureadmin/table";
export function useRole() {
@ -51,8 +51,7 @@ export function useRole() {
label: "登录时间",
prop: "loginTime",
minWidth: 180,
formatter: ({ loginTime }) =>
dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
formatter: ({ loginTime }) => dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "操作",

View File

@ -18,7 +18,7 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以
tabs = 15,
about = 16,
editor = 17,
flowchart = 18,
bills = 18,
formdesign = 19,
board = 20,
ppt = 21,
@ -26,4 +26,4 @@ const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以
guide = 23,
menuoverflow = 24;
export { home, vueflow, ganttastic, components, able, table, form, list, result, error, frame, nested, permission, system, monitor, tabs, about, editor, flowchart, formdesign, board, ppt, mind, guide, menuoverflow };
export { home, vueflow, ganttastic, components, able, table, form, list, result, error, frame, nested, permission, system, monitor, tabs, about, editor, bills, formdesign, board, ppt, mind, guide, menuoverflow };

View File

@ -1,4 +1,5 @@
import { $t } from "@/plugins/i18n";
const Layout = () => import("@/layout/index.vue");
export default [
@ -32,7 +33,7 @@ export default [
{
path: "/empty",
name: "Empty",
component: () => import("@/views/empty/index.vue"),
component: () => import("@/components/Empty/index.vue"),
meta: {
title: $t("menus.pureEmpty"),
showLink: false,

View File

@ -155,19 +155,19 @@ watch(loginDay, value => {
]"
prop="username"
>
<el-input v-model="ruleForm.username" :placeholder="t('login.pureUsername')" :prefix-icon="useRenderIcon(User)" clearable />
<el-input v-model="ruleForm.username" :placeholder="t('login.pureUsername')" :prefix-icon="useRenderIcon(User)" clearable @keydown.enter="onLogin(ruleFormRef)" />
</el-form-item>
</Motion>
<Motion :delay="150">
<el-form-item prop="password">
<el-input v-model="ruleForm.password" :placeholder="t('login.purePassword')" :prefix-icon="useRenderIcon(Lock)" clearable show-password />
<el-input v-model="ruleForm.password" :placeholder="t('login.purePassword')" :prefix-icon="useRenderIcon(Lock)" clearable show-password @keydown.enter="onLogin(ruleFormRef)" />
</el-form-item>
</Motion>
<Motion :delay="200">
<el-form-item prop="verifyCode">
<el-input v-model="ruleForm.verifyCode" :placeholder="t('login.pureVerifyCode')" :prefix-icon="useRenderIcon('ri:shield-keyhole-line')" clearable>
<el-input v-model="ruleForm.verifyCode" :placeholder="t('login.pureVerifyCode')" :prefix-icon="useRenderIcon('ri:shield-keyhole-line')" clearable @keydown.enter="onLogin(ruleFormRef)">
<template v-slot:append>
<ReImageVerify v-model:code="imgCode" />
</template>

View File

@ -8,11 +8,10 @@ import { useUserStoreHook } from "@/store/modules/user";
export const REGEXP_SIX = /^\d{6}$/;
/** 密码正则密码格式应为8-18位数字、字母、符号的任意两种组合 */
export const REGEXP_PWD =
/^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
export const REGEXP_PWD = /^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!([^(0-9a-zA-Z)]|[()])+$)(?!^.*[\u4E00-\u9FA5].*$)([^(0-9a-zA-Z)]|[()]|[a-z]|[A-Z]|[0-9]){8,18}$/;
/** 登录校验 */
const loginRules = reactive<FormRules>({
export const loginRules = reactive<FormRules>({
password: [
{
validator: (rule, value, callback) => {
@ -33,9 +32,7 @@ const loginRules = reactive<FormRules>({
if (value === "") {
callback(new Error(transformI18n($t("login.pureVerifyCodeReg"))));
} else if (useUserStoreHook().verifyCode !== value) {
callback(
new Error(transformI18n($t("login.pureVerifyCodeCorrectReg")))
);
callback(new Error(transformI18n($t("login.pureVerifyCodeCorrectReg"))));
} else {
callback();
}
@ -46,7 +43,7 @@ const loginRules = reactive<FormRules>({
});
/** 手机登录校验 */
const phoneRules = reactive<FormRules>({
export const phoneRules = reactive<FormRules>({
phone: [
{
validator: (rule, value, callback) => {
@ -78,7 +75,7 @@ const phoneRules = reactive<FormRules>({
});
/** 忘记密码校验 */
const updateRules = reactive<FormRules>({
export const updateRules = reactive<FormRules>({
phone: [
{
validator: (rule, value, callback) => {
@ -122,5 +119,3 @@ const updateRules = reactive<FormRules>({
}
]
});
export { loginRules, phoneRules, updateRules };

View File

@ -1,168 +0,0 @@
import dayjs from "dayjs";
import { message } from "@/utils/message";
import { getKeyList } from "@pureadmin/utils";
import { getLoginLogsList } from "@/api/system";
import { usePublicHooks } from "@/hooks/system/usePublicHooks";
import type { PaginationProps } from "@pureadmin/table";
import { onMounted, reactive, ref, type Ref, toRaw } from "vue";
export function useRole(tableRef: Ref) {
const form = reactive({
username: "",
status: "",
loginTime: ""
});
const dataList = ref([]);
const loading = ref(true);
const selectedNum = ref(0);
const { tagStyle } = usePublicHooks();
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
const columns: TableColumnList = [
{
label: "勾选列", // 如果需要表格多选此处label必须设置
type: "selection",
fixed: "left",
reserveSelection: true // 数据刷新后保留选项
},
{
label: "序号",
prop: "id",
minWidth: 90
},
{
label: "用户名",
prop: "username",
minWidth: 100
},
{
label: "登录 IP",
prop: "ip",
minWidth: 140
},
{
label: "登录地点",
prop: "address",
minWidth: 140
},
{
label: "操作系统",
prop: "system",
minWidth: 100
},
{
label: "浏览器类型",
prop: "browser",
minWidth: 100
},
{
label: "登录状态",
prop: "status",
minWidth: 100,
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} style={tagStyle.value(row.status)}>
{row.status === 1 ? "成功" : "失败"}
</el-tag>
)
},
{
label: "登录行为",
prop: "behavior",
minWidth: 100
},
{
label: "登录时间",
prop: "loginTime",
minWidth: 180,
formatter: ({ loginTime }) => dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss")
}
];
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
/** 当CheckBox选择项发生变化时会触发该事件 */
function handleSelectionChange(val) {
selectedNum.value = val.length;
// 重置表格高度
tableRef.value.setAdaptive();
}
/** 取消选择 */
function onSelectionCancel() {
selectedNum.value = 0;
// 用于多选表格,清空用户的选择
tableRef.value.getTableRef().clearSelection();
}
/** 批量删除 */
function onbatchDel() {
// 返回当前选中的行
const curSelected = tableRef.value.getTableRef().getSelectionRows();
// 接下来根据实际业务通过选中行的某项数据比如下面的id调用接口进行批量删除
message(`已删除序号为 ${getKeyList(curSelected, "id")} 的数据`, {
type: "success"
});
tableRef.value.getTableRef().clearSelection();
onSearch();
}
/** 清空日志 */
function clearAll() {
// 根据实际业务,调用接口删除所有日志数据
message("已删除所有日志数据", {
type: "success"
});
onSearch();
}
async function onSearch() {
loading.value = true;
const { data } = await getLoginLogsList(toRaw(form));
dataList.value = data.list;
pagination.total = data.total;
pagination.pageSize = data.pageSize;
pagination.currentPage = data.currentPage;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
return {
form,
loading,
columns,
dataList,
pagination,
selectedNum,
onSearch,
clearAll,
resetForm,
onbatchDel,
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
};
}

View File

@ -1,10 +1,10 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useRole } from "./hook";
import { useRole } from "@/hooks/monitor/useRole";
import { getPickerShortcuts } from "../../utils";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import PureTable from "@pureadmin/table";
import Delete from "@iconify-icons/ep/delete";
import Refresh from "@iconify-icons/ep/refresh";
@ -15,130 +15,68 @@ defineOptions({
const formRef = ref();
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
pagination,
selectedNum,
onSearch,
clearAll,
resetForm,
onbatchDel,
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
} = useRole(tableRef);
const { form, loading, columns, dataList, pagination, selectedNum, onSearch, clearAll, resetForm, onbatchDel, handleSizeChange, onSelectionCancel, handleCurrentChange, handleSelectionChange } =
useRole(tableRef);
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="!w-[150px]"
/>
<el-input v-model="form.username" class="!w-[150px]" clearable placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="登录状态" prop="status">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="!w-[150px]"
>
<el-select v-model="form.status" class="!w-[150px]" clearable placeholder="请选择">
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="登录时间" prop="loginTime">
<el-date-picker
v-model="form.loginTime"
:shortcuts="getPickerShortcuts()"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
/>
<el-date-picker v-model="form.loginTime" :shortcuts="getPickerShortcuts()" end-placeholder="结束日期时间" range-separator="" start-placeholder="开始日期时间" type="datetimerange" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置</el-button>
</el-form-item>
</el-form>
<PureTableBar
title="登录日志(仅演示,操作后不生效)"
:columns="columns"
@refresh="onSearch"
>
<PureTableBar :columns="columns" title="登录日志(仅演示,操作后不生效)" @refresh="onSearch">
<template #buttons>
<el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
<template #reference>
<el-button type="danger" :icon="useRenderIcon(Delete)">
清空日志
</el-button>
<el-button :icon="useRenderIcon(Delete)" type="danger"> 清空日志</el-button>
</template>
</el-popconfirm>
</template>
<template v-slot="{ size, dynamicColumns }">
<div
v-if="selectedNum > 0"
v-motion-fade
class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center"
>
<div v-if="selectedNum > 0" v-motion-fade class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center">
<div class="flex-auto">
<span
style="font-size: var(--el-font-size-base)"
class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]"
>
已选 {{ selectedNum }}
</span>
<el-button type="primary" text @click="onSelectionCancel">
取消选择
</el-button>
<span class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]" style="font-size: var(--el-font-size-base)"> 已选 {{ selectedNum }} </span>
<el-button text type="primary" @click="onSelectionCancel"> 取消选择</el-button>
</div>
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
<template #reference>
<el-button type="danger" text class="mr-1"> 批量删除 </el-button>
<el-button class="mr-1" text type="danger"> 批量删除</el-button>
</template>
</el-popconfirm>
</div>
<pure-table
ref="tableRef"
row-key="id"
align-whole="center"
table-layout="auto"
:loading="loading"
:size="size"
adaptive
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:columns="dynamicColumns"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:pagination="pagination"
:paginationSmall="size === 'small'"
:size="size"
adaptive
align-whole="center"
row-key="id"
table-layout="auto"
@selection-change="handleSelectionChange"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
@ -148,7 +86,7 @@ const {
</div>
</template>
<style scoped lang="scss">
<style lang="scss" scoped>
:deep(.el-dropdown-menu__item i) {
margin: 0;
}

View File

@ -1,174 +0,0 @@
import dayjs from "dayjs";
import { message } from "@/utils/message";
import { getKeyList } from "@pureadmin/utils";
import { getOperationLogsList } from "@/api/system";
import { usePublicHooks } from "@/views/system/hooks";
import type { PaginationProps } from "@pureadmin/table";
import { type Ref, reactive, ref, onMounted, toRaw } from "vue";
export function useRole(tableRef: Ref) {
const form = reactive({
module: "",
status: "",
operatingTime: ""
});
const dataList = ref([]);
const loading = ref(true);
const selectedNum = ref(0);
const { tagStyle } = usePublicHooks();
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 10,
currentPage: 1,
background: true
});
const columns: TableColumnList = [
{
label: "勾选列", // 如果需要表格多选此处label必须设置
type: "selection",
fixed: "left",
reserveSelection: true // 数据刷新后保留选项
},
{
label: "序号",
prop: "id",
minWidth: 90
},
{
label: "操作人员",
prop: "username",
minWidth: 100
},
{
label: "所属模块",
prop: "module",
minWidth: 140
},
{
label: "操作概要",
prop: "summary",
minWidth: 140
},
{
label: "操作 IP",
prop: "ip",
minWidth: 100
},
{
label: "操作地点",
prop: "address",
minWidth: 140
},
{
label: "操作系统",
prop: "system",
minWidth: 100
},
{
label: "浏览器类型",
prop: "browser",
minWidth: 100
},
{
label: "操作状态",
prop: "status",
minWidth: 100,
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} style={tagStyle.value(row.status)}>
{row.status === 1 ? "成功" : "失败"}
</el-tag>
)
},
{
label: "操作时间",
prop: "operatingTime",
minWidth: 180,
formatter: ({ operatingTime }) =>
dayjs(operatingTime).format("YYYY-MM-DD HH:mm:ss")
}
];
function handleSizeChange(val: number) {
console.log(`${val} items per page`);
}
function handleCurrentChange(val: number) {
console.log(`current page: ${val}`);
}
/** 当CheckBox选择项发生变化时会触发该事件 */
function handleSelectionChange(val) {
selectedNum.value = val.length;
// 重置表格高度
tableRef.value.setAdaptive();
}
/** 取消选择 */
function onSelectionCancel() {
selectedNum.value = 0;
// 用于多选表格,清空用户的选择
tableRef.value.getTableRef().clearSelection();
}
/** 批量删除 */
function onbatchDel() {
// 返回当前选中的行
const curSelected = tableRef.value.getTableRef().getSelectionRows();
// 接下来根据实际业务通过选中行的某项数据比如下面的id调用接口进行批量删除
message(`已删除序号为 ${getKeyList(curSelected, "id")} 的数据`, {
type: "success"
});
tableRef.value.getTableRef().clearSelection();
onSearch();
}
/** 清空日志 */
function clearAll() {
// 根据实际业务,调用接口删除所有日志数据
message("已删除所有日志数据", {
type: "success"
});
onSearch();
}
async function onSearch() {
loading.value = true;
const { data } = await getOperationLogsList(toRaw(form));
dataList.value = data.list;
pagination.total = data.total;
pagination.pageSize = data.pageSize;
pagination.currentPage = data.currentPage;
setTimeout(() => {
loading.value = false;
}, 500);
}
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
onMounted(() => {
onSearch();
});
return {
form,
loading,
columns,
dataList,
pagination,
selectedNum,
onSearch,
clearAll,
resetForm,
onbatchDel,
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
};
}

View File

@ -1,10 +1,10 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useRole } from "./hook";
import { useRole } from "@/hooks/monitor/useRole";
import { getPickerShortcuts } from "../../utils";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import PureTable from "@pureadmin/table";
import Delete from "@iconify-icons/ep/delete";
import Refresh from "@iconify-icons/ep/refresh";
@ -15,130 +15,68 @@ defineOptions({
const formRef = ref();
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
pagination,
selectedNum,
onSearch,
clearAll,
resetForm,
onbatchDel,
handleSizeChange,
onSelectionCancel,
handleCurrentChange,
handleSelectionChange
} = useRole(tableRef);
const { form, loading, columns, dataList, pagination, selectedNum, onSearch, clearAll, resetForm, onbatchDel, handleSizeChange, onSelectionCancel, handleCurrentChange, handleSelectionChange } =
useRole(tableRef);
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="所属模块" prop="module">
<el-input
v-model="form.module"
placeholder="请输入所属模块"
clearable
class="!w-[170px]"
/>
<el-input v-model="form.module" class="!w-[170px]" clearable placeholder="请输入所属模块" />
</el-form-item>
<el-form-item label="操作状态" prop="status">
<el-select
v-model="form.status"
placeholder="请选择"
clearable
class="!w-[150px]"
>
<el-select v-model="form.status" class="!w-[150px]" clearable placeholder="请选择">
<el-option label="成功" value="1" />
<el-option label="失败" value="0" />
</el-select>
</el-form-item>
<el-form-item label="操作时间" prop="operatingTime">
<el-date-picker
v-model="form.operatingTime"
:shortcuts="getPickerShortcuts()"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
/>
<el-date-picker v-model="form.operatingTime" :shortcuts="getPickerShortcuts()" end-placeholder="结束日期时间" range-separator="" start-placeholder="开始日期时间" type="datetimerange" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置</el-button>
</el-form-item>
</el-form>
<PureTableBar
title="操作日志(仅演示,操作后不生效)"
:columns="columns"
@refresh="onSearch"
>
<PureTableBar :columns="columns" title="操作日志(仅演示,操作后不生效)" @refresh="onSearch">
<template #buttons>
<el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
<template #reference>
<el-button type="danger" :icon="useRenderIcon(Delete)">
清空日志
</el-button>
<el-button :icon="useRenderIcon(Delete)" type="danger"> 清空日志</el-button>
</template>
</el-popconfirm>
</template>
<template v-slot="{ size, dynamicColumns }">
<div
v-if="selectedNum > 0"
v-motion-fade
class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center"
>
<div v-if="selectedNum > 0" v-motion-fade class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center">
<div class="flex-auto">
<span
style="font-size: var(--el-font-size-base)"
class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]"
>
已选 {{ selectedNum }}
</span>
<el-button type="primary" text @click="onSelectionCancel">
取消选择
</el-button>
<span class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]" style="font-size: var(--el-font-size-base)"> 已选 {{ selectedNum }} </span>
<el-button text type="primary" @click="onSelectionCancel"> 取消选择</el-button>
</div>
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
<template #reference>
<el-button type="danger" text class="mr-1"> 批量删除 </el-button>
<el-button class="mr-1" text type="danger"> 批量删除</el-button>
</template>
</el-popconfirm>
</div>
<pure-table
ref="tableRef"
row-key="id"
align-whole="center"
table-layout="auto"
:loading="loading"
:size="size"
adaptive
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:columns="dynamicColumns"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:size="size"
adaptive
align-whole="center"
row-key="id"
table-layout="auto"
@selection-change="handleSelectionChange"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
@ -148,7 +86,7 @@ const {
</div>
</template>
<style scoped lang="scss">
<style lang="scss" scoped>
:deep(.el-dropdown-menu__item i) {
margin: 0;
}

View File

@ -1,4 +1,4 @@
<script setup lang="tsx">
<script lang="tsx" setup>
import { ref } from "vue";
import "vue-json-pretty/lib/styles.css";
import VueJsonPretty from "vue-json-pretty";
@ -82,15 +82,10 @@ const dataList = ref([
<template>
<div>
<el-scrollbar>
<PureDescriptions border :data="data" :columns="columns" :column="5" />
<PureDescriptions :column="5" :columns="columns" :data="data" border />
</el-scrollbar>
<el-tabs :modelValue="'responseBody'" type="border-card" class="mt-4">
<el-tab-pane
v-for="(item, index) in dataList"
:key="index"
:name="item.name"
:label="item.title"
>
<el-tabs :modelValue="'responseBody'" class="mt-4" type="border-card">
<el-tab-pane v-for="(item, index) in dataList" :key="index" :label="item.title" :name="item.name">
<el-scrollbar max-height="calc(100vh - 240px)">
<vue-json-pretty v-model:data="item.data" />
</el-scrollbar>

View File

@ -3,9 +3,9 @@ import Detail from "./detail.vue";
import { message } from "@/utils/message";
import { addDialog } from "@/components/ReDialog";
import type { PaginationProps } from "@pureadmin/table";
import { type Ref, reactive, ref, onMounted, toRaw } from "vue";
import { onMounted, reactive, ref, type Ref, toRaw } from "vue";
import { getKeyList, useCopyToClipboard } from "@pureadmin/utils";
import { getSystemLogsList, getSystemLogsDetail } from "@/api/system";
import { getSystemLogsDetail, getSystemLogsList } from "@/api/system";
import Info from "@iconify-icons/ri/question-line";
export function useRole(tableRef: Ref) {
@ -25,20 +25,20 @@ export function useRole(tableRef: Ref) {
background: true
});
// const getLevelType = (type, text = false) => {
// switch (type) {
// case 0:
// return text ? "debug" : "primary";
// case 1:
// return text ? "info" : "success";
// case 2:
// return text ? "warn" : "info";
// case 3:
// return text ? "error" : "warning";
// case 4:
// return text ? "fatal" : "danger";
// }
// };
const getLevelType = (type, text = false) => {
switch (type) {
case 0:
return text ? "debug" : "primary";
case 1:
return text ? "info" : "success";
case 2:
return text ? "warn" : "info";
case 3:
return text ? "error" : "warning";
case 4:
return text ? "fatal" : "danger";
}
};
const columns: TableColumnList = [
{
@ -98,26 +98,22 @@ export function useRole(tableRef: Ref) {
prop: "browser",
minWidth: 100
},
// {
// label: "级别",
// prop: "level",
// minWidth: 90,
// cellRenderer: ({ row, props }) => (
// <el-tag size={props.size} type={getLevelType(row.level)} effect="plain">
// {getLevelType(row.level, true)}
// </el-tag>
// )
// },
{
label: "级别",
prop: "level",
minWidth: 90,
cellRenderer: ({ row, props }) => (
<el-tag size={props.size} type={getLevelType(row.level)} effect="plain">
{getLevelType(row.level, true)}
</el-tag>
)
},
{
label: "请求耗时",
prop: "takesTime",
minWidth: 100,
cellRenderer: ({ row, props }) => (
<el-tag
size={props.size}
type={row.takesTime < 1000 ? "success" : "warning"}
effect="plain"
>
<el-tag size={props.size} type={row.takesTime < 1000 ? "success" : "warning"} effect="plain">
{row.takesTime} ms
</el-tag>
)
@ -126,8 +122,7 @@ export function useRole(tableRef: Ref) {
label: "请求时间",
prop: "requestTime",
minWidth: 180,
formatter: ({ requestTime }) =>
dayjs(requestTime).format("YYYY-MM-DD HH:mm:ss")
formatter: ({ requestTime }) => dayjs(requestTime).format("YYYY-MM-DD HH:mm:ss")
},
{
label: "操作",
@ -162,9 +157,7 @@ export function useRole(tableRef: Ref) {
function handleCellDblclick({ url }, { property }) {
if (property !== "url") return;
update(url);
copied.value
? message(`${url} 已拷贝`, { type: "success" })
: message("拷贝失败", { type: "warning" });
copied.value ? message(`${url} 已拷贝`, { type: "success" }) : message("拷贝失败", { type: "warning" });
}
/** 批量删除 */

View File

@ -1,10 +1,10 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useRole } from "./hook";
import { getPickerShortcuts } from "../../utils";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import PureTable from "@pureadmin/table";
import View from "@iconify-icons/ep/view";
import Delete from "@iconify-icons/ep/delete";
import Refresh from "@iconify-icons/ep/refresh";
@ -38,115 +38,63 @@ const {
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="所属模块" prop="module">
<el-input
v-model="form.module"
placeholder="请输入所属模块"
clearable
class="!w-[170px]"
/>
<el-input v-model="form.module" class="!w-[170px]" clearable placeholder="请输入所属模块" />
</el-form-item>
<el-form-item label="请求时间" prop="requestTime">
<el-date-picker
v-model="form.requestTime"
:shortcuts="getPickerShortcuts()"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期时间"
end-placeholder="结束日期时间"
/>
<el-date-picker v-model="form.requestTime" :shortcuts="getPickerShortcuts()" end-placeholder="结束日期时间" range-separator="" start-placeholder="开始日期时间" type="datetimerange" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置</el-button>
</el-form-item>
</el-form>
<PureTableBar
title="系统日志(仅演示,操作后不生效)"
:columns="columns"
@refresh="onSearch"
>
<PureTableBar :columns="columns" title="系统日志(仅演示,操作后不生效)" @refresh="onSearch">
<template #buttons>
<el-popconfirm title="确定要删除所有日志数据吗?" @confirm="clearAll">
<template #reference>
<el-button type="danger" :icon="useRenderIcon(Delete)">
清空日志
</el-button>
<el-button :icon="useRenderIcon(Delete)" type="danger"> 清空日志</el-button>
</template>
</el-popconfirm>
</template>
<template v-slot="{ size, dynamicColumns }">
<div
v-if="selectedNum > 0"
v-motion-fade
class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center"
>
<div v-if="selectedNum > 0" v-motion-fade class="bg-[var(--el-fill-color-light)] w-full h-[46px] mb-2 pl-4 flex items-center">
<div class="flex-auto">
<span
style="font-size: var(--el-font-size-base)"
class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]"
>
已选 {{ selectedNum }}
</span>
<el-button type="primary" text @click="onSelectionCancel">
取消选择
</el-button>
<span class="text-[rgba(42,46,54,0.5)] dark:text-[rgba(220,220,242,0.5)]" style="font-size: var(--el-font-size-base)"> 已选 {{ selectedNum }} </span>
<el-button text type="primary" @click="onSelectionCancel"> 取消选择</el-button>
</div>
<el-popconfirm title="是否确认删除?" @confirm="onbatchDel">
<template #reference>
<el-button type="danger" text class="mr-1"> 批量删除 </el-button>
<el-button class="mr-1" text type="danger"> 批量删除</el-button>
</template>
</el-popconfirm>
</div>
<pure-table
ref="tableRef"
row-key="id"
align-whole="center"
table-layout="auto"
:loading="loading"
:size="size"
adaptive
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:columns="dynamicColumns"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:size="size"
adaptive
align-whole="center"
row-key="id"
table-layout="auto"
@selection-change="handleSelectionChange"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
@cell-dblclick="handleCellDblclick"
>
<template #operation="{ row }">
<el-button
class="reset-margin !outline-none"
link
type="primary"
:size="size"
:icon="useRenderIcon(View)"
@click="onDetail(row)"
>
详情
</el-button>
<el-button :icon="useRenderIcon(View)" :size="size" class="reset-margin !outline-none" link type="primary" @click="onDetail(row)"> 详情 </el-button>
</template>
</pure-table>
</template>
@ -154,7 +102,7 @@ const {
</div>
</template>
<style scoped lang="scss">
<style lang="scss" scoped>
:deep(.el-dropdown-menu__item i) {
margin: 0;
}

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useRole } from "./hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRole } from "@/hooks/monitor/useRole";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Plane from "@iconify-icons/ri/plane-line";
@ -12,93 +12,47 @@ defineOptions({
});
const formRef = ref();
const {
form,
loading,
columns,
dataList,
pagination,
onSearch,
resetForm,
handleOffline,
handleSizeChange,
handleCurrentChange,
handleSelectionChange
} = useRole();
const { form, loading, columns, dataList, pagination, onSearch, resetForm, handleOffline, handleSizeChange, handleCurrentChange, handleSelectionChange } = useRole();
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="用户名" prop="username">
<el-input
v-model="form.username"
placeholder="请输入用户名"
clearable
class="!w-[180px]"
/>
<el-input v-model="form.username" class="!w-[180px]" clearable placeholder="请输入用户名" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置</el-button>
</el-form-item>
</el-form>
<PureTableBar
title="在线用户(仅演示,操作后不生效)"
:columns="columns"
@refresh="onSearch"
>
<PureTableBar :columns="columns" title="在线用户(仅演示,操作后不生效)" @refresh="onSearch">
<template v-slot="{ size, dynamicColumns }">
<pure-table
align-whole="center"
showOverflowTooltip
table-layout="auto"
:loading="loading"
:size="size"
adaptive
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:columns="dynamicColumns"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:size="size"
adaptive
align-whole="center"
showOverflowTooltip
table-layout="auto"
@selection-change="handleSelectionChange"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
>
<template #operation="{ row }">
<el-popconfirm
:title="`是否强制下线${row.username}`"
@confirm="handleOffline(row)"
>
<el-popconfirm :title="`是否强制下线${row.username}`" @confirm="handleOffline(row)">
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Plane)"
>
强退
</el-button>
<el-button :icon="useRenderIcon(Plane)" :size="size" class="reset-margin" link type="primary"> 强退 </el-button>
</template>
</el-popconfirm>
</template>
@ -108,7 +62,7 @@ const {
</div>
</template>
<style scoped lang="scss">
<style lang="scss" scoped>
:deep(.el-dropdown-menu__item i) {
margin: 0;
}

View File

@ -1,9 +1,9 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import ReCol from "@/components/ReCol";
import { formRules } from "./utils/rule";
import { FormProps } from "./utils/types";
import { usePublicHooks } from "../hooks";
import { usePublicHooks } from "@/hooks/system/usePublicHooks";
const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({
@ -31,18 +31,12 @@ defineExpose({ getRef });
</script>
<template>
<el-form
ref="ruleFormRef"
:model="newFormInline"
:rules="formRules"
label-width="82px"
>
<el-form ref="ruleFormRef" :model="newFormInline" :rules="formRules" label-width="82px">
<el-row :gutter="30">
<re-col>
<el-form-item label="上级部门">
<el-cascader
v-model="newFormInline.parentId"
class="w-full"
:options="newFormInline.higherDeptOptions"
:props="{
value: 'id',
@ -50,6 +44,7 @@ defineExpose({ getRef });
emitPath: false,
checkStrictly: true
}"
class="w-full"
clearable
filterable
placeholder="请选择上级部门"
@ -62,76 +57,42 @@ defineExpose({ getRef });
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="部门名称" prop="name">
<el-input
v-model="newFormInline.name"
clearable
placeholder="请输入部门名称"
/>
<el-input v-model="newFormInline.name" clearable placeholder="请输入部门名称" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="部门负责人">
<el-input
v-model="newFormInline.principal"
clearable
placeholder="请输入部门负责人"
/>
<el-input v-model="newFormInline.principal" clearable placeholder="请输入部门负责人" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="手机号" prop="phone">
<el-input
v-model="newFormInline.phone"
clearable
placeholder="请输入手机号"
/>
<el-input v-model="newFormInline.phone" clearable placeholder="请输入手机号" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="邮箱" prop="email">
<el-input
v-model="newFormInline.email"
clearable
placeholder="请输入邮箱"
/>
<el-input v-model="newFormInline.email" clearable placeholder="请输入邮箱" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="排序">
<el-input-number
v-model="newFormInline.sort"
class="!w-full"
:min="0"
:max="9999"
controls-position="right"
/>
<el-input-number v-model="newFormInline.sort" :max="9999" :min="0" class="!w-full" controls-position="right" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="部门状态">
<el-switch
v-model="newFormInline.status"
inline-prompt
:active-value="1"
:inactive-value="0"
active-text="启用"
inactive-text="停用"
:style="switchStyle"
/>
<el-switch v-model="newFormInline.status" :active-value="1" :inactive-value="0" :style="switchStyle" active-text="启用" inactive-text="停用" inline-prompt />
</el-form-item>
</re-col>
<re-col>
<el-form-item label="备注">
<el-input
v-model="newFormInline.remark"
placeholder="请输入备注信息"
type="textarea"
/>
<el-input v-model="newFormInline.remark" placeholder="请输入备注信息" type="textarea" />
</el-form-item>
</re-col>
</el-row>

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useDept } from "./utils/hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Delete from "@iconify-icons/ep/delete";
@ -15,131 +15,57 @@ defineOptions({
const formRef = ref();
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
openDialog,
handleDelete,
handleSelectionChange
} = useDept();
const { form, loading, columns, dataList, onSearch, resetForm, openDialog, handleDelete, handleSelectionChange } = useDept();
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="部门名称:" prop="name">
<el-input
v-model="form.name"
placeholder="请输入部门名称"
clearable
class="!w-[180px]"
/>
<el-input v-model="form.name" class="!w-[180px]" clearable placeholder="请输入部门名称" />
</el-form-item>
<el-form-item label="状态:" prop="status">
<el-select
v-model="form.status"
placeholder="请选择状态"
clearable
class="!w-[180px]"
>
<el-option label="启用" :value="1" />
<el-option label="停用" :value="0" />
<el-select v-model="form.status" class="!w-[180px]" clearable placeholder="请选择状态">
<el-option :value="1" label="启用" />
<el-option :value="0" label="停用" />
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置 </el-button>
</el-form-item>
</el-form>
<PureTableBar
title="部门管理(仅演示,操作后不生效)"
:columns="columns"
:tableRef="tableRef?.getTableRef()"
@refresh="onSearch"
>
<PureTableBar :columns="columns" :tableRef="tableRef?.getTableRef()" title="部门管理(仅演示,操作后不生效)" @refresh="onSearch">
<template #buttons>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
新增部门
</el-button>
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增部门 </el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table
ref="tableRef"
adaptive
:adaptiveConfig="{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
default-expand-all
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:size="size"
adaptive
align-whole="center"
default-expand-all
row-key="id"
showOverflowTooltip
table-layout="auto"
@selection-change="handleSelectionChange"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
</el-button>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增', { parentId: row.id } as any)"
>
新增
</el-button>
<el-popconfirm
:title="`是否确认删除部门名称为${row.name}的这条数据`"
@confirm="handleDelete(row)"
>
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="openDialog('修改', row)"> 修改 </el-button>
<el-button :icon="useRenderIcon(AddFill)" :size="size" class="reset-margin" link type="primary" @click="openDialog('新增', { parentId: row.id } as any)"> 新增 </el-button>
<el-popconfirm :title="`是否确认删除部门名称为${row.name}的这条数据`" @confirm="handleDelete(row)">
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
</el-button>
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
</template>
</el-popconfirm>
</template>

View File

@ -1,4 +1,4 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import ReCol from "@/components/ReCol";
import { formRules } from "./utils/rule";
@ -7,15 +7,7 @@ import { transformI18n } from "@/plugins/i18n";
import { IconSelect } from "@/components/ReIcon";
import Segmented from "@/components/ReSegmented";
import ReAnimateSelector from "@/components/ReAnimateSelector";
import {
menuTypeOptions,
showLinkOptions,
fixedTagOptions,
keepAliveOptions,
hiddenTagOptions,
showParentOptions,
frameLoadingOptions
} from "./utils/enums";
import { fixedTagOptions, frameLoadingOptions, hiddenTagOptions, keepAliveOptions, menuTypeOptions, showLinkOptions, showParentOptions } from "./utils/enums";
const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({
@ -55,19 +47,11 @@ defineExpose({ getRef });
</script>
<template>
<el-form
ref="ruleFormRef"
:model="newFormInline"
:rules="formRules"
label-width="82px"
>
<el-form ref="ruleFormRef" :model="newFormInline" :rules="formRules" label-width="82px">
<el-row :gutter="30">
<re-col>
<el-form-item label="菜单类型">
<Segmented
v-model="newFormInline.menuType"
:options="menuTypeOptions"
/>
<Segmented v-model="newFormInline.menuType" :options="menuTypeOptions" />
</el-form-item>
</re-col>
@ -75,7 +59,6 @@ defineExpose({ getRef });
<el-form-item label="上级菜单">
<el-cascader
v-model="newFormInline.parentId"
class="w-full"
:options="newFormInline.higherMenuOptions"
:props="{
value: 'id',
@ -83,6 +66,7 @@ defineExpose({ getRef });
emitPath: false,
checkStrictly: true
}"
class="w-full"
clearable
filterable
placeholder="请选择上级菜单"
@ -95,158 +79,80 @@ defineExpose({ getRef });
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="菜单名称" prop="title">
<el-input
v-model="newFormInline.title"
clearable
placeholder="请输入菜单名称"
/>
<el-input v-model="newFormInline.title" clearable placeholder="请输入菜单名称" />
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType !== 3" :value="12" :xs="24" :sm="24">
<re-col v-if="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="路由名称" prop="name">
<el-input
v-model="newFormInline.name"
clearable
placeholder="请输入路由名称"
/>
<el-input v-model="newFormInline.name" clearable placeholder="请输入路由名称" />
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType !== 3" :value="12" :xs="24" :sm="24">
<re-col v-if="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="路由路径" prop="path">
<el-input
v-model="newFormInline.path"
clearable
placeholder="请输入路由路径"
/>
<el-input v-model="newFormInline.path" clearable placeholder="请输入路由路径" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 0"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType === 0" :sm="24" :value="12" :xs="24">
<el-form-item label="组件路径">
<el-input
v-model="newFormInline.component"
clearable
placeholder="请输入组件路径"
/>
<el-input v-model="newFormInline.component" clearable placeholder="请输入组件路径" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<re-col :sm="24" :value="12" :xs="24">
<el-form-item label="菜单排序">
<el-input-number
v-model="newFormInline.rank"
class="!w-full"
:min="1"
:max="9999"
controls-position="right"
/>
<el-input-number v-model="newFormInline.rank" :max="9999" :min="1" class="!w-full" controls-position="right" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 0"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType === 0" :sm="24" :value="12" :xs="24">
<el-form-item label="路由重定向">
<el-input
v-model="newFormInline.redirect"
clearable
placeholder="请输入默认跳转地址"
/>
<el-input v-model="newFormInline.redirect" clearable placeholder="请输入默认跳转地址" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="菜单图标">
<IconSelect v-model="newFormInline.icon" class="w-full" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="右侧图标">
<el-input
v-model="newFormInline.extraIcon"
clearable
placeholder="菜单名称右侧的额外图标"
/>
<el-input v-model="newFormInline.extraIcon" clearable placeholder="菜单名称右侧的额外图标" />
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<re-col v-show="newFormInline.menuType < 2" :sm="24" :value="12" :xs="24">
<el-form-item label="进场动画">
<ReAnimateSelector
v-model="newFormInline.enterTransition"
placeholder="请选择页面进场加载动画"
/>
<ReAnimateSelector v-model="newFormInline.enterTransition" placeholder="请选择页面进场加载动画" />
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<re-col v-show="newFormInline.menuType < 2" :sm="24" :value="12" :xs="24">
<el-form-item label="离场动画">
<ReAnimateSelector
v-model="newFormInline.leaveTransition"
placeholder="请选择页面离场加载动画"
/>
<ReAnimateSelector v-model="newFormInline.leaveTransition" placeholder="请选择页面离场加载动画" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 0"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType === 0" :sm="24" :value="12" :xs="24">
<el-form-item label="菜单激活">
<el-input
v-model="newFormInline.activePath"
clearable
placeholder="请输入需要激活的菜单"
/>
<el-input v-model="newFormInline.activePath" clearable placeholder="请输入需要激活的菜单" />
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType === 3" :value="12" :xs="24" :sm="24">
<re-col v-if="newFormInline.menuType === 3" :sm="24" :value="12" :xs="24">
<!-- 按钮级别权限设置 -->
<el-form-item label="权限标识" prop="auths">
<el-input
v-model="newFormInline.auths"
clearable
placeholder="请输入权限标识"
/>
<el-input v-model="newFormInline.auths" clearable placeholder="请输入权限标识" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType === 1"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType === 1" :sm="24" :value="12" :xs="24">
<!-- iframe -->
<el-form-item label="链接地址">
<el-input
v-model="newFormInline.frameSrc"
clearable
placeholder="请输入 iframe 链接地址"
/>
<el-input v-model="newFormInline.frameSrc" clearable placeholder="请输入 iframe 链接地址" />
</el-form-item>
</re-col>
<re-col v-if="newFormInline.menuType === 1" :value="12" :xs="24" :sm="24">
<re-col v-if="newFormInline.menuType === 1" :sm="24" :value="12" :xs="24">
<el-form-item label="加载动画">
<Segmented
:modelValue="newFormInline.frameLoading ? 0 : 1"
@ -260,12 +166,7 @@ defineExpose({ getRef });
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="菜单">
<Segmented
:modelValue="newFormInline.showLink ? 0 : 1"
@ -278,12 +179,7 @@ defineExpose({ getRef });
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menuType !== 3"
:value="12"
:xs="24"
:sm="24"
>
<re-col v-show="newFormInline.menuType !== 3" :sm="24" :value="12" :xs="24">
<el-form-item label="父级菜单">
<Segmented
:modelValue="newFormInline.showParent ? 0 : 1"
@ -297,7 +193,7 @@ defineExpose({ getRef });
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<re-col v-show="newFormInline.menuType < 2" :sm="24" :value="12" :xs="24">
<el-form-item label="缓存页面">
<Segmented
:modelValue="newFormInline.keepAlive ? 0 : 1"
@ -311,7 +207,7 @@ defineExpose({ getRef });
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<re-col v-show="newFormInline.menuType < 2" :sm="24" :value="12" :xs="24">
<el-form-item label="标签页">
<Segmented
:modelValue="newFormInline.hiddenTag ? 1 : 0"
@ -324,7 +220,7 @@ defineExpose({ getRef });
/>
</el-form-item>
</re-col>
<re-col v-show="newFormInline.menuType < 2" :value="12" :xs="24" :sm="24">
<re-col v-show="newFormInline.menuType < 2" :sm="24" :value="12" :xs="24">
<el-form-item label="固定标签页">
<Segmented
:modelValue="newFormInline.fixedTag ? 0 : 1"

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
<script lang="ts" setup>
import { ref } from "vue";
import { useMenu } from "./utils/hook";
import { transformI18n } from "@/plugins/i18n";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Delete from "@iconify-icons/ep/delete";
@ -16,105 +16,47 @@ defineOptions({
const formRef = ref();
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
openDialog,
handleDelete,
handleSelectionChange
} = useMenu();
const { form, loading, columns, dataList, onSearch, resetForm, openDialog, handleDelete, handleSelectionChange } = useMenu();
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="菜单名称:" prop="title">
<el-input
v-model="form.title"
placeholder="请输入菜单名称"
clearable
class="!w-[180px]"
/>
<el-input v-model="form.title" class="!w-[180px]" clearable placeholder="请输入菜单名称" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置 </el-button>
</el-form-item>
</el-form>
<PureTableBar
title="菜单管理(仅演示,操作后不生效)"
:columns="columns"
:isExpandAll="false"
:tableRef="tableRef?.getTableRef()"
@refresh="onSearch"
>
<PureTableBar :columns="columns" :isExpandAll="false" :tableRef="tableRef?.getTableRef()" title="菜单管理(仅演示,操作后不生效)" @refresh="onSearch">
<template #buttons>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
新增菜单
</el-button>
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增菜单 </el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table
ref="tableRef"
adaptive
:adaptiveConfig="{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:size="size"
adaptive
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
@selection-change="handleSelectionChange"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
</el-button>
<el-button
v-show="row.menuType !== 3"
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增', { parentId: row.id } as any)"
>
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="openDialog('修改', row)"> 修改 </el-button>
<el-button v-show="row.menuType !== 3" :icon="useRenderIcon(AddFill)" :size="size" class="reset-margin" link type="primary" @click="openDialog('新增', { parentId: row.id } as any)">
新增
</el-button>
<el-popconfirm
@ -122,15 +64,7 @@ const {
@confirm="handleDelete(row)"
>
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
</el-button>
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
</template>
</el-popconfirm>
</template>

View File

@ -1,14 +1,9 @@
<script setup lang="ts">
<script lang="ts" setup>
import { useRole } from "./utils/hook";
import { ref, computed, nextTick, onMounted } from "vue";
import { PureTableBar } from "@/components/RePureTableBar";
import { computed, nextTick, onMounted, ref } from "vue";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import {
delay,
subBefore,
deviceDetection,
useResizeObserver
} from "@pureadmin/utils";
import { delay, deviceDetection, subBefore, useResizeObserver } from "@pureadmin/utils";
// import Database from "@iconify-icons/ri/database-2-line";
// import More from "@iconify-icons/ep/more-filled";
@ -82,9 +77,7 @@ onMounted(() => {
useResizeObserver(contentRef, async () => {
await nextTick();
delay(60).then(() => {
treeHeight.value = parseFloat(
subBefore(tableRef.value.getTableDoms().tableWrapper.style.height, "px")
);
treeHeight.value = parseFloat(subBefore(tableRef.value.getTableDoms().tableWrapper.style.height, "px"));
});
});
});
@ -92,134 +85,67 @@ onMounted(() => {
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto"
>
<el-form ref="formRef" :inline="true" :model="form" class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px] overflow-auto">
<el-form-item label="角色名称:" prop="name">
<el-input
v-model="form.name"
placeholder="请输入角色名称"
clearable
class="!w-[180px]"
/>
<el-input v-model="form.name" class="!w-[180px]" clearable placeholder="请输入角色名称" />
</el-form-item>
<el-form-item label="角色标识:" prop="code">
<el-input
v-model="form.code"
placeholder="请输入角色标识"
clearable
class="!w-[180px]"
/>
<el-input v-model="form.code" class="!w-[180px]" clearable placeholder="请输入角色标识" />
</el-form-item>
<el-form-item label="状态:" prop="status">
<el-select
v-model="form.status"
placeholder="请选择状态"
clearable
class="!w-[180px]"
>
<el-select v-model="form.status" class="!w-[180px]" clearable placeholder="请选择状态">
<el-option label="已启用" value="1" />
<el-option label="已停用" value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
搜索
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
</el-button>
<el-button :icon="useRenderIcon('ri:search-line')" :loading="loading" type="primary" @click="onSearch"> 搜索 </el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)"> 重置 </el-button>
</el-form-item>
</el-form>
<div
ref="contentRef"
:class="['flex', deviceDetection() ? 'flex-wrap' : '']"
>
<div ref="contentRef" :class="['flex', deviceDetection() ? 'flex-wrap' : '']">
<PureTableBar
:class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
:columns="columns"
style="transition: width 220ms cubic-bezier(0.4, 0, 0.2, 1)"
title="角色管理(仅演示,操作后不生效)"
:columns="columns"
@refresh="onSearch"
>
<template #buttons>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
新增角色
</el-button>
<el-button :icon="useRenderIcon(AddFill)" type="primary" @click="openDialog()"> 新增角色 </el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table
ref="tableRef"
align-whole="center"
showOverflowTooltip
table-layout="auto"
:loading="loading"
:size="size"
adaptive
:row-style="rowStyle"
:adaptiveConfig="{ offsetBottom: 108 }"
:data="dataList"
:columns="dynamicColumns"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:data="dataList"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
:loading="loading"
:pagination="pagination"
:paginationSmall="size === 'small' ? true : false"
:row-style="rowStyle"
:size="size"
adaptive
align-whole="center"
showOverflowTooltip
table-layout="auto"
@selection-change="handleSelectionChange"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
</el-button>
<el-popconfirm
:title="`是否确认删除角色名称为${row.name}的这条数据`"
@confirm="handleDelete(row)"
>
<el-button :icon="useRenderIcon(EditPen)" :size="size" class="reset-margin" link type="primary" @click="openDialog('修改', row)"> 修改 </el-button>
<el-popconfirm :title="`是否确认删除角色名称为${row.name}的这条数据`" @confirm="handleDelete(row)">
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
</el-button>
<el-button :icon="useRenderIcon(Delete)" :size="size" class="reset-margin" link type="primary"> 删除 </el-button>
</template>
</el-popconfirm>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Menu)"
@click="handleMenu(row)"
>
权限
</el-button>
<el-button :icon="useRenderIcon(Menu)" :size="size" class="reset-margin" link type="primary" @click="handleMenu(row)"> 权限 </el-button>
<!-- <el-dropdown>
<el-button
class="ml-3 mt-[2px]"
@ -262,10 +188,7 @@ onMounted(() => {
</template>
</PureTableBar>
<div
v-if="isShow"
class="!min-w-[calc(100vw-60vw-268px)] mt-2 px-2 pb-2 bg-bg_color ml-2 overflow-auto"
>
<div v-if="isShow" class="!min-w-[calc(100vw-60vw-268px)] mt-2 px-2 pb-2 bg-bg_color ml-2 overflow-auto">
<div class="flex justify-between w-full px-3 pt-5 pb-4">
<div class="flex">
<span :class="iconClass">
@ -273,10 +196,10 @@ onMounted(() => {
v-tippy="{
content: '关闭'
}"
class="dark:text-white"
width="18px"
height="18px"
:icon="Close"
class="dark:text-white"
height="18px"
width="18px"
@click="handleMenu"
/>
</span>
@ -285,10 +208,10 @@ onMounted(() => {
v-tippy="{
content: '保存菜单权限'
}"
class="dark:text-white"
width="18px"
height="18px"
:icon="Check"
class="dark:text-white"
height="18px"
width="18px"
@click="handleSave"
/>
</span>
@ -298,27 +221,13 @@ onMounted(() => {
{{ `${curRow?.name ? `${curRow.name}` : ""}` }}
</p>
</div>
<el-input
v-model="treeSearchValue"
placeholder="请输入菜单进行搜索"
class="mb-1"
clearable
@input="onQueryChanged"
/>
<el-input v-model="treeSearchValue" class="mb-1" clearable placeholder="请输入菜单进行搜索" @input="onQueryChanged" />
<div class="flex flex-wrap">
<el-checkbox v-model="isExpandAll" label="展开/折叠" />
<el-checkbox v-model="isSelectAll" label="全选/全不选" />
<el-checkbox v-model="isLinkage" label="父子联动" />
</div>
<el-tree-v2
ref="treeRef"
show-checkbox
:data="treeData"
:props="treeProps"
:height="treeHeight"
:check-strictly="!isLinkage"
:filter-method="filterMethod"
>
<el-tree-v2 ref="treeRef" :check-strictly="!isLinkage" :data="treeData" :filter-method="filterMethod" :height="treeHeight" :props="treeProps" show-checkbox>
<template #default="{ node }">
<span>{{ transformI18n(node.label) }}</span>
</template>
@ -328,7 +237,7 @@ onMounted(() => {
</div>
</template>
<style scoped lang="scss">
<style lang="scss" scoped>
:deep(.el-dropdown-menu__item i) {
margin: 0;
}

View File

@ -2,7 +2,7 @@
import { ref } from "vue";
import tree from "./tree.vue";
import { useUser } from "./utils/hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { PureTableBar } from "@/components/TableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Upload from "@iconify-icons/ri/upload-line";