update: 菜单管理组件替换、痰喘优化

This commit is contained in:
easy 2023-03-06 20:06:49 +08:00
parent 3039c20e2f
commit d4d26c504d
7 changed files with 256 additions and 328 deletions

View File

@ -1,10 +1,10 @@
<template>
<div class="basic-info-container">
<a-card>
<div class="card">
<h3>基本信息</h3>
<a-form ref="basicFormRef" :model="form.data" class="basic-form">
<j-form ref="basicFormRef" :model="form.data" class="basic-form">
<div class="row" style="display: flex">
<a-form-item
<j-form-item
label="菜单图标"
name="icon"
:rules="[
@ -20,25 +20,28 @@
:type="form.data.icon"
style="font-size: 90px"
/>
<span class="mark" @click="dialog.openDialog"
<span class="mark" @click="dialogVisible = true"
>点击修改</span
>
</div>
<div
v-else
@click="dialog.openDialog"
@click="dialogVisible = true"
class="icon-upload no-icon"
>
<span>
<plus-outlined style="font-size: 30px" />
<AIcon
type="PlusOutlined"
style="font-size: 30px"
/>
<p>点击选择图标</p>
</span>
</div>
</a-form-item>
<a-row :gutter="24" style="flex: 1 1 auto">
<a-col :span="12">
<a-form-item
</j-form-item>
<j-row :gutter="24" style="flex: 1 1 auto">
<j-col :span="12">
<j-form-item
label="名称"
name="name"
:rules="[
@ -46,11 +49,11 @@
{ max: 64, message: '最多可输入64个字符' },
]"
>
<a-input v-model:value="form.data.name" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
<j-input v-model:value="form.data.name" />
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="编码"
name="code"
:rules="[
@ -58,11 +61,11 @@
{ max: 64, message: '最多可输入64个字符' },
]"
>
<a-input v-model:value="form.data.code" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
<j-input v-model:value="form.data.code" />
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="页面地址"
name="url"
:rules="[
@ -73,11 +76,11 @@
{ max: 128, message: '最多可输入128字符' },
]"
>
<a-input v-model:value="form.data.url" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
<j-input v-model:value="form.data.url" />
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="排序"
name="sortIndex"
:rules="[
@ -87,80 +90,84 @@
},
]"
>
<a-input v-model:value="form.data.sortIndex" />
</a-form-item>
</a-col>
</a-row>
<j-input v-model:value="form.data.sortIndex" />
</j-form-item>
</j-col>
</j-row>
</div>
<a-form-item label="说明" name="describe">
<a-textarea
<j-form-item label="说明" name="describe">
<j-textarea
v-model:value="form.data.describe"
:rows="4"
placeholder="请输入说明"
/>
</a-form-item>
</a-form>
</a-card>
<a-card>
</j-form-item>
</j-form>
</div>
<div class="card">
<h3>权限配置</h3>
<a-form
<j-form
ref="permissFormRef"
:model="form.data"
class="basic-form permiss-form"
>
<a-form-item name="accessSupport" required>
<j-form-item name="accessSupport" required>
<template #label>
<span style="margin-right: 3px">数据权限控制</span>
<a-tooltip title="此菜单页面数据所对应的资产类型">
<question-circle-outlined
<j-tooltip title="此菜单页面数据所对应的资产类型">
<AIcon
type="QuestionCircleOutlined"
class="img-style"
style="color: #a6a6a6"
/>
</a-tooltip>
</j-tooltip>
</template>
<a-radio-group
<j-radio-group
v-model:value="form.data.accessSupport"
name="radioGroup"
>
<a-radio value="unsupported">不支持</a-radio>
<a-radio value="support">支持</a-radio>
<a-radio value="indirect">
<j-radio value="unsupported">不支持</j-radio>
<j-radio value="support">支持</j-radio>
<j-radio value="indirect">
<span style="margin-right: 3px">间接控制</span>
<a-tooltip
<j-tooltip
title="此菜单内的数据基于其他菜单的数据权限控制"
>
<question-circle-filled class="img-style" />
</a-tooltip>
</a-radio>
</a-radio-group>
<AIcon
type="QuestionCircleFilled"
class="img-style"
/>
</j-tooltip>
</j-radio>
</j-radio-group>
<a-form-item
<j-form-item
name="assetType"
v-if="form.data.accessSupport === 'support'"
:rules="[{ required: true, message: '请选择资产类型' }]"
style="margin-top: 24px; margin-bottom: 0"
>
<a-select
<j-select
v-model:value="form.data.assetType"
style="width: 500px"
placeholder="请选择资产类型"
>
<a-select-option
<j-select-option
v-for="item in form.assetsType"
:value="item.value"
>{{ item.label }}</a-select-option
>{{ item.label }}</j-select-option
>
</a-select>
</a-form-item>
</j-select>
</j-form-item>
<a-form-item
<j-form-item
name="indirectMenus"
v-if="form.data.accessSupport === 'indirect'"
:rules="[{ required: true, message: '请选择关联菜单' }]"
style="margin-top: 24px; margin-bottom: 0"
>
<a-tree-select
<j-tree-select
v-model:value="form.data.indirectMenus"
style="width: 400px"
:dropdown-style="{
@ -177,18 +184,18 @@
value: 'id',
}"
>
</a-tree-select>
</a-form-item>
</a-form-item>
<a-form-item label="权限">
</j-tree-select>
</j-form-item>
</j-form-item>
<j-form-item label="权限">
<PermissChoose
:first-width="3"
max-height="350px"
v-model:value="form.data.permissions"
:key="form.data.id || ''"
/>
</a-form-item>
</a-form>
</j-form-item>
</j-form>
<PermissionButton
type="primary"
@ -197,22 +204,20 @@
>
保存
</PermissionButton>
</a-card>
</div>
<!-- 弹窗 -->
<div class="dialogs">
<ChooseIconDialog ref="ChooseIconRef" @confirm="dialog.confirm" />
</div>
<ChooseIconDialog
v-if="dialogVisible"
v-model:visible="dialogVisible"
@confirm="(typeStr:string)=>form.data.icon = typeStr"
/>
</div>
</template>
<script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue';
import {
PlusOutlined,
QuestionCircleFilled,
QuestionCircleOutlined,
} from '@ant-design/icons-vue';
import { FormInstance, message } from 'ant-design-vue';
import ChooseIconDialog from '../components/ChooseIconDialog.vue';
import PermissChoose from '../components/PermissChoose.vue';
@ -260,9 +265,12 @@ const form = reactive({
//
routeParams.id &&
getMenuInfo_api(routeParams.id).then((resp: any) => {
console.log(1111);
form.data = {
...(resp.result as formType),
accessSupport: resp.result.accessSupport.value,
accessSupport:
resp.result?.accessSupport?.value || 'unsupported',
};
});
//
@ -323,15 +331,7 @@ const form = reactive({
form.init();
//
const ChooseIconRef = ref<any>(null);
const dialog = {
openDialog: () => {
ChooseIconRef.value && ChooseIconRef.value.openDialog();
},
confirm: (typeStr: string) => {
form.data.icon = typeStr || form.data.icon;
},
};
const dialogVisible = ref(false);
type formType = {
id?: string;
@ -356,8 +356,10 @@ type assetType = {
<style lang="less" scoped>
.basic-info-container {
.ant-card {
.card {
margin-bottom: 24px;
padding: 24px;
background-color: #fff;
h3 {
position: relative;

View File

@ -11,18 +11,18 @@
<PermissionButton
type="primary"
:uhasPermission="`${permission}:update`"
@click="dialog.openDialog('新增')"
@click="openDialog('新增', {})"
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
</template>
<template #action="slotProps">
<a-space :size="16">
<j-space :size="16">
<PermissionButton
type="link"
:uhasPermission="`${permission}:update`"
:tooltip="{ title: '编辑' }"
@click="dialog.openDialog('编辑', slotProps)"
@click="openDialog('编辑', slotProps)"
>
<AIcon type="EditOutlined" />
</PermissionButton>
@ -30,7 +30,7 @@
type="link"
:uhasPermission="true"
:tooltip="{ title: '查看' }"
@click="dialog.openDialog('查看', slotProps)"
@click="openDialog('查看', slotProps)"
>
<AIcon type="SearchOutlined" />
</PermissionButton>
@ -45,15 +45,18 @@
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</j-space>
</template>
</j-pro-table>
<div class="dialog">
<ButtonAddDialog
ref="dialogRef"
@confirm="dialog.confirm"
v-if="dialogVisible"
v-model:visible="dialogVisible"
:menu-info="menuInfo"
:mode="dialogTitle"
:data="selectItem"
@confirm="table.getList"
/>
</div>
</div>
@ -76,15 +79,13 @@ const routeParams = {
};
//
const dialogRef = ref<any>(null);
const dialog = {
//
openDialog: (mode: string, row?: object) => {
dialogRef.value && dialogRef.value.openDialog(mode, { ...row });
},
confirm: () => {
table.getList();
},
const selectItem = ref<any>({});
const dialogVisible = ref(false);
const dialogTitle = ref<'查看' | '新增' | '编辑'>('新增');
const openDialog = (mode: '查看' | '新增' | '编辑', row: object) => {
selectItem.value = { ...row };
dialogTitle.value = mode;
dialogVisible.value = true;
};
// -
const menuInfo = ref<any>({});

View File

@ -1,14 +1,14 @@
<template>
<page-container>
<div class="menu-detail-container">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="basic" tab="基本信息">
<j-tabs v-model:activeKey="activeKey">
<j-tab-pane key="basic" tab="基本信息">
<BasicInfo />
</a-tab-pane>
<a-tab-pane key="button" tab="按钮管理">
</j-tab-pane>
<j-tab-pane key="button" tab="按钮管理">
<ButtonMange />
</a-tab-pane>
</a-tabs>
</j-tab-pane>
</j-tabs>
</div>
</page-container>
</template>

View File

@ -1,13 +1,12 @@
<template>
<a-modal
v-model:visible="dialog.visible"
:title="form.mode"
visible
:title="props.mode"
width="660px"
@ok="dialog.handleOk"
@ok="confirm"
@cancel="emits('update:visible', false)"
:maskClosable="false"
cancelText="取消"
okText="确定"
:confirmLoading="dialog.loading"
:confirmLoading="loading"
>
<a-form :model="form.data" class="basic-form" ref="formRef">
<a-form-item
@ -20,7 +19,7 @@
>
<a-input
v-model:value="form.data.id"
:disabled="form.mode !== '新增'"
:disabled="props.mode !== '新增'"
/>
</a-form-item>
<a-form-item
@ -33,7 +32,7 @@
>
<a-input
v-model:value="form.data.name"
:disabled="form.mode === '查看'"
:disabled="props.mode === '查看'"
/>
</a-form-item>
<a-form-item
@ -47,19 +46,11 @@
},
]"
>
<!-- <a-form-item-rest>
<PermissChoose
:first-width="8"
max-height="350px"
v-model:value="form.data.permissions"
:disabled="form.mode === '查看'"
/>
</a-form-item-rest> -->
<PermissChoose
:first-width="8"
max-height="350px"
v-model:value="form.data.permissions"
:disabled="form.mode === '查看'"
:disabled="props.mode === '查看'"
:key="form.data.id || ''"
/>
</a-form-item>
@ -68,7 +59,7 @@
v-model:value="form.data.describe"
:rows="4"
placeholder="请输入说明"
:disabled="form.mode === '查看'"
:disabled="props.mode === '查看'"
/>
</a-form-item>
</a-form>
@ -81,54 +72,42 @@ import { Rule } from 'ant-design-vue/es/form';
import PermissChoose from '../components/PermissChoose.vue';
import { saveMenuInfo_api } from '@/api/system/menu';
const emits = defineEmits(['confirm', 'update:visible']);
const props = defineProps<{
menuInfo: {
buttons: formType[];
id: string;
};
visible: boolean;
mode: '查看' | '新增' | '编辑';
data: formType;
}>();
const emits = defineEmits(['confirm']);
const dialog = reactive({
visible: false,
loading: false,
handleOk: () => {
props.menuInfo.id &&
formRef.value &&
formRef.value
.validate()
.then(() => {
const buttons = toRaw(props.menuInfo.buttons);
const button = buttons.find(
(item) => item.id === form.data.id,
);
if (button) {
Object.entries(form.data).forEach(([key, value]) => {
button[key] = value;
});
} else buttons.push({ ...form.data });
const params = {
...props.menuInfo,
buttons,
};
dialog.loading = true;
saveMenuInfo_api(params)
.then((resp) => {
dialog.changeVisible();
message.success('操作成功');
emits('confirm');
})
.finally(() => (dialog.loading = false));
})
.catch(() => {});
},
changeVisible: (mode?: string, formValue?: formType) => {
dialog.visible = !dialog.visible;
form.data = { ...initForm, ...formValue };
form.mode = mode || '';
formRef.value && formRef.value.clearValidate();
},
});
const loading = ref(false);
const confirm = () => {
loading.value = true;
formRef.value &&
formRef.value.validate().then(() => {
const buttons = toRaw(props.menuInfo.buttons);
const button = buttons.find((item) => item.id === form.data.id);
if (button) {
Object.entries(form.data).forEach(([key, value]) => {
button[key] = value;
});
} else buttons.push({ ...form.data });
const params = {
...props.menuInfo,
buttons,
};
saveMenuInfo_api(params)
.then((resp) => {
message.success('操作成功');
emits('confirm');
emits('update:visible', false);
})
.finally(() => (loading.value = false));
});
};
const initForm = {
name: '',
id: '',
@ -137,19 +116,13 @@ const initForm = {
} as formType;
const formRef = ref<FormInstance>();
const form = reactive({
data: { ...initForm },
mode: '',
checkPermission: async (_rule: Rule, value: string[]) => {
data: { ...initForm, ...props.data },
checkPermission: (_rule: Rule, value: string[]) => {
if (!value || value.length < 1) return Promise.reject('请选择权限');
return Promise.resolve();
},
});
//
defineExpose({
openDialog: dialog.changeVisible,
});
type formType = {
name: string;
id: string;

View File

@ -1,24 +1,33 @@
<template>
<a-modal
v-model:visible="dialog.visible"
<j-modal
visible
title="菜单图标"
width="800px"
@ok="dialog.handleOk"
@cancel="emits('update:visible', false)"
@ok="confirm"
>
<a-radio-group v-model:value="selected" class="radio">
<a-radio-button
<j-radio-group v-model:value="selected" class="radio">
<j-radio-button
v-for="typeStr in iconKeys"
:value="typeStr"
:class="{ active: selected === typeStr }"
>
<a-icon :type="typeStr" />
</a-radio-button>
</a-radio-group>
</a-modal>
<AIcon :type="typeStr" />
</j-radio-button>
</j-radio-group>
</j-modal>
</template>
<script setup lang="ts">
const emits = defineEmits(['confirm']);
const emits = defineEmits(['confirm', 'update:visible']);
const props = defineProps<{
visible: boolean;
}>();
const confirm = () => {
emits('confirm', selected.value);
emits('update:visible', false);
};
const iconKeys = [
'EyeOutlined',
'EditOutlined',
@ -48,29 +57,11 @@ const iconKeys = [
'TeamOutlined',
'MenuUnfoldOutlined',
'MenuFoldOutlined',
'QuestionCircleOutlined',
'InfoCircleOutlined',
'SearchOutlined',
];
const dialog = reactive({
visible: false,
handleOk: () => {
emits('confirm', selected.value);
dialog.changeVisible();
selected.value = '';
},
changeVisible: (show?: boolean) => {
dialog.visible = show === undefined ? !dialog.visible : show;
},
});
const selected = ref<string>('');
//
defineExpose({
openDialog: dialog.changeVisible,
});
</script>
<style lang="less" scoped>

View File

@ -155,10 +155,12 @@ const permission = reactive({
const checked = checkedValue?.find(
(checkedItem) => checkedItem.permission === item.id,
);
const options = item.actions.map((actionItem: any) => ({
label: actionItem.name,
value: actionItem.action,
}));
const options =
item.actions && item.actions.map((actionItem: any) => ({
label: actionItem.name,
value: actionItem.action,
})) || [];
return {
id: item.id,
name: item.name,
@ -182,7 +184,6 @@ const permission = reactive({
});
permission.init();
type permissionType = {
id: string;
name: string;

View File

@ -1,14 +1,18 @@
<template>
<page-container>
<div class="menu-container">
<Search :columns="query.columns" @search="query.search" />
<j-advanced-search
:columns="columns"
@search="(params:any)=>queryParams = {...params}"
/>
<j-pro-table
ref="tableRef"
:columns="table.columns"
:columns="columns"
:request="table.getList"
model="TABLE"
:params="query.params"
:params="queryParams"
noPagination
>
<template #headerTitle>
<PermissionButton
@ -18,17 +22,11 @@
>
<AIcon type="PlusOutlined" />新增
</PermissionButton>
<a-button
<j-button
style="margin-left: 12px"
@click="router.push('/system/Menu/Setting')"
>菜单配置</a-button
>菜单配置</j-button
>
<!-- <PermissionButton
:uhasPermission="true"
@click="router.push('/system/Menu/Setting')"
>
菜单配置
</PermissionButton> -->
</template>
<template #createTime="slotProps">
{{
@ -38,17 +36,17 @@
}}
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip>
<j-space :size="16">
<j-tooltip>
<template #title>查看</template>
<a-button
<j-button
style="padding: 0"
type="link"
@click="table.toDetails(slotProps)"
>
<search-outlined />
</a-button>
</a-tooltip>
<AIcon type="SearchOutlined" />
</j-button>
</j-tooltip>
<PermissionButton
type="link"
@ -69,7 +67,7 @@
>
<AIcon type="DeleteOutlined" />
</PermissionButton>
</a-space>
</j-space>
</template>
</j-pro-table>
</div>
@ -80,7 +78,6 @@
import PermissionButton from '@/components/PermissionButton/index.vue';
import { getMenuTree_api, delMenuInfo_api } from '@/api/system/menu';
import { SearchOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import moment from 'moment';
@ -88,112 +85,75 @@ const permission = 'system/Menu';
const router = useRouter();
//
const query = reactive({
columns: [
{
title: '编码',
dataIndex: 'code',
key: 'code',
ellipsis: true,
fixed: 'left',
search: {
type: 'string',
},
const columns = [
{
title: '编码',
dataIndex: 'code',
key: 'code',
ellipsis: true,
fixed: 'left',
search: {
type: 'string',
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '页面地址',
dataIndex: 'url',
key: 'url',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '排序',
dataIndex: 'sortIndex',
key: 'sortIndex',
ellipsis: true,
search: {
type: 'number',
},
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
ellipsis: true,
search: {
type: 'date',
},
},
],
params: {
terms: [],
width: 300,
},
search: (params: any) => {
query.params = params;
{
title: '名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
search: {
type: 'string',
},
width: 220,
},
});
{
title: '页面地址',
dataIndex: 'url',
key: 'url',
ellipsis: true,
search: {
type: 'string',
},
},
{
title: '排序',
dataIndex: 'sortIndex',
key: 'sortIndex',
ellipsis: true,
search: {
type: 'number',
},
width: 80,
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
width: 200,
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
ellipsis: true,
search: {
type: 'date',
},
width: 180,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
scopedSlots: true,
width: 140,
},
];
const queryParams = ref({ terms: [] });
const tableRef = ref<Record<string, any>>({}); //
const table = reactive({
columns: [
{
title: '编码',
dataIndex: 'code',
key: 'code',
width: 300,
},
{
title: '名称',
dataIndex: 'name',
key: 'name',
width: 220,
},
{
title: '页面地址',
dataIndex: 'url',
key: 'url',
},
{
title: '排序',
dataIndex: 'sortIndex',
key: 'sortIndex',
width: 80,
},
{
title: '说明',
dataIndex: 'describe',
key: 'describe',
width: 200,
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
scopedSlots: true,
width: 180,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
scopedSlots: true,
width: 140,
},
],
tableData: [],
total: 0,
getList: async (_params: any) => {
//
@ -220,7 +180,7 @@ const table = reactive({
..._params,
terms:
_params.terms && _params.length !== 0
? [...query.params.terms, item]
? [..._params.terms, item]
: [item],
sorts: [{ name: 'sortIndex', order: 'asc' }],
paging: false,
@ -233,9 +193,9 @@ const table = reactive({
code: resp.message,
result: {
data: resp.result,
pageIndex: 0,
pageSize: 0,
total: 0,
pageIndex: resp.pageIndex,
pageSize: resp.pageSize,
total: resp.total,
},
status: resp.status,
};