Dev273 (#1868)
* fixed: 修复addFunction下前端api.js无法创建的bug。 * feature: 增加严格角色模式 * Update system.vue * fixed: 多点登录拦截模式下,jwt换票期间不需要拉黑token。 * fixed: 修复使用ast时候产生无意义的换行的问题 * fixed: 修复跨级操作角色权限的越权问题 * feature: 优化严格模式角色鉴权操作。 * fixed: 增加菜单和api设置越权问题的限制 * feature: 增加插件打包前的自动化同步所需菜单和api的功能 * feature: 自动化代码可以默认生成导入导出 * feature: 自动化导入导出对模板进行回滚 * feature: 剔除无用的packfile代码包 * feature: 发布V2.7.3版本公测。 --------- Co-authored-by: task <ms.yangdan@gmail.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gin-vue-admin",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "node openDocument.js && vite --host --mode development",
|
||||
@@ -19,6 +19,7 @@
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.4.0",
|
||||
"core-js": "^3.31.1",
|
||||
"default-passive-events": "^2.0.0",
|
||||
"echarts": "5.4.3",
|
||||
"element-plus": "^2.7.4",
|
||||
"highlight.js": "^11.8.0",
|
||||
|
@@ -166,3 +166,22 @@ export const addFunc = (data) => {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const initMenu = (data) => {
|
||||
return service({
|
||||
url: '/autoCode/initMenu',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const initAPI = (data) => {
|
||||
return service({
|
||||
url: '/autoCode/initAPI',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -40,3 +40,17 @@ export const getSystemState = () => {
|
||||
donNotShowLoading: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启服务
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
export const reloadSystem = (data) => {
|
||||
return service({
|
||||
url: '/system/reloadSystem',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
68
web/src/components/arrayCtrl/arrayCtrl.vue
Normal file
68
web/src/components/arrayCtrl/arrayCtrl.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<el-tag
|
||||
v-for="tag in modelValue"
|
||||
:key="tag"
|
||||
:closable="editable"
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
<template v-if="editable">
|
||||
<el-input
|
||||
v-if="inputVisible"
|
||||
ref="InputRef"
|
||||
v-model="inputValue"
|
||||
class="w-20"
|
||||
size="small"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
<el-button v-else class="button-new-tag" size="small" @click="showInput">
|
||||
+ 新增
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
defineOptions({
|
||||
name: 'ArrayCtrl',
|
||||
})
|
||||
|
||||
import { nextTick, ref } from 'vue'
|
||||
|
||||
const inputValue = ref('')
|
||||
const inputVisible = ref(false)
|
||||
const InputRef = ref(null)
|
||||
|
||||
const modelValue = defineModel()
|
||||
|
||||
defineProps({
|
||||
editable: {
|
||||
type: Boolean,
|
||||
default: () => false
|
||||
}
|
||||
})
|
||||
|
||||
const handleClose = (tag) => {
|
||||
modelValue.value.splice(modelValue.value.indexOf(tag), 1)
|
||||
}
|
||||
|
||||
const showInput = () => {
|
||||
inputVisible.value = true
|
||||
nextTick(() => {
|
||||
InputRef.value?.input?.focus()
|
||||
})
|
||||
}
|
||||
|
||||
const handleInputConfirm = () => {
|
||||
if (inputValue.value) {
|
||||
modelValue.value.push(inputValue.value)
|
||||
}
|
||||
inputVisible.value = false
|
||||
inputValue.value = ''
|
||||
}
|
||||
</script>
|
@@ -15,9 +15,7 @@
|
||||
|
||||
<script setup>
|
||||
import ImageCompress from '@/utils/image'
|
||||
import { ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useUserStore } from '@/pinia/modules/user'
|
||||
import { getBaseUrl } from '@/utils/format'
|
||||
|
||||
defineOptions({
|
||||
@@ -40,10 +38,6 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const path = ref(import.meta.env.VITE_BASE_API)
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const beforeImageUpload = (file) => {
|
||||
const isJPG = file.type === 'image/jpeg'
|
||||
const isPng = file.type === 'image/png'
|
||||
|
@@ -20,7 +20,7 @@ export const viteLogo = (env) => {
|
||||
)
|
||||
console.log(
|
||||
chalk.green(
|
||||
`> 当前版本:v2.7.2`
|
||||
`> 当前版本:v2.7.3`
|
||||
)
|
||||
)
|
||||
console.log(
|
||||
|
@@ -10,7 +10,7 @@ export default {
|
||||
register(app)
|
||||
console.log(`
|
||||
欢迎使用 Gin-Vue-Admin
|
||||
当前版本:v2.7.2
|
||||
当前版本:v2.7.3
|
||||
加群方式:微信:shouzi_1994 QQ群:622360840
|
||||
项目地址:https://github.com/flipped-aurora/gin-vue-admin
|
||||
插件市场:https://plugin.gin-vue-admin.com
|
||||
|
@@ -15,6 +15,8 @@ import run from '@/core/gin-vue-admin.js'
|
||||
import auth from '@/directive/auth'
|
||||
import { store } from '@/pinia'
|
||||
import App from './App.vue'
|
||||
//消除警告
|
||||
import 'default-passive-events'
|
||||
|
||||
const app = createApp(App)
|
||||
app.config.productionTip = false
|
||||
|
@@ -231,20 +231,13 @@ const rules = ref({
|
||||
]
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(999)
|
||||
const tableData = ref([])
|
||||
const searchInfo = ref({})
|
||||
|
||||
// 查询
|
||||
const getTableData = async() => {
|
||||
const table = await getAuthorityList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value })
|
||||
const table = await getAuthorityList()
|
||||
if (table.code === 0) {
|
||||
tableData.value = table.data.list
|
||||
total.value = table.data.total
|
||||
page.value = table.data.page
|
||||
pageSize.value = table.data.pageSize
|
||||
tableData.value = table.data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,9 +287,7 @@ const deleteAuth = (row) => {
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
if (tableData.value.length === 1 && page.value > 1) {
|
||||
page.value--
|
||||
}
|
||||
|
||||
getTableData()
|
||||
}
|
||||
})
|
||||
|
@@ -131,6 +131,7 @@ const authDataEnter = async() => {
|
||||
|
||||
// 选择
|
||||
const selectAuthority = () => {
|
||||
dataAuthorityId.value = dataAuthorityId.value.filter(item => item)
|
||||
emit('changeRow', 'dataAuthorityId', dataAuthorityId.value)
|
||||
needConfirm.value = true
|
||||
}
|
||||
|
@@ -585,23 +585,12 @@ const rules = reactive({
|
||||
],
|
||||
})
|
||||
|
||||
const page = ref(1)
|
||||
const total = ref(0)
|
||||
const pageSize = ref(999)
|
||||
const tableData = ref([])
|
||||
const searchInfo = ref({})
|
||||
// 查询
|
||||
const getTableData = async() => {
|
||||
const table = await getMenuList({
|
||||
page: page.value,
|
||||
pageSize: pageSize.value,
|
||||
...searchInfo.value,
|
||||
})
|
||||
const table = await getMenuList()
|
||||
if (table.code === 0) {
|
||||
tableData.value = table.data.list
|
||||
total.value = table.data.total
|
||||
page.value = table.data.page
|
||||
pageSize.value = table.data.pageSize
|
||||
tableData.value = table.data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,9 +682,7 @@ const deleteMenu = (ID) => {
|
||||
type: 'success',
|
||||
message: '删除成功!',
|
||||
})
|
||||
if (tableData.value.length === 1 && page.value > 1) {
|
||||
page.value--
|
||||
}
|
||||
|
||||
getTableData()
|
||||
}
|
||||
})
|
||||
|
@@ -301,8 +301,8 @@ watch(() => tableData.value, () => {
|
||||
|
||||
const initPage = async() => {
|
||||
getTableData()
|
||||
const res = await getAuthorityList({ page: 1, pageSize: 999 })
|
||||
setOptions(res.data.list)
|
||||
const res = await getAuthorityList()
|
||||
setOptions(res.data)
|
||||
}
|
||||
|
||||
initPage()
|
||||
|
@@ -167,6 +167,9 @@
|
||||
<el-form-item label="前端详情">
|
||||
<el-switch v-model="middleDate.desc" />
|
||||
</el-form-item>
|
||||
<el-form-item label="导入/导出">
|
||||
<el-switch v-model="middleDate.excel" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否排序">
|
||||
<el-switch v-model="middleDate.sort" />
|
||||
</el-form-item>
|
||||
|
@@ -507,6 +507,15 @@
|
||||
<el-checkbox v-model="row.desc" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="left"
|
||||
prop="excel"
|
||||
label="导入/导出"
|
||||
>
|
||||
<template #default="{row}">
|
||||
<el-checkbox v-model="row.excel" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
align="left"
|
||||
prop="fieldJson"
|
||||
@@ -808,6 +817,7 @@ const llmAutoFunc = async (mode) =>{
|
||||
form: true,
|
||||
desc: true,
|
||||
table: true,
|
||||
excel: false,
|
||||
dataSource: {
|
||||
association:1,
|
||||
table: '',
|
||||
@@ -964,6 +974,7 @@ const fieldTemplate = {
|
||||
form: true,
|
||||
desc: true,
|
||||
table: true,
|
||||
excel: false,
|
||||
errorText: '',
|
||||
primaryKey: false,
|
||||
clearable: true,
|
||||
@@ -1258,6 +1269,7 @@ const getColumnFunc = async() => {
|
||||
dictType: '',
|
||||
form: true,
|
||||
table: true,
|
||||
excel: false,
|
||||
desc: true,
|
||||
dataSource: {
|
||||
association:1,
|
||||
|
@@ -4,32 +4,231 @@
|
||||
<WarningBar title="目前只支持标准插件(通过插件模板生成的标准目录插件),非标准插件请自行打包" />
|
||||
<div class="flex items-center gap-3">
|
||||
<el-input
|
||||
v-model="plugName"
|
||||
placeholder="插件模板处填写的【插件名】"
|
||||
v-model="plugName"
|
||||
placeholder="插件模板处填写的【插件名】"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="pubPlugin"
|
||||
>打包插件</el-button>
|
||||
</div>
|
||||
<el-card class="mt-2 text-center">
|
||||
<WarningBar title="穿梭框请只选择子级菜单即可" />
|
||||
<el-input v-model="parentMenu" placeholder="请输入菜单组名,例:公告管理" class="mb-2"></el-input>
|
||||
<el-transfer
|
||||
v-model="menus"
|
||||
:props="{
|
||||
key: 'ID',
|
||||
}"
|
||||
class="plugin-transfer"
|
||||
:data="menusData"
|
||||
filterable
|
||||
:filter-method="filterMenuMethod"
|
||||
filter-placeholder="请输入菜单名称/路径"
|
||||
:titles="['可选菜单','使用菜单']"
|
||||
:button-texts="['移除', '选中']"
|
||||
>
|
||||
<template #default="{option}">
|
||||
{{ option.meta.title }} {{ option.component }}
|
||||
</template>
|
||||
</el-transfer>
|
||||
<div class="flex justify-end mt-2">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="fmtInitMenu"
|
||||
>
|
||||
定义安装菜单
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card class="mt-2 text-center">
|
||||
<el-transfer
|
||||
v-model="apis"
|
||||
:props="{
|
||||
key: 'ID',
|
||||
}"
|
||||
class="plugin-transfer"
|
||||
:data="apisData"
|
||||
filterable
|
||||
:filter-method="filterApiMethod"
|
||||
filter-placeholder="请输入API描述/PATH"
|
||||
:titles="['可选API','使用API']"
|
||||
:button-texts="['移除', '选中']"
|
||||
>
|
||||
<template #default="{option}">
|
||||
{{ option.description }} {{ option.path }}
|
||||
</template>
|
||||
</el-transfer>
|
||||
<div class="flex justify-end mt-2">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="fmtInitAPI"
|
||||
>
|
||||
定义安装API
|
||||
</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="pubPlugin"
|
||||
>
|
||||
打包插件
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||
import { pubPlug } from '@/api/autoCode.js'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { pubPlug,initMenu,initAPI } from '@/api/autoCode.js'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import {getAllApis} from "@/api/api";
|
||||
import {getMenuList} from "@/api/menu";
|
||||
|
||||
const plugName = ref('')
|
||||
|
||||
const pubPlugin = async() => {
|
||||
const res = await pubPlug({ plugName: plugName.value })
|
||||
if (res.code === 0) {
|
||||
ElMessage.success(res.msg)
|
||||
const menus = ref([])
|
||||
const menusData = ref([])
|
||||
const apis = ref([])
|
||||
const apisData = ref([])
|
||||
const parentMenu = ref('')
|
||||
|
||||
const fmtMenu = (menus) => {
|
||||
// 如果menu存在children,递归展开到一级
|
||||
const res = []
|
||||
menus.forEach(item => {
|
||||
if (item.children) {
|
||||
res.push(...fmtMenu(item.children))
|
||||
} else {
|
||||
res.push(item)
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
const initData = async() => {
|
||||
const menuRes = await getMenuList()
|
||||
if (menuRes.code === 0) {
|
||||
menusData.value = fmtMenu(menuRes.data)
|
||||
}
|
||||
const apiRes = await getAllApis()
|
||||
if (apiRes.code === 0) {
|
||||
apisData.value = apiRes.data.apis
|
||||
}
|
||||
}
|
||||
|
||||
const filterMenuMethod = (query, item) => {
|
||||
return item.meta.title.indexOf(query) > -1 || item.component.indexOf(query) > -1
|
||||
}
|
||||
|
||||
const filterApiMethod = (query, item) => {
|
||||
return item.description.indexOf(query) > -1 || item.path.indexOf(query) > -1
|
||||
}
|
||||
|
||||
initData()
|
||||
|
||||
const pubPlugin = async() => {
|
||||
|
||||
ElMessageBox.confirm(
|
||||
`请检查server下的/plugin/${plugName.value}/plugin.go是否已放开需要的 initialize.Api(ctx) 和 initialize.Menu(ctx)?`,
|
||||
'打包',
|
||||
{
|
||||
confirmButtonText: '打包',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
const res = await pubPlug({ plugName: plugName.value })
|
||||
if (res.code === 0) {
|
||||
ElMessage.success(res.msg)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '关闭打包',
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
const fmtInitMenu = () => {
|
||||
if (!parentMenu.value) {
|
||||
ElMessage.error('请填写菜单组名')
|
||||
return
|
||||
}
|
||||
if (menus.value.length === 0) {
|
||||
ElMessage.error('请至少选择一个菜单')
|
||||
return
|
||||
}
|
||||
if (plugName.value === '') {
|
||||
ElMessage.error('请填写插件名')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(
|
||||
`点击后将会覆盖server下的/plugin/${plugName.value}/initialize/menu. 是否继续?`,
|
||||
'生成初始菜单',
|
||||
{
|
||||
confirmButtonText: '生成',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
const req = {
|
||||
plugName: plugName.value,
|
||||
parentMenu: parentMenu.value,
|
||||
menus: menus.value
|
||||
}
|
||||
initMenu(req)
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '关闭生成菜单',
|
||||
})
|
||||
})
|
||||
}
|
||||
const fmtInitAPI = () => {
|
||||
if (apis.value.length === 0) {
|
||||
ElMessage.error('请至少选择一个API')
|
||||
return
|
||||
}
|
||||
if (plugName.value === '') {
|
||||
ElMessage.error('请填写插件名')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(
|
||||
`点击后将会覆盖server下的/plugin/${plugName.value}/initialize/api. 是否继续?`,
|
||||
'生成初始API',
|
||||
{
|
||||
confirmButtonText: '生成',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
const req = {
|
||||
plugName: plugName.value,
|
||||
apis: apis.value
|
||||
}
|
||||
initAPI(req)
|
||||
console.log(req)
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '关闭生成API',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.plugin-transfer{
|
||||
.el-transfer-panel{
|
||||
width: 400px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user