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:
co-authored by
krank
SliverHorn
千石
parent
3b5c96d7cb
commit
c9477d37fa
+1
-1
@@ -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",
|
||||
|
||||
@@ -20,7 +20,7 @@ export const viteLogo = (env) => {
|
||||
)
|
||||
console.log(
|
||||
chalk.green(
|
||||
`> 当前版本:v2.7.1`
|
||||
`> 当前版本:v2.7.2`
|
||||
)
|
||||
)
|
||||
console.log(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user