feat:优化页面代码及版本升级报错处理

branch_202502110906
朱群锋 2025-02-11 17:29:41 +08:00
parent 969d9f5d7d
commit c827a97c3b
5 changed files with 340 additions and 740 deletions

View File

@ -1,31 +1,37 @@
<script setup lang="ts">
import {reactive, toRefs} from 'vue'
import * as ElIcons from '@element-plus/icons-vue'
import {reactive, toRefs} from 'vue'
import * as ElIcons from '@element-plus/icons-vue'
const prop = defineProps({
iconVisible: {
type: Boolean,
default: false
}
})
const prop = defineProps({
visible: {
type: Boolean,
default: false
}
})
defineEmits(['onIcon'])
const state = reactive({
iconList: ElIcons,
})
const {iconList} = toRefs(state)
const emits = defineEmits(['onIcon'])
const handleClose = (val: any) => {
//
emits('onIcon',val)
}
let { visible } = toRefs(prop)
const state = reactive({
iconList: ElIcons,
})
const {iconList} = toRefs(state)
</script>
<template>
<el-dialog v-model="prop.iconVisible" title="图标" :close-on-press-escape="false" :close-on-click-modal="false" :show-close="false" width="70%">
<el-icon v-for="icon in iconList" @click="$emit('onIcon', icon)" :size="30" color="#242e42"
style="border: 1px solid #e4e7ed;padding: 1rem;cursor: pointer;">
<component :is="icon"></component>
</el-icon>
</el-dialog>
<el-dialog v-model="visible" title="图标"
@close="handleClose"
width="70%">
<el-icon v-for="icon in iconList" @click="$emit('onIcon', icon)" :size="30" color="#242e42"
style="border: 1px solid #e4e7ed;padding: 1rem;cursor: pointer;">
<component :is="icon"></component>
</el-icon>
</el-dialog>
</template>
<style lang="scss">
.el-dialog__header{
margin: 0 !important;
}
<style lang="scss">
.el-dialog__header {
margin: 0 !important;
}
</style>

View File

@ -1,413 +0,0 @@
<script setup lang="ts">
import { reactive, onMounted, ref } from "vue"
import {ElMessage, ElMessageBox} from 'element-plus'
import type {FormInstance} from 'element-plus'
import Table from '@/components/Table.vue'
import { page, del, save, execute, tables, columns } from "@/api/lowcode/codeGen"
const searchForm = reactive({
tableName: null
})
const table = reactive({
loading: false,
page: {
current: 1,
size: 10,
total: 1,
},
operation:{
isShow: true,
width: '240'
},
tableTitle: [
{prop:'dataSource',label:'数据源'},
{prop:'tableName',label:'表名'},
{prop:'tableComment',label:'表注释'},
{prop:'subTableName',label:'子表名称'},
{prop:'subTableComment',label:'子表注释'},
{prop:'updateTime',label:'更新时间'},
{prop:'createTime',label:'创建时间'}
],
tableData:[],
})
onMounted(()=>{
onCodeGenPage()
})
function onCodeGenPage(){
table.loading = true;
page(Object.assign(table.page, searchForm)).then((res:any)=>{
if(res){
table.loading = false;
table.tableData = res.result.records;
table.page.current = res.result.current;
table.page.size = res.result.size;
table.page.total = res.result.total;
}
})
}
function onSizeChange(e){
table.page.size = e;
onCodeGenPage();
}
function onCurrentChange(e){
table.page.current = e;
onCodeGenPage();
}
function onRefresh(){
searchForm.tableName = null
onCodeGenPage();
}
function onSearch(){
onCodeGenPage();
}
var validatePath = (rule:any, value:any, callback:any) => {
if(!value.startsWith('/')){
callback(new Error('请以“/”开头'));
}else if(value.endsWith('/')){
callback(new Error('不能以“/”结尾'));
}else{
callback();
}
}
const formRef = ref<FormInstance>()
const form = reactive({
tableList: [],
primary:'',
tabsActive: 'table',
codeVisible: false,
templates: [
{ label: '单表(增删改查)', value: 'single' },
{ label: '树表(增删改查)', value: 'tree' },
{ label: '主子表(增删改查)', value: 'subTable' }
],
codeForm: {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
})
function onTables(){
tables({name: 'tansci_boot'}).then((res:any)=>{
form.tableList = res.result
})
}
function onDelete(val:any){
ElMessageBox.confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
del(val.column.row.id).then(res=>{
if(res){
ElMessage.success('删除成功!');
onCodeGenPage();
}
})
}).catch(e=>{
console.log(e)
})
}
function onAdd(){
onTables()
form.tabsActive = 'table'
form.codeForm = {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
form.codeVisible = true
}
function onTablechange(){
let _table = form.tableList.find(item => form.codeForm.tableName == item.tableName )
form.codeForm.tableComment = _table.tableComment
form.codeForm.dataSource = _table.tableSchema
columns({name: form.codeForm.tableName}).then((res:any)=>{
// form.codeForm.columns = res.result
let _columns = res.result
form.codeForm.columns = []
_columns.forEach((it:any) => {
form.codeForm.columns.push({
columnName: it.columnName.replace(/\_(\w)/g, (all, letter) => letter.toUpperCase()),
columnComment: it.columnComment,
columnType: it.columnType,
component: `component: 'input'`,
where: '=',
save: true,
query: true,
list: true,
required: it.required == 1
})
})
})
}
function onSubTableChange(){
columns({name: form.codeForm.info.subTable}).then((res:any)=>{
// form.codeForm.subColumns = res.result
let _columns = res.result
form.codeForm.subColumns = []
_columns.forEach((it:any) => {
form.codeForm.subColumns.push({
columnName: it.columnName.replace(/\_(\w)/g, (all, letter) => letter.toUpperCase()),
columnComment: it.columnComment,
columnType: it.columnType,
component: `component: 'input'`,
where: '=',
save: true,
query: true,
list: true,
required: it.required == 1
})
})
})
}
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid)=>{
if(valid){
ElMessageBox.confirm('此操作会生成代码并覆盖, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let formData = new FormData()
formData.append("tableName", form.codeForm.tableName)
formData.append("tableComment", form.codeForm.tableComment)
formData.append("dataSource", form.codeForm.dataSource)
formData.append("info", JSON.stringify(form.codeForm.info))
formData.append("columns", JSON.stringify(form.codeForm.columns))
formData.append("subTableName", form.codeForm.info.subTable)
formData.append("subColumns", JSON.stringify(form.codeForm.subColumns))
execute(formData).then((res:any)=>{
formData.append("interfaceId", res.result)
save(formData).then((res:any)=>{
ElMessage.success("添加成功!");
onCodeGenPage()
form.codeVisible = false
})
})
})
}
})
}
</script>
<template>
<div class="codegen-container">
<Table :data="table.tableData" :column="table.tableTitle" :operation="table.operation" :page="table.page" :loading="table.loading"
@onSizeChange="onSizeChange" @onCurrentChange="onCurrentChange">
<template #search>
<div><el-button type="primary" @click="onAdd"></el-button></div>
<div><el-input v-model="searchForm.tableName" placeholder="请输入表名"></el-input></div>
<div><el-button @click="onRefresh" icon="RefreshRight" circle></el-button></div>
<div><el-button @click="onSearch" type="primary" icon="Search">查询</el-button></div>
</template>
<template #column="scope">
<el-button @click="onDelete(scope)" type='primary' link style="color:var(--delete); padding:0;">删除</el-button>
</template>
</Table>
<el-dialog v-model="form.codeVisible" title="接口生成" :show-close="false" width="60%" >
<el-form ref="formRef" :model="form.codeForm" :rules="rules" status-icon label-width="100px">
<div style="padding-bottom: 1rem;">数据源信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="表 名" prop="tableName" :rules="[{ required: true, message: '请选择表', trigger: 'change' }]">
<el-select v-model="form.codeForm.tableName" @change="onTablechange()" placeholder="请选择表" style="width:100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableName" :value="item.tableName">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.tableComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="描 述" prop="tableComment" :rules="[{ required: true, message: '请输入描述', trigger: 'change' }]">
<el-input v-model="form.codeForm.tableComment" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<div style="padding: 1rem ;">生成接口信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="生成模板" prop="info.template" :rules="[{ required: true, message: '请选择模板', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.template" placeholder="请选择模板" style="width:100%">
<el-option v-for="item in form.templates" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模板单表树表主子表增删改查</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.moduleName" label="模块名称" :rules="[{ required: true, message: '请输入模块名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.moduleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块名称第一级分组名称例如系统功能</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.modulePath" label="模块路径" :rules="[{ required: true, message: '请输入模块路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.modulePath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块路径第一级分组的路径例如/system</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessName" label="功能名称" :rules="[{ required: true, message: '请输入功能名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.businessName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能名称第二级分组名称例如菜单管理</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessPath" label="功能路径" :rules="[{ required: true, message: '请输入功能路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.businessPath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能路径第二级分组路径例如/menu</span>
</el-col>
</el-row>
<div v-if="form.codeForm.info.template == 'tree'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treeId" label="树编码" :rules="[{ required: true, message: '请选择树编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treeId" placeholder="请选择树编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树编码树显示的编码字段名称例如id</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treePid" label="父编码" :rules="[{ required: true, message: '请选择树父编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treePid" placeholder="请选择树父编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树父编码树显示的父编码字段名称例如pid</span>
</el-col>
</el-row>
</div>
<div v-if="form.codeForm.info.template == 'subTable'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTable" label="关联子表名" :rules="[{ required: true, message: '请选择关联子表名称', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTable" @change="onSubTableChange()" placeholder="请选择表" style="width:100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableComment" :value="item.tableName">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.tableComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>关联子表名关联字表的名称例如sys_menu_role</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTableKey" label="子表外键名" :rules="[{ required: true, message: '请选择子表关联的外键名', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTableKey" placeholder="请选择子表关联的外键名" style="width:100%">
<el-option v-for="item in form.codeForm.subColumns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>子表关联的外键名子表关联的外键名例如menu_id</span>
</el-col>
</el-row>
</div>
</el-card>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="form.codeVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit(formRef)"></el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<style lang="scss" scoped>
.codegen-container{
}
</style>

View File

@ -1,24 +0,0 @@
<script setup lang="ts">
import { reactive, getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance()
const state = reactive({
url: proxy.$global.baseApi + '/api/web/index.html'
})
</script>
<template>
<div>
<iframe :src="state.url" width="100%" height="100%" frameborder="0"></iframe>
</div>
</template>
<style scoped>
iframe{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
</style>

View File

@ -348,7 +348,7 @@ function onClassifySubmit() {
<span>{{ node.label }}</span>
</span>
<template #content>
<el-button-group size="mini">
<el-button-group size="small">
<el-button @click="onOperateChange(data,1)" icon="check"></el-button>
<el-button @click="onOperateChange(data,2)" icon="edit"></el-button>
<el-button @click="onOperateChange(data,3)" icon="delete"></el-button>

View File

@ -1,19 +1,129 @@
<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import type {FormInstance} from 'element-plus'
import {list,save,update,del} from '@/api/system/menu'
import ElIcon from '@/components/ElIcon.vue'
import {onMounted, reactive, ref} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import type {FormInstance} from 'element-plus'
import {list, save, update, del} from '@/api/system/menu'
import ElIcon from '@/components/ElIcon.vue'
const menuFormRef = ref<FormInstance>();
const state = reactive({
treeData: [],
treeList: [],
operate: 0,
type: 1,
menuForm:{
const menuFormRef = ref<FormInstance>();
const state = reactive({
treeData: [],
treeList: [],
operate: 0,
type: 1,
menuForm: {
id: '',
parentId: '',
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
},
menuId: null,
iconVisible: false,
})
onMounted(() => {
onMenuTree()
})
function onMenuTree() {
list({}).then((res: any) => {
if (res) {
state.treeData = res.result;
state.treeList = [];
}
})
}
function onNodeClick(data: any) {
if (data.permission) {
state.type = 2;
} else {
state.type = 1;
}
state.operate = 0;
state.menuId = data.id;
state.menuForm = {
id: data.id,
parentId: data.parentId,
name: data.name,
url: data.url,
icon: data.icon,
chineseName: data.chineseName,
englishName: data.englishName,
sort: data.sort,
componentType: data.componentType,
component: data.component,
openMode: data.openMode,
isDel: data.isDel,
keepAlive: data.keepAlive,
isShow: data.isShow,
remarks: data.remarks,
permission: data.permission
}
}
function onTypeChange(type: any) {
state.type = type
}
function onOperateChange(val: any) {
if (val == 1) {
let menuId = '0'
if (state.menuId) {
menuId = state.menuId
}
state.operate = 1;
state.menuForm = {
id: '',
parentId: menuId,
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
}
} else if (val == 2) {
state.operate = 2;
} else {
if (!state.menuId) {
ElMessage.warning("请选择要删除的菜单!")
return false;
}
state.operate = 0;
ElMessageBox.confirm('此操作将永久删除该菜单, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
del(state.menuId).then(res => {
if (res) {
ElMessage.success("删除成功!");
state.menuForm = {
id: '',
parentId: '',
parentId: '0',
name: '',
url: '',
icon: '',
@ -28,288 +138,209 @@
isShow: 0,
remarks: '',
permission: null
},
menuId: null,
iconVisible: false,
};
onMenuTree();
}
})
}).catch(e => {
console.log(e)
})
}
}
onMounted(()=>{
onMenuTree()
})
function onFormIcon() {
state.iconVisible = true;
}
function onMenuTree(){
list({}).then((res:any)=>{
if(res){
state.treeData = res.result;
state.treeList = [];
function onIcon(val: any) {
if(val) {
state.menuForm.icon = val.name;
}
state.iconVisible = false;
}
}
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (valid) {
if (state.operate == 1) {
save(state.menuForm).then(res => {
if (res) {
ElMessage.success("添加成功!");
onMenuTree();
}
})
}
function onNodeClick(data:any){
if(data.permission){
state.type = 2;
} else {
state.type = 1;
}
state.operate = 0;
state.menuId = data.id;
state.menuForm = {
id: data.id,
parentId: data.parentId,
name: data.name,
url: data.url,
icon: data.icon,
chineseName: data.chineseName,
englishName: data.englishName,
sort: data.sort,
componentType: data.componentType,
component: data.component,
openMode: data.openMode,
isDel: data.isDel,
keepAlive: data.keepAlive,
isShow: data.isShow,
remarks: data.remarks,
permission: data.permission
}
}
function onTypeChange(type:any){
state.type = type
}
function onOperateChange(val:any){
if(val == 1){
let menuId = '0'
if(state.menuId){
menuId = state.menuId
}
state.operate = 1;
state.menuForm = {
id: '',
parentId: menuId,
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
}
} else if(val == 2) {
state.operate = 2;
} else {
if(!state.menuId){
ElMessage.warning("请选择要删除的菜单!")
return false;
}
state.operate = 0;
ElMessageBox.confirm('此操作将永久删除该菜单, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
del(state.menuId).then(res=>{
if(res){
ElMessage.success("删除成功!");
state.menuForm = {
id: '',
parentId: '0',
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
};
onMenuTree();
}
})
}).catch(e=>{
console.log(e)
})
}
}
function onFormIcon(){
state.iconVisible = true;
}
function onIcon(val:any){
state.menuForm.icon = val.name;
state.iconVisible = false;
}
const onSubmit = async (formEl: FormInstance | undefined) =>{
if (!formEl) return;
await formEl.validate((valid)=>{
if(valid){
if(state.operate == 1){
save(state.menuForm).then(res=>{
if(res){
ElMessage.success("添加成功!");
onMenuTree();
}
})
} else if (state.operate == 2) {
update(state.menuForm).then(res=>{
if(res){
ElMessage.success("更新成功!");
onMenuTree();
}
})
}
state.menuForm = {
id: '',
parentId: '0',
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
};
state.operate = 0;
}
} else if (state.operate == 2) {
update(state.menuForm).then(res => {
if (res) {
ElMessage.success("更新成功!");
onMenuTree();
}
})
}
state.menuForm = {
id: '',
parentId: '0',
name: '',
url: '',
icon: '',
chineseName: '',
englishName: '',
sort: 0,
componentType: 0,
component: null,
openMode: 0,
isDel: 0,
keepAlive: 0,
isShow: 0,
remarks: '',
permission: null
};
state.operate = 0;
}
})
}
</script>
<template>
<div class="menu-container">
<div class="menu-tree">
<el-scrollbar height="45rem">
<el-tree :data="state.treeData" :props="{children: 'children', label: 'chineseName'}" highlight-current @node-click="onNodeClick" empty-text="">
<template #default="{ node, data }">
<div class="menu-container">
<div class="menu-tree">
<el-scrollbar height="45rem">
<el-tree :data="state.treeData" :props="{children: 'children', label: 'chineseName'}" highlight-current
@node-click="onNodeClick" empty-text="暂无菜单">
<template #default="{ node, data }">
<span class="custom-tree-node">
<el-icon v-if="data.icon" style="vertical-align: middle;padding-right:10px;">
<component :is="data.icon"></component>
</el-icon>
<span>{{ node.label }}</span>
</span>
</template>
</el-tree>
</el-scrollbar>
</div>
<div class="menu-form">
<el-radio-group @change="onTypeChange" v-model="state.type">
<el-radio-button :value="1">菜单</el-radio-button>
<el-radio-button :value="2">按钮</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" style="margin: 0 1rem;"/>
<el-radio-group @change="onOperateChange" v-model="state.operate">
<el-radio-button v-permission="'menu:save'" :value="1"></el-radio-button>
<el-radio-button v-permission="'menu:update'" :value="2"></el-radio-button>
<el-radio-button v-permission="'menu:delete'" :value="3"></el-radio-button>
</el-radio-group>
<el-divider content-position="left">菜单详情</el-divider>
<el-form :model="state.menuForm" ref="menuFormRef" :disabled="state.operate===0 || state.operate===3" label-position="right" label-width="150px">
<el-form-item v-if="state.type == 1" label="父级菜单" prop="parentId" :rules="[{required: true, message: '父级不能为空', trigger: 'blur'}]">
<el-tree-select v-model="state.menuForm.parentId" :data="state.treeList" :props="{children: 'children', label: 'chineseName'}" node-key="id"
check-strictly :render-after-expand="false" :default-checked-keys="[state.menuForm.parentId]" :default-expanded-keys="[state.menuForm.parentId]" placeholder="请选父级菜单" style="width:50%"/>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单名称" prop="name" :rules="[{required: true, message: '名称不能为空', trigger: 'blur'},{pattern: /^[A-Za-z0-9]+$/, message: '必须是字母', trigger: 'blur'}]">
<el-input v-model="state.menuForm.name" placeholder="请输入名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单路由" prop="url" :rules="[{required: true, message: '路由不能为空', trigger: 'blur'}]">
<el-input v-model="state.menuForm.url" placeholder="请输入路由" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单图标" prop="icon" :rules="[{required: true, message: '菜单图标不能为空', trigger: 'blur'}]">
<el-input v-model="state.menuForm.icon" @click="onFormIcon" readonly suffix-icon="Platform" style="width:50%"></el-input>
<ElIcon :iconVisible="state.iconVisible" @onIcon="onIcon"/>
</el-form-item>
<el-form-item v-if="state.type == 1" label="中文名称" prop="chineseName" :rules="[{required: true, message: '中文名称不能为空', trigger: 'blur'},{pattern: /^[\u4e00-\u9fa5]{*}$/, message: '必须是汉字', trigger: 'blur'}]">
<el-input v-model="state.menuForm.chineseName" placeholder="请输入中文名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="英文名称" prop="englishName" :rules="[{required: true, message: '英文名称不能为空', trigger: 'blur'},{pattern: /^[A-Za-z0-9]+$/, message: '必须是字母', trigger: 'blur'}]">
<el-input v-model="state.menuForm.englishName" placeholder="请输入英文名称" autocomplete="off" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 2" label="菜单名称" prop="chineseName" :rules="[{required: true, message: '请输入名称', trigger: 'blur'}]">
<el-input v-model="state.menuForm.chineseName" placeholder="请输入名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 2" label="权限标识" prop="permission" :rules="[{required: true, message: '请输入权限标识', trigger: 'blur'}]">
<el-input v-model="state.menuForm.permission" placeholder="请输入权限标识" style="width:50%"></el-input>
</el-form-item>
<el-form-item label="菜单顺序" prop="sort" :rules="[{required: true, message: '菜单顺序不能为空', trigger: 'blur'}]">
<el-input-number v-model="state.menuForm.sort" :min="0" :max="999" style="width:50%"></el-input-number>
</el-form-item>
<el-form-item v-if="state.type == 1" label="组件类型" prop="componentType" :rules="[{required: true, message: '请选择组件类型', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.componentType">
<el-radio :value="0">默认</el-radio>
<el-radio :value="1">amis</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.type == 1" label="组件名称" prop="component">
<el-input v-model="state.menuForm.component" placeholder="请输入组件名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单类型" prop="openMode" :rules="[{required: true, message: '请选择类型', trigger: 'change'}]">
<el-select v-model="state.menuForm.openMode" placeholder="请选菜单类型" style="width:50%">
<el-option label="菜单" :value="0"></el-option>
<el-option label="Iframe" :value="1"></el-option>
<el-option label="新标签页" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="state.type == 1" label="是否缓存" prop="keepAlive" :rules="[{required: true, message: '请选择是否缓存', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.keepAlive">
<el-radio :value="1">缓存</el-radio>
<el-radio :value="0">不缓存</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.type == 1" label="是否显示" prop="isShow" :rules="[{required: true, message: '请选择是否显示', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.isShow">
<el-radio :value="1">显示</el-radio>
<el-radio :value="0">不显示</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="state.menuForm.remarks" type="textarea" :rows="2" placeholder="请输入备注" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-show="state.operate != 0 && state.operate != 3">
<el-button type="primary" @click="onSubmit(menuFormRef)"></el-button>
</el-form-item>
</el-form>
</div>
</template>
</el-tree>
</el-scrollbar>
</div>
<div class="menu-form">
<el-radio-group @change="onTypeChange" v-model="state.type">
<el-radio-button :value="1">菜单</el-radio-button>
<el-radio-button :value="2">按钮</el-radio-button>
</el-radio-group>
<el-divider direction="vertical" style="margin: 0 1rem;"/>
<el-radio-group @change="onOperateChange" v-model="state.operate">
<el-radio-button v-permission="'menu:save'" :value="1"></el-radio-button>
<el-radio-button v-permission="'menu:update'" :value="2"></el-radio-button>
<el-radio-button v-permission="'menu:delete'" :value="3"></el-radio-button>
</el-radio-group>
<el-divider content-position="left">菜单详情</el-divider>
<el-form :model="state.menuForm" ref="menuFormRef" :disabled="state.operate===0 || state.operate===3"
label-position="right" label-width="150px">
<el-form-item v-if="state.type == 1" label="父级菜单" prop="parentId"
:rules="[{required: true, message: '父级不能为空', trigger: 'blur'}]">
<el-tree-select v-model="state.menuForm.parentId" :data="state.treeList"
:props="{children: 'children', label: 'chineseName'}" node-key="id"
check-strictly :render-after-expand="false" :default-checked-keys="[state.menuForm.parentId]"
:default-expanded-keys="[state.menuForm.parentId]" placeholder="请选父级菜单"
style="width:50%"/>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单名称" prop="name"
:rules="[{required: true, message: '名称不能为空', trigger: 'blur'},{pattern: /^[A-Za-z0-9]+$/, message: '必须是字母', trigger: 'blur'}]">
<el-input v-model="state.menuForm.name" placeholder="请输入名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单路由" prop="url"
:rules="[{required: true, message: '路由不能为空', trigger: 'blur'}]">
<el-input v-model="state.menuForm.url" placeholder="请输入路由" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单图标" prop="icon"
:rules="[{required: true, message: '菜单图标不能为空', trigger: 'blur'}]">
<el-input v-model="state.menuForm.icon" @click="onFormIcon" readonly suffix-icon="Platform"
style="width:50%"></el-input>
<ElIcon v-model:visible="state.iconVisible" @onIcon="onIcon"/>
</el-form-item>
<el-form-item v-if="state.type == 1" label="中文名称" prop="chineseName"
:rules="[{required: true, message: '中文名称不能为空', trigger: 'blur'}]">
<el-input v-model="state.menuForm.chineseName" placeholder="请输入中文名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="英文名称" prop="englishName"
:rules="[{required: true, message: '英文名称不能为空', trigger: 'blur'},{pattern: /^[A-Za-z0-9]+$/, message: '必须是字母', trigger: 'blur'}]">
<el-input v-model="state.menuForm.englishName" placeholder="请输入英文名称" autocomplete="off"
style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 2" label="菜单名称" prop="chineseName"
:rules="[{required: true, message: '请输入名称', trigger: 'blur'}]">
<el-input v-model="state.menuForm.chineseName" placeholder="请输入名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 2" label="权限标识" prop="permission"
:rules="[{required: true, message: '请输入权限标识', trigger: 'blur'}]">
<el-input v-model="state.menuForm.permission" placeholder="请输入权限标识" style="width:50%"></el-input>
</el-form-item>
<el-form-item label="菜单顺序" prop="sort"
:rules="[{required: true, message: '菜单顺序不能为空', trigger: 'blur'}]">
<el-input-number v-model="state.menuForm.sort" :min="0" :max="999" style="width:50%"></el-input-number>
</el-form-item>
<el-form-item v-if="state.type == 1" label="组件类型" prop="componentType"
:rules="[{required: true, message: '请选择组件类型', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.componentType">
<el-radio :value="0">默认</el-radio>
<el-radio :value="1">amis</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.type == 1" label="组件名称" prop="component">
<el-input v-model="state.menuForm.component" placeholder="请输入组件名称" style="width:50%"></el-input>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单类型" prop="openMode"
:rules="[{required: true, message: '请选择类型', trigger: 'change'}]">
<el-select v-model="state.menuForm.openMode" placeholder="请选菜单类型" style="width:50%">
<el-option label="菜单" :value="0"></el-option>
<el-option label="Iframe" :value="1"></el-option>
<el-option label="新标签页" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="state.type == 1" label="是否缓存" prop="keepAlive"
:rules="[{required: true, message: '请选择是否缓存', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.keepAlive">
<el-radio :value="1">缓存</el-radio>
<el-radio :value="0">不缓存</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="state.type == 1" label="是否显示" prop="isShow"
:rules="[{required: true, message: '请选择是否显示', trigger: 'change'}]">
<el-radio-group v-model="state.menuForm.isShow">
<el-radio :value="1">显示</el-radio>
<el-radio :value="0">不显示</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="state.menuForm.remarks" type="textarea" :rows="2" placeholder="请输入备注"
style="width:50%"></el-input>
</el-form-item>
<el-form-item v-show="state.operate != 0 && state.operate != 3">
<el-button type="primary" @click="onSubmit(menuFormRef)"></el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<style lang="scss">
.menu-container{
padding-bottom: 1.5rem;
display: flex;
.menu-tree{
border-right: 1px solid #e4e7ed;
margin: 0 4rem 0 1rem;
min-width: 12rem;
.el-tree-node:hover>.el-tree-node__content{
background-color: #fff !important;
color: var(--theme) !important;
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: #fff !important;
color: var(--theme) !important;
}
}
.menu-form{
width: 100%;
}
.menu-container {
padding-bottom: 1.5rem;
display: flex;
.menu-tree {
border-right: 1px solid #e4e7ed;
margin: 0 4rem 0 1rem;
min-width: 12rem;
.el-tree-node:hover > .el-tree-node__content {
background-color: #fff !important;
color: var(--theme) !important;
}
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
background-color: #fff !important;
color: var(--theme) !important;
}
}
.menu-form {
width: 100%;
}
}
</style>