初始化项目

This commit is contained in:
2023-01-10 11:52:47 +08:00
parent c74db0d2b9
commit 2180adecb0
142 changed files with 16480 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
<template>
<div>
<warning-bar title="id , created_at , updated_at , deleted_at 会自动生成请勿重复创建。搜索时如果条件为LIKE只支持字符串" />
<el-form
ref="fieldDialogFrom"
:model="middleDate"
label-width="120px"
label-position="right"
:rules="rules"
class="grid-form"
>
<el-form-item label="Field名称" prop="fieldName">
<el-input v-model="middleDate.fieldName" autocomplete="off" style="width:80%" />
<el-button size="small" style="width:18%;margin-left:2%" @click="autoFill">
<span style="font-size: 12px">自动填充</span>
</el-button>
</el-form-item>
<el-form-item label="Field中文名" prop="fieldDesc">
<el-input v-model="middleDate.fieldDesc" autocomplete="off" />
</el-form-item>
<el-form-item label="FieldJSON" prop="fieldJson">
<el-input v-model="middleDate.fieldJson" autocomplete="off" />
</el-form-item>
<el-form-item label="数据库字段名" prop="columnName">
<el-input v-model="middleDate.columnName" autocomplete="off" />
</el-form-item>
<el-form-item label="数据库字段描述" prop="comment">
<el-input v-model="middleDate.comment" autocomplete="off" />
</el-form-item>
<el-form-item label="Field数据类型" prop="fieldType">
<el-select
v-model="middleDate.fieldType"
style="width:100%"
placeholder="请选择field数据类型"
clearable
@change="clearOther"
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="middleDate.fieldType === 'enum' ? '枚举值' : '类型长度'" prop="dataTypeLong">
<el-input v-model="middleDate.dataTypeLong" :placeholder="middleDate.fieldType === 'enum'?`例:'北京','天津'`:'数据库类型长度'" />
</el-form-item>
<el-form-item label="Field查询条件" prop="fieldSearchType">
<el-select
v-model="middleDate.fieldSearchType"
style="width:100%"
placeholder="请选择Field查询条件"
clearable
>
<el-option
v-for="item in typeSearchOptions"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="
(middleDate.fieldType!=='string'&&item.value==='LIKE')||
((middleDate.fieldType!=='int'&&middleDate.fieldType!=='time.Time'&&middleDate.fieldType!=='float64')&&(item.value==='BETWEEN' || item.value==='NOT BETWEEN'))
"
/>
</el-select>
</el-form-item>
<el-form-item label="关联字典" prop="dictType">
<el-select
v-model="middleDate.dictType"
style="width:100%"
:disabled="middleDate.fieldType!=='int'"
placeholder="请选择字典"
clearable
>
<el-option
v-for="item in dictOptions"
:key="item.type"
:label="`${item.type}(${item.name})`"
:value="item.type"
/>
</el-select>
</el-form-item>
<el-form-item label="是否排序">
<el-switch v-model="middleDate.sort" />
</el-form-item>
<el-form-item label="是否必填">
<el-switch v-model="middleDate.require" />
</el-form-item>
<el-form-item label="是否可清空">
<el-switch v-model="middleDate.clearable" />
</el-form-item>
<el-form-item label="校验失败文案">
<el-input v-model="middleDate.errorText" />
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { toLowerCase, toSQLLine } from '@/utils/stringFun'
import { getSysDictionaryList } from '@/api/sysDictionary'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ref } from 'vue'
const props = defineProps({
dialogMiddle: {
type: Object,
default: function() {
return {}
}
}
})
const middleDate = ref({})
const dictOptions = ref([])
const typeSearchOptions = ref([
{
label: '=',
value: '='
},
{
label: '<>',
value: '<>'
},
{
label: '>',
value: '>'
},
{
label: '<',
value: '<'
},
{
label: 'LIKE',
value: 'LIKE'
},
{
label: 'BETWEEN',
value: 'BETWEEN'
},
{
label: 'NOT BETWEEN',
value: 'NOT BETWEEN'
}
])
const typeOptions = ref([
{
label: '字符串',
value: 'string'
},
{
label: '整型',
value: 'int'
},
{
label: '布尔值',
value: 'bool'
},
{
label: '浮点型',
value: 'float64'
},
{
label: '时间',
value: 'time.Time'
},
{
label: '枚举',
value: 'enum'
}
])
const rules = ref({
fieldName: [
{ required: true, message: '请输入field英文名', trigger: 'blur' }
],
fieldDesc: [
{ required: true, message: '请输入field中文名', trigger: 'blur' }
],
fieldJson: [
{ required: true, message: '请输入field格式化json', trigger: 'blur' }
],
columnName: [
{ required: true, message: '请输入数据库字段', trigger: 'blur' }
],
fieldType: [
{ required: true, message: '请选择field数据类型', trigger: 'blur' }
]
})
const init = async() => {
middleDate.value = props.dialogMiddle
const dictRes = await getSysDictionaryList({
page: 1,
pageSize: 999999
})
dictOptions.value = dictRes.data.list
}
init()
const autoFill = () => {
middleDate.value.fieldJson = toLowerCase(middleDate.value.fieldName)
middleDate.value.columnName = toSQLLine(middleDate.value.fieldJson)
}
const clearOther = () => {
middleDate.value.fieldSearchType = ''
middleDate.value.dictType = ''
}
const fieldDialogFrom = ref(null)
defineExpose({ fieldDialogFrom })
</script>
<script>
export default {
name: 'FieldDialog'
}
</script>
<style scoped>
.grid-form{
display: grid;
grid-template-columns: 1fr 1fr;
}
.click-text{
color: #0d84ff;
font-size: 13px;
cursor: pointer;
user-select: none;
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<div class="previewCode">
<el-tabs v-model="activeName">
<el-tab-pane v-for="(item, key) in previewCode" :key="key" :label="key" :name="key">
<div :id="key" class="tab-info" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import marked from 'marked'
import hljs from 'highlight.js'
import 'highlight.js/styles/atelier-plateau-light.css'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'
const props = defineProps({
previewCode: {
type: Object,
default() {
return {}
}
}
})
const activeName = ref('')
onMounted(() => {
marked.setOptions({
renderer: new marked.Renderer(),
highlight: function(code) {
return hljs.highlightAuto(code).value
},
pedantic: false,
gfm: true,
tables: true,
breaks: false,
sanitize: false,
smartLists: true,
smartypants: false,
xhtml: false
})
for (const key in props.previewCode) {
if (activeName.value === '') {
activeName.value = key
}
document.getElementById(key).innerHTML = marked(props.previewCode[key])
}
})
const selectText = () => {
const element = document.getElementById(activeName.value)
if (document.body.createTextRange) {
const range = document.body.createTextRange()
range.moveToElementText(element)
range.select()
} else if (window.getSelection) {
const selection = window.getSelection()
const range = document.createRange()
range.selectNodeContents(element)
selection.removeAllRanges()
selection.addRange(range)
} else {
alert('none')
}
}
const copy = () => {
selectText()
document.execCommand('copy')
ElMessage.success('复制成功')
}
defineExpose({ copy })
</script>
<script>
export default {
}
</script>
<style lang="scss">
.previewCode {
.tab-info {
height: 50vh;
background: #fff;
padding: 0 20px;
overflow-y: scroll;
}
}
</style>

View File

@@ -0,0 +1,723 @@
<template>
<div>
<warning-bar href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=3" title="此功能为开发环境使用不建议发布到生产具体使用效果请看视频https://www.bilibili.com/video/BV1kv4y1g7nT?p=3" />
<!-- 从数据库直接获取字段 -->
<div class="gva-search-box">
<el-collapse v-model="activeNames" style="margin-bottom:12px">
<el-collapse-item name="1">
<template #title>
<div :style="{fontSize:'16px',paddingLeft:'20px'}">
点这里从现有数据库创建代码
<el-icon class="header-icon ">
<pointer />
</el-icon>
</div>
</template>
<el-form ref="getTableForm" style="margin-top:24px" :inline="true" :model="dbform" label-width="120px">
<el-form-item label="业务库" prop="selectDBtype">
<template #label>
<el-tooltip content="注需要提前到db-list自行配置多数据库如未配置需配置后重启服务方可使用。此处可选择对应库表可理解为从哪个库选择表" placement="bottom" effect="light">
<div> 业务库 <el-icon><QuestionFilled /></el-icon> </div>
</el-tooltip>
</template>
<el-select v-model="dbform.businessDB" clearable style="width:194px" placeholder="选择业务库" @change="getDbFunc">
<el-option
v-for="item in dbList"
:key="item.aliasName"
:value="item.aliasName"
:label="item.aliasName"
:disabled="item.disable"
>
<div>
<span>{{ item.aliasName }}</span>
<span style="float:right;color:#8492a6;font-size:13px">{{ item.dbName }}</span>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="数据库名" prop="structName">
<el-select v-model="dbform.dbName" clearable filterable placeholder="请选择数据库" @change="getTableFunc">
<el-option
v-for="item in dbOptions"
:key="item.database"
:label="item.database"
:value="item.database"
/>
</el-select>
</el-form-item>
<el-form-item label="表名" prop="structName">
<el-select
v-model="dbform.tableName"
:disabled="!dbform.dbName"
filterable
placeholder="请选择表"
>
<el-option
v-for="item in tableOptions"
:key="item.tableName"
:label="item.tableName"
:value="item.tableName"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" @click="getColumnFunc">使用此表创建</el-button>
</el-form-item>
</el-form>
</el-collapse-item>
</el-collapse>
</div>
<div class="gva-search-box">
<!-- 初始版本自动化代码工具 -->
<el-form ref="autoCodeForm" :rules="rules" :model="form" label-width="120px" :inline="true">
<el-form-item label="Struct名称" prop="structName">
<el-input v-model="form.structName" placeholder="首字母自动转换大写" />
</el-form-item>
<el-form-item label="TableName" prop="tableName">
<el-input v-model="form.tableName" placeholder="指定表名(非必填)" />
</el-form-item>
<el-form-item label="Struct简称" prop="abbreviation">
<el-input v-model="form.abbreviation" placeholder="简称会作为入参对象名和路由group" />
</el-form-item>
<el-form-item label="Struct中文名称" prop="description">
<el-input v-model="form.description" placeholder="中文描述作为自动api描述" />
</el-form-item>
<el-form-item label="文件名称" prop="packageName">
<el-input v-model="form.packageName" placeholder="生成文件的默认名称(建议为驼峰格式,首字母小写,如sysXxxXxxx)" @blur="toLowerCaseFunc(form,'packageName')" />
</el-form-item>
<el-form-item label="Package" prop="package">
<el-select v-model="form.package" style="width:194px">
<el-option v-for="item in pkgs" :key="item.ID" :value="item.packageName" :label="item.packageName" />
</el-select>
<el-icon class="auto-icon" @click="getPkgs"><refresh /></el-icon>
<el-icon class="auto-icon" @click="goPkgs"><document-add /></el-icon>
</el-form-item>
<el-form-item label="业务库" prop="businessDB">
<template #label>
<el-tooltip content="注需要提前到db-list自行配置多数据库此项为空则会使用gva本库创建自动化代码(global.GVA_DB),填写后则会创建指定库的代码(global.MustGetGlobalDBByDBName(dbname))" placement="bottom" effect="light">
<div> 业务库 <el-icon><QuestionFilled /></el-icon> </div>
</el-tooltip>
</template>
<el-select
v-model="form.businessDB"
style="width:194px"
placeholder="选择业务库"
>
<el-option
v-for="item in dbList"
:key="item.aliasName"
:value="item.aliasName"
:label="item.aliasName"
:disabled="item.disable"
>
<div>
<span>{{ item.aliasName }}</span>
<span style="float:right;color:#8492a6;font-size:13px">{{ item.dbName }}</span>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<template #label>
<el-tooltip content="注:会自动在结构体添加 created_by updated_by deleted_by方便用户进行资源权限控制" placement="bottom" effect="light">
<div> 创建资源标识 <el-icon><QuestionFilled /></el-icon> </div>
</el-tooltip>
</template>
<el-checkbox v-model="form.autoCreateResource" />
</el-form-item>
<el-form-item>
<template #label>
<el-tooltip content="注把自动生成的API注册进数据库" placement="bottom" effect="light">
<div> 自动创建API </div>
</el-tooltip>
</template>
<el-checkbox v-model="form.autoCreateApiToSql" />
</el-form-item>
<el-form-item>
<template #label>
<el-tooltip content="注自动迁移生成的文件到yaml配置的对应位置" placement="bottom" effect="light">
<div> 自动移动文件 </div>
</el-tooltip>
</template>
<el-checkbox v-model="form.autoMoveFile" />
</el-form-item>
</el-form>
</div>
<!-- 组件列表 -->
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button size="small" type="primary" @click="editAndAddField()">新增Field</el-button>
</div>
<el-table :data="form.fields">
<el-table-column align="left" type="index" label="序列" width="60" />
<el-table-column align="left" prop="fieldName" label="Field名" width="160">
<template #default="{row}">
<el-input v-model="row.fieldName" />
</template>
</el-table-column>
<el-table-column align="left" prop="fieldDesc" label="中文名" width="160">
<template #default="{row}">
<el-input v-model="row.fieldDesc" />
</template>
</el-table-column>
<el-table-column align="left" prop="require" label="必填">
<template #default="{row}"> <el-checkbox v-model="row.require" /></template>
</el-table-column>
<el-table-column align="left" prop="sort" label="排序">
<template #default="{row}"> <el-checkbox v-model="row.sort" /> </template>
</el-table-column>
<el-table-column align="left" prop="fieldJson" width="160px" label="FieldJson">
<template #default="{row}">
<el-input v-model="row.fieldJson" />
</template>
</el-table-column>
<el-table-column align="left" prop="fieldType" label="Field数据类型" width="160">
<template #default="{row}">
<el-select
v-model="row.fieldType"
style="width:100%"
placeholder="请选择field数据类型"
clearable
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column align="left" prop="dataTypeLong" label="数据库字段长度" width="160">
<template #default="{row}">
<el-input v-model="row.dataTypeLong" />
</template>
</el-table-column>
<el-table-column align="left" prop="columnName" label="数据库字段" width="160">
<template #default="{row}">
<el-input v-model="row.columnName" />
</template>
</el-table-column>
<el-table-column align="left" prop="comment" label="数据库字段描述" width="160">
<template #default="{row}">
<el-input v-model="row.columnName" />
</template>
</el-table-column>
<el-table-column align="left" prop="fieldSearchType" label="搜索条件" width="130">
<template #default="{row}">
<el-select
v-model="row.fieldSearchType"
style="width:100%"
placeholder="请选择Field查询条件"
clearable
>
<el-option
v-for="item in typeSearchOptions"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="
(row.fieldType!=='string'&&item.value==='LIKE')||
((row.fieldType!=='int'&&row.fieldType!=='time.Time'&&row.fieldType!=='float64')&&(item.value==='BETWEEN' || item.value==='NOT BETWEEN'))
"
/>
</el-select>
</template>
</el-table-column>
<el-table-column align="left" label="操作" width="300" fixed="right">
<template #default="scope">
<el-button
size="small"
type="primary"
link
icon="edit"
@click="editAndAddField(scope.row)"
>高级编辑</el-button>
<el-button
size="small"
type="primary"
link
:disabled="scope.$index === 0"
@click="moveUpField(scope.$index)"
>上移</el-button>
<el-button
size="small"
type="primary"
link
:disabled="(scope.$index + 1) === form.fields.length"
@click="moveDownField(scope.$index)"
>下移</el-button>
<el-popover v-model="scope.row.visible" placement="top">
<p>确定删除吗</p>
<div style="text-align: right; margin-top: 8px;">
<el-button size="small" type="primary" link @click="scope.row.visible = false">取消</el-button>
<el-button type="primary" size="small" @click="deleteField(scope.$index)">确定</el-button>
</div>
<template #reference>
<el-button size="small" type="primary" link icon="delete" @click="scope.row.visible = true">删除</el-button>
</template>
</el-popover>
</template>
</el-table-column>
</el-table>
<!-- 组件列表 -->
<div class="gva-btn-list justify-content-flex-end auto-btn-list">
<el-button size="small" type="primary" @click="enterForm(true)">预览代码</el-button>
<el-button size="small" type="primary" @click="enterForm(false)">生成代码</el-button>
</div>
</div>
<!-- 组件弹窗 -->
<el-dialog v-model="dialogFlag" width="70%" title="组件内容">
<FieldDialog v-if="dialogFlag" ref="fieldDialogNode" :dialog-middle="dialogMiddle" />
<template #footer>
<div class="dialog-footer">
<el-button size="small" @click="closeDialog"> </el-button>
<el-button size="small" type="primary" @click="enterDialog"> </el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="previewFlag">
<template #header>
<div class="previewCodeTool">
<p>操作栏</p>
<el-button size="small" type="primary" @click="selectText">全选</el-button>
<el-button size="small" type="primary" @click="copy">复制</el-button>
</div>
</template>
<PreviewCodeDialog v-if="previewFlag" ref="previewNode" :preview-code="preViewCode" />
<template #footer>
<div class="dialog-footer" style="padding-top:14px;padding-right:14px">
<el-button size="small" type="primary" @click="previewFlag = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import FieldDialog from '@/view/systemTools/autoCode/component/fieldDialog.vue'
import PreviewCodeDialog from '@/view/systemTools/autoCode/component/previewCodeDialg.vue'
import { toUpperCase, toHump, toSQLLine, toLowerCase } from '@/utils/stringFun'
import { createTemp, getDB, getTable, getColumn, preview, getMeta, getPackageApi } from '@/api/autoCode'
import { getDict } from '@/utils/dictionary'
import { ref, getCurrentInstance, reactive, watch, toRaw } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import WarningBar from '@/components/warningBar/warningBar.vue'
const typeOptions = ref([
{
label: '字符串',
value: 'string'
},
{
label: '整型',
value: 'int'
},
{
label: '布尔值',
value: 'bool'
},
{
label: '浮点型',
value: 'float64'
},
{
label: '时间',
value: 'time.Time'
},
{
label: '枚举',
value: 'enum'
}
])
const typeSearchOptions = ref([
{
label: '=',
value: '='
},
{
label: '<>',
value: '<>'
},
{
label: '>',
value: '>'
},
{
label: '<',
value: '<'
},
{
label: 'LIKE',
value: 'LIKE'
},
{
label: 'BETWEEN',
value: 'BETWEEN'
},
{
label: 'NOT BETWEEN',
value: 'NOT BETWEEN'
}
])
const fieldTemplate = {
fieldName: '',
fieldDesc: '',
fieldType: '',
dataType: '',
fieldJson: '',
columnName: '',
dataTypeLong: '',
comment: '',
require: false,
sort: false,
errorText: '',
clearable: true,
fieldSearchType: '',
dictType: ''
}
const route = useRoute()
const router = useRouter()
const activeNames = reactive([])
const preViewCode = ref({})
const dbform = ref({
businessDB: '',
dbName: '',
tableName: ''
})
const tableOptions = ref([])
const addFlag = ref('')
const fdMap = ref({})
const form = ref({
structName: '',
tableName: '',
packageName: '',
package: '',
abbreviation: '',
description: '',
businessDB: '',
autoCreateApiToSql: true,
autoMoveFile: true,
autoCreateResource: false,
fields: []
})
const rules = ref({
structName: [
{ required: true, message: '请输入结构体名称', trigger: 'blur' }
],
abbreviation: [
{ required: true, message: '请输入结构体简称', trigger: 'blur' }
],
description: [
{ required: true, message: '请输入结构体描述', trigger: 'blur' }
],
packageName: [
{
required: true,
message: '文件名称sysXxxxXxxx',
trigger: 'blur'
}
],
package: [
{ required: true, message: '请选择package', trigger: 'blur' }
]
})
const dialogMiddle = ref({})
const bk = ref({})
const dialogFlag = ref(false)
const previewFlag = ref(false)
const toLowerCaseFunc = (form, key) => {
form[key] = toLowerCase(form[key])
}
const previewNode = ref(null)
const selectText = () => {
previewNode.value.selectText()
}
const copy = () => {
previewNode.value.copy()
}
const editAndAddField = (item) => {
dialogFlag.value = true
if (item) {
addFlag.value = 'edit'
bk.value = JSON.parse(JSON.stringify(item))
dialogMiddle.value = item
} else {
addFlag.value = 'add'
dialogMiddle.value = JSON.parse(JSON.stringify(fieldTemplate))
}
}
const moveUpField = (index) => {
if (index === 0) {
return
}
const oldUpField = form.value.fields[index - 1]
form.value.fields.splice(index - 1, 1)
form.value.fields.splice(index, 0, oldUpField)
}
const moveDownField = (index) => {
const fCount = form.value.fields.length
if (index === fCount - 1) {
return
}
const oldDownField = form.value.fields[index + 1]
form.value.fields.splice(index + 1, 1)
form.value.fields.splice(index, 0, oldDownField)
}
const currentInstance = getCurrentInstance()
const enterDialog = () => {
currentInstance.refs.fieldDialogNode.fieldDialogFrom.validate(valid => {
if (valid) {
dialogMiddle.value.fieldName = toUpperCase(
dialogMiddle.value.fieldName
)
if (addFlag.value === 'add') {
form.value.fields.push(dialogMiddle.value)
}
dialogFlag.value = false
} else {
return false
}
})
}
const closeDialog = () => {
if (addFlag.value === 'edit') {
dialogMiddle.value = bk.value
}
dialogFlag.value = false
}
const deleteField = (index) => {
form.value.fields.splice(index, 1)
}
const autoCodeForm = ref(null)
const enterForm = async(isPreview) => {
if (form.value.fields.length <= 0) {
ElMessage({
type: 'error',
message: '请填写至少一个field'
})
return false
}
if (
form.value.fields.some(item => item.fieldName === form.value.structName)
) {
ElMessage({
type: 'error',
message: '存在与结构体同名的字段'
})
return false
}
autoCodeForm.value.validate(async valid => {
if (valid) {
for (const key in form.value) {
if (typeof form.value[key] === 'string') {
form.value[key] = form.value[key].trim()
}
}
form.value.structName = toUpperCase(form.value.structName)
form.value.tableName = form.value.tableName.replace(' ', '')
if (!form.value.tableName) {
form.value.tableName = toSQLLine(toLowerCase(form.value.structName))
}
if (form.value.structName === form.value.abbreviation) {
ElMessage({
type: 'error',
message: 'structName和struct简称不能相同'
})
return false
}
form.value.humpPackageName = toSQLLine(form.value.packageName)
if (isPreview) {
const data = await preview(form.value)
preViewCode.value = data.data.autoCode
previewFlag.value = true
} else {
const data = await createTemp(form.value)
if (data.headers?.success === 'false') {
return
} else {
if (form.value.autoMoveFile) {
ElMessage({
type: 'success',
message: '自动化代码创建成功,自动移动成功'
})
return
}
ElMessage({
type: 'success',
message: '自动化代码创建成功,正在下载'
})
}
const blob = new Blob([data])
const fileName = 'ginvueadmin.zip'
if ('download' in document.createElement('a')) {
// 不是IE浏览器
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
} else {
// IE 10+
window.navigator.msSaveBlob(blob, fileName)
}
}
} else {
return false
}
})
}
const dbList = ref([])
const dbOptions = ref([])
const getDbFunc = async() => {
dbform.value.dbName = ''
dbform.value.tableName = ''
const res = await getDB({ businessDB: dbform.value.businessDB })
if (res.code === 0) {
dbOptions.value = res.data.dbs
dbList.value = res.data.dbList
}
}
const getTableFunc = async() => {
const res = await getTable({ businessDB: dbform.value.businessDB, dbName: dbform.value.dbName })
if (res.code === 0) {
tableOptions.value = res.data.tables
}
dbform.value.tableName = ''
}
const getColumnFunc = async() => {
const gormModelList = ['id', 'created_at', 'updated_at', 'deleted_at']
const res = await getColumn(dbform.value)
if (res.code === 0) {
let dbtype = ''
if (dbform.value.businessDB !== '') {
const dbtmp = dbList.value.find(item => item.aliasName === dbform.value.businessDB)
console.log(dbtmp)
const dbraw = toRaw(dbtmp)
console.log(dbraw)
dbtype = dbraw.dbtype
}
const tbHump = toHump(dbform.value.tableName)
form.value.structName = toUpperCase(tbHump)
form.value.tableName = dbform.value.tableName
form.value.packageName = tbHump
form.value.abbreviation = tbHump
form.value.description = tbHump + '表'
form.value.autoCreateApiToSql = true
form.value.autoMoveFile = true
form.value.fields = []
res.data.columns &&
res.data.columns.forEach(item => {
if (!gormModelList.some(gormfd => gormfd === item.columnName)) {
const fbHump = toHump(item.columnName)
form.value.fields.push({
fieldName: toUpperCase(fbHump),
fieldDesc: item.columnComment || fbHump + '字段',
fieldType: fdMap.value[item.dataType],
dataType: item.dataType,
fieldJson: fbHump,
dataTypeLong: item.dataTypeLong && item.dataTypeLong.split(',')[0],
columnName: dbtype == 'oracle' ? item.columnName.toUpperCase() : item.columnName,
comment: item.columnComment,
require: false,
errorText: '',
clearable: true,
fieldSearchType: '',
dictType: ''
})
}
})
}
}
const setFdMap = async() => {
const fdTypes = ['string', 'int', 'bool', 'float64', 'time.Time']
fdTypes.forEach(async fdtype => {
const res = await getDict(fdtype)
res && res.forEach(item => {
fdMap.value[item.label] = fdtype
})
})
}
const getAutoCodeJson = async(id) => {
const res = await getMeta({ id: Number(id) })
if (res.code === 0) {
form.value = JSON.parse(res.data.meta)
}
}
const pkgs = ref([])
const getPkgs = async() => {
const res = await getPackageApi()
if (res.code === 0) {
pkgs.value = res.data.pkgs
}
}
const goPkgs = () => {
router.push({ name: 'autoPkg' })
}
const init = () => {
getDbFunc()
setFdMap()
getPkgs()
const id = route.params.id
if (id) {
getAutoCodeJson(id)
}
}
init()
watch(() => route.params.id, (id) => {
if (route.name === 'autoCodeEdit') {
init()
}
})
</script>
<script>
export default {
name: 'AutoCode'
}
</script>
<style scoped lang="scss">
.previewCodeTool {
display: flex;
align-items: center;
padding: 5px 0;
}
.button-box {
padding: 10px 20px;
.el-button {
margin-right: 20px;
float: right;
}
}
.auto-btn-list{
margin-top: 16px;
}
.auto-icon{
margin-left: 6px;
color: #666;
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,188 @@
<template>
<div>
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button size="small" type="primary" icon="plus" @click="goAutoCode(null)">新增</el-button>
</div>
<el-table :data="tableData">
<el-table-column
type="selection"
width="55"
/>
<el-table-column align="left" label="id" width="60" prop="ID" />
<el-table-column align="left" label="日期" width="180">
<template #default="scope">{{ formatDate(scope.row.CreatedAt) }}</template>
</el-table-column>
<el-table-column align="left" label="结构体名" min-width="150" prop="structName" />
<el-table-column align="left" label="结构体描述" min-width="150" prop="structCNName" />
<el-table-column align="left" label="表名称" min-width="150" prop="tableName" />
<el-table-column align="left" label="回滚标记" min-width="150" prop="flag">
<template #default="scope">
<el-tag
v-if="scope.row.flag"
type="danger"
size="small"
effect="dark"
>
已回滚
</el-tag>
<el-tag
v-else
size="small"
type="success"
effect="dark"
>
未回滚
</el-tag>
</template>
</el-table-column>
<el-table-column align="left" label="操作" min-width="240">
<template #default="scope">
<div>
<el-button size="small" type="primary" link :disabled="scope.row.flag === 1" @click="rollbackFunc(scope.row,true)">回滚(删表)</el-button>
<el-button size="small" type="primary" link :disabled="scope.row.flag === 1" @click="rollbackFunc(scope.row,false)">回滚(不删表)</el-button>
<el-button size="small" type="primary" link @click="goAutoCode(scope.row)">复用</el-button>
<el-button size="small" type="primary" link @click="deleteRow(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="gva-pagination">
<el-pagination
:current-page="page"
:page-size="pageSize"
:page-sizes="[10, 30, 50, 100]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'AutoCodeAdmin',
}
</script>
<script setup>
import { getSysHistory, rollback, delSysHistory } from '@/api/autoCode.js'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ref } from 'vue'
import { formatDate } from '@/utils/format'
const router = useRouter()
const page = ref(1)
const total = ref(0)
const pageSize = ref(10)
const tableData = ref([])
// 分页
const handleSizeChange = (val) => {
pageSize.value = val
getTableData()
}
const handleCurrentChange = (val) => {
page.value = val
getTableData()
}
// 查询
const getTableData = async() => {
const table = await getSysHistory({
page: page.value,
pageSize: pageSize.value
})
if (table.code === 0) {
tableData.value = table.data.list
total.value = table.data.total
page.value = table.data.page
pageSize.value = table.data.pageSize
}
}
getTableData()
const deleteRow = async(row) => {
ElMessageBox.confirm('此操作将删除本历史, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
const res = await delSysHistory({ id: Number(row.ID) })
if (res.code === 0) {
ElMessage.success('删除成功')
getTableData()
}
})
}
const rollbackFunc = async(row, flag) => {
if (flag) {
ElMessageBox.confirm(`此操作将删除自动创建的文件和api会删除表, 是否继续?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
ElMessageBox.confirm(`此操作将删除自动创建的文件和api会删除表, 请继续确认!!!`, '会删除表', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
ElMessageBox.confirm(`此操作将删除自动创建的文件和api会删除表, 请继续确认!!!`, '会删除表', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
const res = await rollback({ id: Number(row.ID), deleteTable: flag })
if (res.code === 0) {
ElMessage.success('回滚成功')
getTableData()
}
})
})
})
} else {
ElMessageBox.confirm(`此操作将删除自动创建的文件和api, 是否继续?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
const res = await rollback({ id: Number(row.ID), deleteTable: flag })
if (res.code === 0) {
ElMessage.success('回滚成功')
getTableData()
}
})
}
}
const goAutoCode = (row) => {
if (row) {
router.push({ name: 'autoCodeEdit', params: {
id: row.ID
}})
} else {
router.push({ name: 'autoCode' })
}
}
</script>
<style scoped lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
.el-tag--mini {
margin-left: 5px;
}
.warning {
color: #dc143c;
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<div>
<warning-bar href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=3" title="此功能为开发环境使用不建议发布到生产具体使用效果请看视频https://www.bilibili.com/video/BV1kv4y1g7nT?p=3" />
<div class="gva-table-box">
<div class="gva-btn-list">
<el-button size="small" type="primary" icon="plus" @click="openDialog('addApi')">新增</el-button>
</div>
<el-table :data="tableData">
<el-table-column align="left" label="id" width="60" prop="ID" />
<el-table-column align="left" label="包名" width="150" prop="packageName" />
<el-table-column align="left" label="展示名" width="150" prop="label" />
<el-table-column align="left" label="描述" min-width="150" prop="desc" />
<el-table-column align="left" label="操作" width="200">
<template #default="scope">
<el-button
icon="delete"
size="small"
type="primary"
link
@click="deleteApiFunc(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-dialog v-model="dialogFormVisible" :before-close="closeDialog" title="创建Package">
<warning-bar title="新增Pkg用于自动化代码使用" />
<el-form ref="pkgForm" :model="form" :rules="rules" label-width="80px">
<el-form-item label="包名" prop="packageName">
<el-input v-model="form.packageName" autocomplete="off" />
</el-form-item>
<el-form-item label="展示名" prop="label">
<el-input v-model="form.label" autocomplete="off" />
</el-form-item>
<el-form-item label="描述" prop="desc">
<el-input v-model="form.desc" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button size="small" @click="closeDialog"> </el-button>
<el-button size="small" type="primary" @click="enterDialog"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'AutoPkg',
}
</script>
<script setup>
import {
createPackageApi,
getPackageApi,
deletePackageApi,
} from '@/api/autoCode'
import { ref } from 'vue'
import WarningBar from '@/components/warningBar/warningBar.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
const form = ref({
packageName: '',
label: '',
desc: '',
})
const validateNum = (rule, value, callback) => {
if ((/^\d+$/.test(value[0]))) {
callback(new Error('不能够以数字开头'))
} else {
callback()
}
}
const rules = ref({
packageName: [
{ required: true, message: '请输入包名', trigger: 'blur' },
{ validator: validateNum, trigger: 'blur' }
],
})
const dialogFormVisible = ref(false)
const openDialog = () => {
dialogFormVisible.value = true
}
const closeDialog = () => {
dialogFormVisible.value = false
form.value = {
packageName: '',
label: '',
desc: '',
}
}
const pkgForm = ref(null)
const enterDialog = async() => {
pkgForm.value.validate(async valid => {
if (valid) {
const res = await createPackageApi(form.value)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '添加成功',
showClose: true
})
}
getTableData()
closeDialog()
}
})
}
const tableData = ref([])
const getTableData = async() => {
const table = await getPackageApi()
if (table.code === 0) {
tableData.value = table.data.pkgs
}
}
const deleteApiFunc = async(row) => {
ElMessageBox.confirm('此操作仅删除数据库中的pkg存储后端相应目录结构请自行删除与数据库保持一致', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async() => {
const res = await deletePackageApi(row)
if (res.code === 0) {
ElMessage({
type: 'success',
message: '删除成功!'
})
getTableData()
}
})
}
getTableData()
</script>
<style scoped lang="scss">
.button-box {
padding: 10px 20px;
.el-button {
float: right;
}
}
.warning {
color: #dc143c;
}
</style>

View File

@@ -0,0 +1,220 @@
<template>
<div>
<div class="gva-table-box">
<el-form label-width="140px" class="plug-form">
<el-form-item label="插件名">
<el-input v-model="form.plugName" placeholder="必填(英文大写字母开头)" @blur="titleCase" />
</el-form-item>
<el-form-item label="路由组">
<el-input v-model="form.routerGroup" placeholder="将会作为插件路由组使用" />
</el-form-item>
<el-form-item label="使用全局属性">
<el-checkbox v-model="form.hasGlobal" />
</el-form-item>
<el-form-item v-if="form.hasGlobal" label="全局属性">
<div v-for="(i,k) in form.global" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注 必填" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.global)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.global,k)" />
</span>
</div>
</el-form-item>
<el-form-item label="使用Request">
<el-checkbox v-model="form.hasRequest" />
</el-form-item>
<el-form-item v-if="form.hasRequest" label="Request">
<div v-for="(i,k) in form.request" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注 必填" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.request)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.request,k)" />
</span>
</div>
</el-form-item>
<el-form-item label="使用Response">
<el-checkbox v-model="form.hasResponse" />
</el-form-item>
<el-form-item v-if="form.hasResponse" label="Response">
<div v-for="(i,k) in form.response" :key="k" class="plug-row">
<span>
<el-input v-model="i.key" placeholder="key 必填" />
</span>
<span>
<el-select v-model="i.type" placeholder="type 必填">
<el-option label="string" value="string" />
<el-option label="int" value="int" />
<el-option label="float32" value="float32" />
<el-option label="float64" value="float64" />
<el-option label="bool" value="bool" />
</el-select>
</span>
<span>
<el-input v-model="i.desc" placeholder="备注 必填" />
</span>
<span>
<el-button :icon="Plus" circle @click="addkv(form.response)" />
</span>
<span>
<el-button :icon="Minus" circle @click="minkv(form.response,k)" />
</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="createPlug">创建</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import { toUpperCase } from '@/utils/stringFun'
import {
Plus,
Minus
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { createPlugApi } from '@/api/autoCode.js'
import { reactive } from 'vue'
const form = reactive({
plugName: '',
routerGroup: '',
hasGlobal: true,
hasRequest: true,
hasResponse: true,
global: [{
key: '',
type: '',
desc: '',
}],
request: [{
key: '',
type: '',
desc: '',
}],
response: [{
key: '',
type: '',
desc: '',
}]
})
const titleCase = () => {
form.plugName = toUpperCase(form.plugName)
}
const createPlug = async() => {
if (!form.plugName || !form.routerGroup) {
ElMessage.error('插件名称和插件路由组为必填项')
return
}
if (form.hasGlobal) {
const intercept = form.global.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('全局属性的key和type为必填项')
return
}
}
if (form.hasRequest) {
const intercept = form.request.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('请求属性的key和type为必填项')
return
}
}
if (form.hasResponse) {
const intercept = form.response.some(i => {
if (!i.key || !i.type) {
return true
}
})
if (intercept) {
ElMessage.error('响应属性的key和type为必填项')
return
}
}
const res = await createPlugApi(form)
if (res.code === 0) {
ElMessageBox('创建成功插件已自动写入后端plugin目录下请按照自己的逻辑进行创造')
}
}
const addkv = (arr) => {
arr.push({
key: '',
value: '',
})
}
const minkv = (arr, key) => {
if (arr.length === 1) {
ElMessage.warning('至少有一个全局属性')
return
}
arr.splice(key, 1)
}
</script>
<style lang="scss" scoped>
.plug-form{
width: 680px;
}
.plug-row{
display: flex;
align-items: center;
width: 100%;
&+&{
margin-top: 12px;
}
&>span{
margin-left: 8px;
}
}
</style>

View File

@@ -0,0 +1,17 @@
<template>
<div style="height:80vh">
<iframe width="100%" height="100%" :src="`${basePath}:${basePort}/form-generator/#/`" frameborder="0" />
</div>
</template>
<script>
export default {
name: 'FormGenerator'
}
</script>
<script setup>
import { ref } from 'vue'
const basePath = ref(import.meta.env.VITE_BASE_PATH)
const basePort = ref(import.meta.env.VITE_SERVER_PORT)
</script>

View File

@@ -0,0 +1,21 @@
<template>
<div>
<router-view v-slot="{ Component }">
<transition mode="out-in" name="el-fade-in-linear">
<keep-alive :include="routerStore.keepAliveRouters">
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
</div>
</template>
<script>
export default {
name: 'System'
}
</script>
<script setup>
import { useRouterStore } from '@/pinia/modules/router'
const routerStore = useRouterStore()
</script>

View File

@@ -0,0 +1,44 @@
<template>
<div>
<el-upload
class="upload-demo"
drag
:action="`${path}/autoCode/installPlugin`"
:headers="{'x-token':userStore.token}"
:show-file-list="false"
:on-success="handleSuccess"
:on-error="handleSuccess"
name="plug"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
拖拽或<em>点击上传</em>
</div>
<template #tip>
<div class="el-upload__tip">
请把安装包的zip拖拽至此处上传
</div>
</template>
</el-upload>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useUserStore } from '@/pinia/modules/user'
import { ElMessage } from 'element-plus'
const userStore = useUserStore()
const path = ref(import.meta.env.VITE_BASE_API)
const handleSuccess = (res) => {
if (res.code === 0) {
let msg = ``
res.data && res.data.forEach((item, index) => {
msg += `${index + 1}.${item.msg}\n`
})
alert(msg)
} else {
ElMessage.error(res.msg)
}
}
</script>

View File

@@ -0,0 +1,463 @@
<template>
<div class="system">
<el-form ref="form" :model="config" label-width="240px">
<!-- System start -->
<el-collapse v-model="activeNames">
<el-collapse-item title="系统配置" name="1">
<el-form-item label="环境值">
<!-- <el-input v-model="config.system.env" />-->
<el-select v-model="config.system.env" style="width:100%">
<el-option value="public" />
<el-option value="develop" />
</el-select>
</el-form-item>
<el-form-item label="端口值">
<el-input v-model.number="config.system.addr" />
</el-form-item>
<el-form-item label="数据库类型">
<el-select v-model="config.system['db-type']" style="width:100%">
<el-option value="mysql" />
<el-option value="pgsql" />
</el-select>
</el-form-item>
<el-form-item label="Oss类型">
<el-select v-model="config.system['oss-type']" style="width:100%">
<el-option value="local" />
<el-option value="qiniu" />
<el-option value="tencent-cos" />
<el-option value="aliyun-oss" />
<el-option value="huawei-obs" />
</el-select>
</el-form-item>
<el-form-item label="多点登录拦截">
<el-checkbox v-model="config.system['use-multipoint']">开启</el-checkbox>
</el-form-item>
<el-form-item label="开启redis">
<el-checkbox v-model="config.system['use-redis']">开启</el-checkbox>
</el-form-item>
<el-form-item label="限流次数">
<el-input-number v-model.number="config.system['iplimit-count']" />
</el-form-item>
<el-form-item label="限流时间">
<el-input-number v-model.number="config.system['iplimit-time']" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="jwt签名" name="2">
<el-form-item label="jwt签名">
<el-input v-model="config.jwt['signing-key']" />
</el-form-item>
<el-form-item label="有效期">
<el-input v-model="config.jwt['expires-time']" />
</el-form-item>
<el-form-item label="缓冲期">
<el-input v-model="config.jwt['buffer-time']" />
</el-form-item>
<el-form-item label="签发者">
<el-input v-model="config.jwt.issuer" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Zap日志配置" name="3">
<el-form-item label="级别">
<el-input v-model.number="config.zap.level" />
</el-form-item>
<el-form-item label="输出">
<el-input v-model="config.zap.format" />
</el-form-item>
<el-form-item label="日志前缀">
<el-input v-model="config.zap.prefix" />
</el-form-item>
<el-form-item label="日志文件夹">
<el-input v-model="config.zap.director" />
</el-form-item>
<el-form-item label="编码级">
<el-input v-model="config.zap['encode-level']" />
</el-form-item>
<el-form-item label="栈名">
<el-input v-model="config.zap['stacktrace-key']" />
</el-form-item>
<el-form-item label="日志留存时间(默认以天为单位)">
<el-input v-model.number="config.zap['max-age']" />
</el-form-item>
<el-form-item label="显示行">
<el-checkbox v-model="config.zap['show-line']" />
</el-form-item>
<el-form-item label="输出控制台">
<el-checkbox v-model="config.zap['log-in-console']" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Redis admin数据库配置" name="4">
<el-form-item label="库">
<el-input v-model.number="config.redis.db" />
</el-form-item>
<el-form-item label="地址">
<el-input v-model="config.redis.addr" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="config.redis.password" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="邮箱配置" name="5">
<el-form-item label="接收者邮箱">
<el-input v-model="config.email.to" placeholder="可多个,以逗号分隔" />
</el-form-item>
<el-form-item label="端口">
<el-input v-model.number="config.email.port" />
</el-form-item>
<el-form-item label="发送者邮箱">
<el-input v-model="config.email.from" />
</el-form-item>
<el-form-item label="host">
<el-input v-model="config.email.host" />
</el-form-item>
<el-form-item label="是否为ssl">
<el-checkbox v-model="config.email['is-ssl']" />
</el-form-item>
<el-form-item label="secret">
<el-input v-model="config.email.secret" />
</el-form-item>
<el-form-item label="测试邮件">
<el-button @click="email">测试邮件</el-button>
</el-form-item>
</el-collapse-item>
<el-collapse-item title="验证码配置" name="7">
<el-form-item label="字符长度">
<el-input v-model.number="config.captcha['key-long']" />
</el-form-item>
<el-form-item label="平台宽度">
<el-input v-model.number="config.captcha['img-width']" />
</el-form-item>
<el-form-item label="图片高度">
<el-input v-model.number="config.captcha['img-height']" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="数据库配置" name="9">
<template v-if="config.system['db-type'] === 'mysql'">
<el-form-item label="用户名">
<el-input v-model="config.mysql.username" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="config.mysql.password" />
</el-form-item>
<el-form-item label="地址">
<el-input v-model="config.mysql.path" />
</el-form-item>
<el-form-item label="数据库">
<el-input v-model="config.mysql['db-name']" />
</el-form-item>
<el-form-item label="前缀">
<el-input v-model="config.mysql['refix']" />
</el-form-item>
<el-form-item label="复数表">
<el-switch v-model="config.mysql['singular']" />
</el-form-item>
<el-form-item label="引擎">
<el-input v-model="config.mysql['engine']" />
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.mysql['max-idle-conns']" />
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.mysql['max-open-conns']" />
</el-form-item>
<el-form-item label="写入日志">
<el-checkbox v-model="config.mysql['log-zap']" />
</el-form-item>
<el-form-item label="日志模式">
<el-input v-model="config.mysql['log-mode']" />
</el-form-item>
</template>
<template v-if="config.system.dbType === 'pgsql'">
<el-form-item label="用户名">
<el-input v-model="config.pgsql.username" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="config.pgsql.password" />
</el-form-item>
<el-form-item label="地址">
<el-input v-model="config.pgsql.path" />
</el-form-item>
<el-form-item label="数据库">
<el-input v-model="config.pgsql.dbname" />
</el-form-item>
<el-form-item label="前缀">
<el-input v-model="config.pgsql['refix']" />
</el-form-item>
<el-form-item label="复数表">
<el-switch v-model="config.pgsql['singular']" />
</el-form-item>
<el-form-item label="引擎">
<el-input v-model="config.pgsql['engine']" />
</el-form-item>
<el-form-item label="maxIdleConns">
<el-input v-model.number="config.pgsql['max-idle-conns']" />
</el-form-item>
<el-form-item label="maxOpenConns">
<el-input v-model.number="config.pgsql['max-open-conns']" />
</el-form-item>
<el-form-item label="写入日志">
<el-checkbox v-model="config.pgsql['log-zap']" />
</el-form-item>
<el-form-item label="日志模式">
<el-input v-model="config.pgsql['log-mode']" />
</el-form-item>
</template>
</el-collapse-item>
<el-collapse-item title="oss配置" name="10">
<template v-if="config.system['oss-type'] === 'local'">
<h2>本地文件配置</h2>
<el-form-item label="本地文件访问路径">
<el-input v-model="config.local.path" />
</el-form-item>
<el-form-item label="本地文件存储路径">
<el-input v-model="config.local['store-path']" />
</el-form-item>
</template>
<template v-if="config.system['oss-type'] === 'qiniu'">
<h2>qiniu上传配置</h2>
<el-form-item label="存储区域">
<el-input v-model="config.qiniu.zone" />
</el-form-item>
<el-form-item label="空间名称">
<el-input v-model="config.qiniu.bucket" />
</el-form-item>
<el-form-item label="CDN加速域名">
<el-input v-model="config.qiniu['img-path']" />
</el-form-item>
<el-form-item label="是否使用https">
<el-checkbox v-model="config.qiniu['use-https']">开启</el-checkbox>
</el-form-item>
<el-form-item label="accessKey">
<el-input v-model="config.qiniu['access-key']" />
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config.qiniu['secret-key']" />
</el-form-item>
<el-form-item label="上传是否使用CDN上传加速">
<el-checkbox v-model="config.qiniu['use-cdn-domains']">开启</el-checkbox>
</el-form-item>
</template>
<template v-if="config.system['oss-type'] === 'tencent-cos'">
<h2>腾讯云COS上传配置</h2>
<el-form-item label="存储桶名称">
<el-input v-model="config['tencent-cos']['bucket']" />
</el-form-item>
<el-form-item label="所属地域">
<el-input v-model="config['tencent-cos'].region" />
</el-form-item>
<el-form-item label="secretID">
<el-input v-model="config['tencent-cos']['secret-id']" />
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config['tencent-cos']['secret-key']" />
</el-form-item>
<el-form-item label="路径前缀">
<el-input v-model="config['tencent-cos']['path-prefix']" />
</el-form-item>
<el-form-item label="访问域名">
<el-input v-model="config['tencent-cos']['base-url']" />
</el-form-item>
</template>
<template v-if="config.system['oss-type'] === 'aliyun-oss'">
<h2>阿里云OSS上传配置</h2>
<el-form-item label="区域">
<el-input v-model="config['aliyun-oss'].endpoint" />
</el-form-item>
<el-form-item label="accessKeyId">
<el-input v-model="config['aliyun-oss']['access-key-id']" />
</el-form-item>
<el-form-item label="accessKeySecret">
<el-input v-model="config['aliyun-oss']['access-key-secret']" />
</el-form-item>
<el-form-item label="存储桶名称">
<el-input v-model="config['aliyun-oss']['bucket-name']" />
</el-form-item>
<el-form-item label="访问域名">
<el-input v-model="config['aliyun-oss']['bucket-url']" />
</el-form-item>
</template>
<template v-if="config.system['oss-type'] === 'huawei-obs'">
<h2>华为云Obs上传配置</h2>
<el-form-item label="路径">
<el-input v-model="config['hua-wei-obs'].path" />
</el-form-item>
<el-form-item label="存储桶名称">
<el-input v-model="config['hua-wei-obs'].bucket" />
</el-form-item>
<el-form-item label="区域">
<el-input v-model="config['hua-wei-obs'].endpoint" />
</el-form-item>
<el-form-item label="accessKey">
<el-input v-model="config['hua-wei-obs']['access-key']" />
</el-form-item>
<el-form-item label="secretKey">
<el-input v-model="config['hua-wei-obs']['secret-key']" />
</el-form-item>
</template>
</el-collapse-item>
<el-collapse-item title="Excel上传配置" name="11">
<el-form-item label="合成目标地址">
<el-input v-model="config.excel.dir" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="自动化代码配置" name="12">
<el-form-item label="是否自动重启(linux)">
<el-checkbox v-model="config.autocode['transfer-restart']" />
</el-form-item>
<el-form-item label="root(项目根路径)">
<el-input v-model="config.autocode.root" disabled />
</el-form-item>
<el-form-item label="Server(后端代码地址)">
<el-input v-model="config.autocode['transfer-restart']" />
</el-form-item>
<el-form-item label="SApi(后端api文件夹地址)">
<el-input v-model="config.autocode['server-api']" />
</el-form-item>
<el-form-item label="SInitialize(后端Initialize文件夹)">
<el-input v-model="config.autocode['server-initialize']" />
</el-form-item>
<el-form-item label="SModel(后端Model文件地址)">
<el-input v-model="config.autocode['server-model']" />
</el-form-item>
<el-form-item label="SRequest(后端Request文件夹地址)">
<el-input v-model="config.autocode['server-request']" />
</el-form-item>
<el-form-item label="SRouter(后端Router文件夹地址)">
<el-input v-model="config.autocode['server-router']" />
</el-form-item>
<el-form-item label="SService(后端Service文件夹地址)">
<el-input v-model="config.autocode['server-service']" />
</el-form-item>
<el-form-item label="Web(前端文件夹地址)">
<el-input v-model="config.autocode.web" />
</el-form-item>
<el-form-item label="WApi(后端WApi文件夹地址)">
<el-input v-model="config.autocode['web-api']" />
</el-form-item>
<el-form-item label="WForm(后端WForm文件夹地址)">
<el-input v-model="config.autocode['web-form']" />
</el-form-item>
<el-form-item label="WTable(后端WTable文件夹地址)">
<el-input v-model="config.autocode['web-table']" />
</el-form-item>
</el-collapse-item>
<el-collapse-item title="Timer(定时任务)" name="13">
<el-form-item label="Start是否启用">
<el-checkbox v-model="config.timer['start']" />
</el-form-item>
<el-form-item label="Spec(CRON表达式)">
<el-input v-model="config.timer.spec" />
</el-form-item>
<template v-for="(item,k) in config.timer.detail">
<div v-for="(key,k2) in item" :key="k2">
<el-form-item :key="k+k2" :label="k2">
<el-input v-model="item[k2]" />
</el-form-item>
</div>
</template>
</el-collapse-item>
</el-collapse>
</el-form>
<div class="gva-btn-list">
<el-button type="primary" size="small" @click="update">立即更新</el-button>
<el-button type="primary" size="small" @click="reload">重启服务开发中</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'Config'
}
</script>
<script setup>
import { getSystemConfig, setSystemConfig } from '@/api/system'
import { emailTest } from '@/api/email'
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
const activeNames = reactive([])
const config = ref({
system: {
'iplimit-count': 0,
'iplimit-time': 0
},
jwt: {},
mysql: {},
pgsql: {},
excel: {},
autocode: {},
redis: {},
qiniu: {},
'tencent-cos': {},
'aliyun-oss': {},
'hua-wei-obs': {},
captcha: {},
zap: {},
local: {},
email: {},
timer: {
detail: {}
}
})
const initForm = async() => {
const res = await getSystemConfig()
if (res.code === 0) {
config.value = res.data.config
}
}
initForm()
const reload = () => {}
const update = async() => {
const res = await setSystemConfig({ config: config.value })
if (res.code === 0) {
ElMessage({
type: 'success',
message: '配置文件设置成功'
})
await initForm()
}
}
const email = async() => {
const res = await emailTest()
if (res.code === 0) {
ElMessage({
type: 'success',
message: '邮件发送成功'
})
await initForm()
} else {
ElMessage({
type: 'error',
message: '邮件发送失败'
})
}
}
</script>
<style lang="scss">
.system {
background: #fff;
padding:36px;
border-radius: 2px;
h2 {
padding: 10px;
margin: 10px 0;
font-size: 16px;
box-shadow: -4px 0px 0px 0px #e7e8e8;
}
::v-deep(.el-input-number__increase){
top:5px !important;
}
.gva-btn-list{
margin-top:16px;
}
}
</style>