V2.7.2版本发布 (#1853)

* feat: 自动化代码增加json导出和导入功能

* feat: 自动化代码前端可见分为Table和Form分别选中

* feature: 调整代码预览为左边栏模式的tabs。

* feat: 增加方法自动添加前端api

* feat: 自动化生成前端支持详情功能

* feat: 增加自动创建可控权限按钮功能

* fixed: 顶栏样式菜单样式细节bug修复

* fixed: 修改视频地址

* fixed: 自动获取表结构和数据库表列结构保持一致

* fixed: casbin 设置空权限无需调用 AddPolicies 方法 (#1850)

* feat:对象存储支持配置Cloudflare R2 (#1849)

* fixed:设为首页和菜单勾选互为必选

---------

Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: 千石 <CN_QianShi@hotmail.com>

* feat: 复杂数据类型的查询将不会生成查询语句,会以string形式接收参数,用户自行实现复杂查询逻辑。

* feat: 创建新角色默认携带字典和长传权限。
禁止删除有首页占用的菜单。
不允许切换至无首页的角色。
自动化代码创建失败将返回错误信息。

* feat: 当package或plugin结构异常时候,阻止创建自动化代码。

---------

Co-authored-by: krank <emosick@qq.com>
Co-authored-by: SliverHorn <503551462@qq.com>
Co-authored-by: 千石 <CN_QianShi@hotmail.com>
This commit is contained in:
PiexlMax(奇淼
2024-08-13 21:55:27 +08:00
committed by GitHub
co-authored by krank SliverHorn 千石
parent 3b5c96d7cb
commit c9477d37fa
40 changed files with 621 additions and 202 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gin-vue-admin",
"version": "2.7.1",
"version": "2.7.2",
"private": true,
"scripts": {
"serve": "node openDocument.js && vite --host --mode development",
+1 -1
View File
@@ -20,7 +20,7 @@ export const viteLogo = (env) => {
)
console.log(
chalk.green(
`> 当前版本:v2.7.1`
`> 当前版本:v2.7.2`
)
)
console.log(
+1 -1
View File
@@ -10,7 +10,7 @@ export default {
register(app)
console.log(`
欢迎使用 Gin-Vue-Admin
当前版本:v2.7.1
当前版本:v2.7.2
加群方式:微信:shouzi_1994 QQ群:622360840
项目地址:https://github.com/flipped-aurora/gin-vue-admin
插件市场:https://plugin.gin-vue-admin.com
+4
View File
@@ -124,6 +124,10 @@
justify-content: center;
}
.el-menu--horizontal .el-menu .el-sub-menu__title{
justify-content: flex-start;
}
html.dark {
/* 自定义深色背景颜色 */
--el-bg-color: rgb(30 ,41 ,59);
@@ -61,7 +61,7 @@ const sideHeight = computed(() => {
<style lang="scss">
.gva-sub-menu{
.el-sub-menu__title{
height: v-bind('sideHeight');
height: v-bind('sideHeight') !important;
}
}
</style>
@@ -1,10 +1,10 @@
<template>
<div class="h-full">
<div v-if="mode==='head'" class="bg-white text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-full overflow-auto">
<div v-if="mode==='head'" class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto">
<el-menu
:default-active="routerStore.topActive"
mode="horizontal"
class="border-r-0 border-b-0 w-[calc(100%-100px)] flex gap-1 items-center box-border h-[calc(100%-1px)]"
class="border-r-0 border-b-0 w-full flex gap-1 items-center box-border h-[calc(100%-1px)]"
unique-opened
@select="(index, _, ele)=>selectMenuItem(index, _, ele,true)"
>
@@ -85,7 +85,6 @@ const router = useRouter();
const routerStore = useRouterStore();
const isCollapse = ref(false);
const active = ref("");
const topActive = ref("");
const layoutSideWidth = computed(() => {
if (!isCollapse.value) {
return config.value.layout_side_width;
+2 -2
View File
@@ -1,9 +1,9 @@
<template>
<div class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-full overflow-auto">
<div class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto">
<el-menu
:default-active="active"
mode="horizontal"
class="border-r-0 w-[calc(100%-100px)] flex gap-1 items-center box-border h-[calc(100%-1px)]"
class="border-r-0 w-full flex gap-1 items-center box-border h-[calc(100%-1px)]"
unique-opened
@select="selectMenuItem"
>
+1 -1
View File
@@ -8,7 +8,7 @@
<div
class="flex items-center cursor-pointer flex-1"
>
<div class="flex items-center cursor-pointer" @click="router.push({ path: '/' })">
<div class="flex items-center cursor-pointer min-w-48" @click="router.push({ path: '/' })">
<img
alt
class="h-12 bg-white rounded-full"
+1 -1
View File
@@ -175,7 +175,7 @@ const videoList = [
},
{
title:"11.菜单参数实战+动态菜单标题+菜单高亮配置",
link:"https://www.bilibili.com/video/BV1Bb421J7oW",
link:"https://www.bilibili.com/video/BV1NE4m1979c",
},
{
title:"12.增加菜单可控按钮",
@@ -29,13 +29,11 @@
<template #default="{ node , data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<span v-if="node.checked">
<el-button
type="primary"
link
:style="{color:row.defaultRouter === data.name?'#E6A23C':'#85ce61'}"
:disabled="!node.checked"
@click="() => setDefault(data)"
>
{{ row.defaultRouter === data.name?"首页":"设为首页" }}
@@ -45,7 +43,6 @@
<el-button
type="primary"
link
@click="() => OpenBtn(data)"
>
分配按钮
@@ -124,6 +121,9 @@ const menuDefaultProps = ref({
children: 'children',
label: function(data) {
return data.meta.title
},
disabled: function(data) {
return props.row.defaultRouter === data.name
}
})
@@ -141,6 +141,7 @@ const init = async() => {
}
})
menuTreeIds.value = arr
}
init()
@@ -2,7 +2,7 @@
<div>
<warning-bar title="id , created_at , updated_at , deleted_at 会自动生成请勿重复创建。搜索时如果条件为LIKE只支持字符串" />
<el-form
ref="fieldDialogFrom"
ref="fieldDialogForm"
:model="middleDate"
label-width="120px"
label-position="right"
@@ -158,8 +158,14 @@
/>
</el-select>
</el-form-item>
<el-form-item label="前端可见">
<el-switch v-model="middleDate.front" />
<el-form-item label="前端新建/编辑">
<el-switch v-model="middleDate.form" />
</el-form-item>
<el-form-item label="前端表格列">
<el-switch v-model="middleDate.table" />
</el-form-item>
<el-form-item label="前端详情">
<el-switch v-model="middleDate.desc" />
</el-form-item>
<el-form-item label="是否排序">
<el-switch v-model="middleDate.sort" />
@@ -432,6 +438,6 @@ const selectDB = async (val) => {
}
const fieldDialogFrom = ref(null)
defineExpose({ fieldDialogFrom })
const fieldDialogForm = ref(null)
defineExpose({ fieldDialogForm })
</script>
@@ -1,5 +1,5 @@
<template>
<el-tabs v-model="activeName">
<el-tabs v-model="activeName" tab-position="left" class="h-[calc(100vh-110px)]">
<el-tab-pane
v-for="(item, key) in previewCode"
:key="key"
@@ -8,7 +8,7 @@
>
<div
:id="key"
class="h-[calc(100vh-160px)] bg-white px-5 overflow-y-scroll"
class="h-[calc(100vh-110px)] bg-white px-5 overflow-y-scroll"
/>
</el-tab-pane>
</el-tabs>
+101 -9
View File
@@ -358,6 +358,20 @@
<el-checkbox v-model="form.autoMigrate" />
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item>
<template #label>
<el-tooltip
content="注:会自动产生页面内的按钮权限配置,若不在角色管理中进行按钮分配则按钮不可见"
placement="bottom"
effect="light"
>
<div> 创建按钮权限 <el-icon><QuestionFilled /></el-icon> </div>
</el-tooltip>
</template>
<el-checkbox v-model="form.autoCreateBtnAuth" />
</el-form-item>
</el-col>
<el-col :span="3">
<el-form-item>
<template #label>
@@ -467,11 +481,30 @@
</el-table-column>
<el-table-column
align="left"
prop="front"
label="前端可见"
prop="form"
width="100"
label="新建/编辑"
>
<template #default="{row}">
<el-checkbox v-model="row.front" />
<el-checkbox v-model="row.form" />
</template>
</el-table-column>
<el-table-column
align="left"
prop="table"
label="表格"
>
<template #default="{row}">
<el-checkbox v-model="row.table" />
</template>
</el-table-column>
<el-table-column
align="left"
prop="desc"
label="详情"
>
<template #default="{row}">
<el-checkbox v-model="row.desc" />
</template>
</el-table-column>
<el-table-column
@@ -615,6 +648,20 @@
</div>
<!-- 组件列表 -->
<div class="gva-btn-list justify-end mt-4">
<el-button
type="primary"
@click="exportJson()"
>
导出json
</el-button>
<el-upload
class="flex items-center"
:before-upload="importJson"
show-file-list="false"
accept=".json"
>
<el-button type="primary" class="mx-2">导入json</el-button>
</el-upload>
<el-button
type="primary"
@click="clearCatch()"
@@ -676,7 +723,7 @@
<el-drawer
v-model="previewFlag"
size="60%"
size="80%"
:show-close="false"
>
<template #header>
@@ -758,9 +805,11 @@ const llmAutoFunc = async (mode) =>{
fieldSearchType: '',
fieldIndexType: '',
dictType: '',
front: true,
form: true,
desc: true,
table: true,
dataSource: {
association:1,
association:1,
table: '',
label: '',
value: ''
@@ -912,7 +961,9 @@ const fieldTemplate = {
defaultValue: '',
require: false,
sort: false,
front: true,
form: true,
desc: true,
table: true,
errorText: '',
primaryKey: false,
clearable: true,
@@ -947,6 +998,7 @@ const form = ref({
businessDB: '',
autoCreateApiToSql: true,
autoCreateMenuToSql: true,
autoCreateBtnAuth: false,
autoMigrate: true,
gvaModel: true,
autoCreateResource: false,
@@ -1031,7 +1083,7 @@ const editAndAddField = (item) => {
const fieldDialogNode = ref(null)
const enterDialog = () => {
fieldDialogNode.value.fieldDialogFrom.validate(valid => {
fieldDialogNode.value.fieldDialogForm.validate(valid => {
if (valid) {
dialogMiddle.value.fieldName = toUpperCase(
dialogMiddle.value.fieldName
@@ -1096,6 +1148,15 @@ const enterForm = async(isPreview) => {
return false
}
if (form.value.fields.some(item => !item.fieldType)) {
ElMessage({
type: 'error',
message: '请填写所有字段类型后进行提交'
})
return false
}
autoCodeForm.value.validate(async valid => {
if (valid) {
for (const key in form.value) {
@@ -1195,7 +1256,9 @@ const getColumnFunc = async() => {
fieldSearchType: '',
fieldIndexType: '',
dictType: '',
front: true,
form: true,
table: true,
desc: true,
dataSource: {
association:1,
table: '',
@@ -1287,6 +1350,7 @@ const clearCatch = async () => {
businessDB: '',
autoCreateApiToSql: true,
autoCreateMenuToSql: true,
autoCreateBtnAuth: false,
autoMigrate: true,
gvaModel: true,
autoCreateResource: false,
@@ -1298,4 +1362,32 @@ const clearCatch = async () => {
getCatch()
const exportJson = () => {
const dataStr = JSON.stringify(form.value, null, 2)
const blob = new Blob([dataStr], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'form_data.json'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
const importJson = (file) =>{
const reader = new FileReader()
reader.onload = (e) => {
console.log(e)
try {
form.value = JSON.parse(e.target.result)
ElMessage.success('JSON 文件导入成功')
} catch (error) {
ElMessage.error('无效的 JSON 文件')
}
}
reader.readAsText(file)
return false
}
</script>