feat axios支持下载文件. 代码生成模块,权限资源编辑, 查询器支持回车出发查询

This commit is contained in:
xxm
2022-10-19 18:04:51 +08:00
parent 245971832f
commit 516d058176
18 changed files with 410 additions and 54 deletions

View File

@@ -8,6 +8,7 @@
:field="field"
:md="defaultItemMd"
:query-params="queryParams"
@enterQuery="query"
/>
<a-col :md="defaultItemMd" :sm="24">
<a-space>

View File

@@ -0,0 +1,34 @@
// 数字
export const NUMBER = 'number'
// 字符串
export const STRING = 'string'
// 布尔
export const BOOLEAN = 'boolean'
// 日期
export const DATE = 'date'
// 时间
export const TIME = 'time'
// 日期时间
export const DATE_TIME = 'date_time'
// 列表
export const LIST = 'list'
/**
* 查询属性
*/
export interface QueryField {
//类型
type: 'number' | 'string' | 'boolean' | 'date' | 'time' | 'date_time' | 'list'
// 提示
placeholder?: string
// 字段名称
field: string
// 显示名称
name: string
// 精度
precision?: number | null
// 查询列表
selectList?: Array<unknown> | null
// 时间格式化
format?: string | null
}

View File

@@ -3,6 +3,7 @@
<a-form-item :label="field.name">
<!-- 文本输入 -->
<a-input
@keyup.enter="query"
allowClear
v-if="field.type === STRING"
:placeholder="field.placeholder ? field.placeholder : '请输入查询值'"
@@ -28,7 +29,7 @@
v-else-if="field.type === LIST"
:placeholder="field.placeholder ? field.placeholder : '请选择查询值'"
v-model:value="queryParams[field.field]"
:options="field.list"
:options="field.selectList"
/>
<!-- 日期 -->
<a-date-picker
@@ -36,7 +37,7 @@
v-else-if="field.type === DATE"
style="width: 100%"
:placeholder="field.placeholder ? field.placeholder : '请选择日期'"
:valueFormat="queryParams.format ? queryParams.format : 'yyyy-MM-DD'"
:valueFormat="field.format ? field.format : 'yyyy-MM-DD'"
v-model:value="queryParams[field.field]"
/>
<!-- 时间 -->
@@ -45,7 +46,7 @@
v-else-if="field.type === TIME"
style="width: 100%"
:placeholder="field.placeholder ? field.placeholder : '请选择时间'"
:valueFormat="queryParams.format ? queryParams.format : 'HH:mm:ss'"
:valueFormat="field.format ? field.format : 'HH:mm:ss'"
v-model:value="queryParams[field.field]"
/>
<!-- 日期时间 -->
@@ -55,7 +56,7 @@
v-else-if="field.type === DATE_TIME"
style="width: 100%"
:placeholder="field.placeholder ? field.placeholder : '请选择日期时间'"
:valueFormat="queryParams.format ? queryParams.format : 'yyyy-MM-DD HH:mm:ss'"
:valueFormat="field.format ? field.format : 'yyyy-MM-DD HH:mm:ss'"
v-model:value="queryParams[field.field]"
/>
<!-- 默认文本输入 -->
@@ -70,7 +71,8 @@
</template>
<script lang="ts" setup>
import { BOOLEAN, DATE, DATE_TIME, LIST, NUMBER, QueryField, STRING, TIME } from './SuperQueryCode'
import { BOOLEAN, DATE, DATE_TIME, LIST, NUMBER, QueryField, STRING, TIME } from './Query'
const emits = defineEmits(['enterQuery'])
const props = withDefaults(
defineProps<{
// 查询字段属性
@@ -84,6 +86,9 @@
md: 6,
},
)
function query() {
emits('enterQuery')
}
</script>
<style scoped></style>

View File

@@ -1,20 +0,0 @@
// 数字
export const NUMBER = 'number'
// 字符串
export const STRING = 'string'
// 布尔
export const BOOLEAN = 'boolean'
// 日期
export const DATE = 'date'
// 时间
export const TIME = 'time'
// 日期时间
export const DATE_TIME = 'date_time'
// 列表
export const LIST = 'list'
export interface QueryField {
type: string
placeholder: string
field: string
}

View File

@@ -31,21 +31,24 @@ const transform: AxiosTransform = {
* @description: 处理响应数据。如果数据不是预期格式,可直接抛出错误
*/
transformResponseHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
const { t } = useI18n()
const { isTransformResponse, isReturnNativeResponse } = options
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取codedatamessage这些信息时开启
// if (!isTransformResponse) {
// return res.data
// }
// 错误的时候返回
// 获取请求头重的数据
const contentType = res.headers['content-type']
const rawData = res.data
// 获取请求头的数据
if (!rawData) {
// return '[HTTP] Request has no return value';
throw new Error('请求出错,请稍候重试')
}
// 下载流处理
if (contentType === 'application/octet-stream') {
return rawData
}
// 接收的通常是json的数据
// 这里 codedatamessage为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
const { code, msg, traceId } = rawData
@@ -75,9 +78,9 @@ const transform: AxiosTransform = {
// errorMessageMode=modal的时候会显示modal错误弹窗而不是消息提示用于一些比较重要的错误
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
if (options.errorMessageMode === 'modal') {
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg })
createErrorModal({ title: '错误提示', content: timeoutMsg || '请求出错,请稍候重试' })
} else if (options.errorMessageMode === 'message') {
createMessage.error(timeoutMsg)
createMessage.error(timeoutMsg || '请求出错,请稍候重试')
}
console.error('TraceId:', traceId)
throw new Error(timeoutMsg || '请求出错,请稍候重试')

View File

@@ -0,0 +1,67 @@
import { defHttp } from '/@/utils/http/axios'
import { PageResult, Result } from '/#/axios'
/**
* 分页
*/
export const page = (params) => {
return defHttp.get<Result<PageResult<DatabaseTable>>>({
url: '/gen/table/page',
params: params,
})
}
/**
* 获取表相关的代码生成参数信息
*/
export function getTableGenParam(tableName) {
return defHttp.get<Result<TableGenParam>>({
url: '/gen/table/getTableGenParam',
params: { tableName },
})
}
/**
* 预览
*/
export function codeGenPreview(obj) {
return defHttp.get<Result<DatabaseTable>>({
url: '/gen/code/codeGenPreview',
data: obj,
})
}
/**
* 下载
*/
export function genCodeZip(obj) {
return defHttp.post({
url: '/gen/code/genCodeZip',
responseType: 'blob',
data: obj,
})
}
/**
* 表信息
*/
export interface DatabaseTable {
// 表名
tableName: string
// 引擎类型
engine: string
// 表表述
tableComment: string
// 创建时间
createTime: string
}
/**
* 代码生成相关参数信息
*/
export interface TableGenParam {
// 实体类名称(大驼峰)
entityName: string
// 功能模块名称(全小写)
module: string
}

View File

@@ -0,0 +1,145 @@
<template>
<a-drawer title="代码生成参数配置" width="50%" :visible="visible" :destroyOnClose="true" :maskClosable="false" @close="handleCancel">
<a-form ref="formRef" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="功能模块名称" name="module">
<a-row>
<a-col :span="18">
<a-input v-model:value="form.module" />
</a-col>
<a-col :span="6">
<a-button style="width: 100%" @click="genParams">生成其他参数</a-button>
</a-col>
</a-row>
</a-form-item>
<a-form-item label="基础包名称" name="basePack">
<a-input v-model:value="form.basePack" />
</a-form-item>
<a-form-item label="实体类名称" name="entityName">
<a-input v-model:value="form.entityName" />
</a-form-item>
<a-form-item label="vue版本" name="vueVersion">
<a-select v-model:value="form.vueVersion" :default-value="form.vueVersion" style="width: 100%" placeholder="选择vue版本">
<!-- <a-select-option key="v2">Vue2</a-select-option>-->
<a-select-option key="v3">Vue3</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="基类" name="baseEntity">
<a-select v-model:value="form.baseEntity" :default-value="form.baseEntity" style="width: 100%" placeholder="选择基类">
<a-select-option key="MpBaseEntity">MpBaseEntity</a-select-option>
<a-select-option key="MpDelEntity">MpDelEntity</a-select-option>
<a-select-option key="MpCreateEntity">MpCreateEntity</a-select-option>
<a-select-option key="MpIdEntity">MpIdEntity</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="创建人" name="author">
<a-input v-model:value="form.author" />
</a-form-item>
<template v-if="genPackFlag">
<a-form-item label="请求地址" name="baseEntity">
<a-input v-model:value="form.requestPath" />
</a-form-item>
<a-form-item label="接口文件目录" name="vueApiPath">
<a-input v-model:value="form.vueApiPath" />
</a-form-item>
<a-form-item label="core包路径" name="corePack">
<a-input v-model:value="form.corePack" />
</a-form-item>
<a-form-item label="dto包路径" name="dtoPack">
<a-input v-model:value="form.dtoPack" />
</a-form-item>
<a-form-item label="参数包路径" name="paramPack">
<a-input v-model:value="form.paramPack" />
</a-form-item>
</template>
</a-form>
<div class="drawer-button">
<a-button key="cancel" @click="handleCancel">取消</a-button>
<a-button key="forward" type="primary" :disabled="!genPackFlag" @click="handleOk">生成</a-button>
</div>
</a-drawer>
</template>
<script lang="ts" setup>
import { getTableGenParam } from './CodeGen.api'
import { $ref } from 'vue/macros'
import { nextTick } from 'vue'
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { FormInstance } from 'ant-design-vue/lib/form'
const { labelCol, wrapperCol, visible } = useFormEdit()
const form = $ref({
basePack: 'cn.bootx',
module: '',
tableName: '',
entityName: '',
baseEntity: 'MpBaseEntity',
vueVersion: 'v3',
corePack: '',
paramPack: '',
dtoPack: '',
controllerPack: '',
requestPath: '',
vueApiPath: '',
author: 'xxm',
})
const rules = {}
let genType = $ref('down' as 'down' | 'preview')
let genPackFlag = $ref(false)
let formRef = $ref<FormInstance>()
const emits = defineEmits(['down', 'preview'])
function show(tableName, type: 'down' | 'preview') {
visible.value = true
form.tableName = tableName
genType = type
genPackFlag = false
getGenConfigParam()
}
// 确定
function handleOk() {
formRef.validate().then(() => {
emits(genType, form)
})
}
/**
* 获取代码生成配置信息
*/
async function getGenConfigParam() {
// 获取功能模块名称
const { data } = await getTableGenParam(form.tableName)
form.entityName = data.entityName
form.module = data.module
}
/**
* 生成代码生成参数参数
*/
function genParams() {
const { basePack, module } = form
// 包名
form.corePack = `${basePack}.core.${module}`
form.paramPack = `${basePack}.param.${module}`
form.dtoPack = `${basePack}.dto.${module}`
form.controllerPack = `${basePack}.controller`
form.requestPath = `/${module}`
form.vueApiPath = `/api/${module}`
genPackFlag = true
}
function handleCancel() {
resetForm()
visible.value = false
}
function resetForm() {
nextTick(() => {
formRef.resetFields()
})
}
defineExpose({
show,
})
</script>
<style scoped></style>

View File

@@ -0,0 +1,93 @@
<template>
<div>
<div class="m-3 p-3 pt-5 bg-white">
<b-query v-model="model.queryParam" :fields="fields" :default-item-md="8" @query="queryPage" @reset="resetQueryParams" />
</div>
<div class="m-3 p-3 bg-white">
<vxe-toolbar ref="xToolbar" custom zoom :refresh="{ query: queryPage }" />
<vxe-table ref="xTable" row-id="id" :loading="loading" :data="pagination.records">
<vxe-column type="seq" title="序号" width="60" />
<vxe-column field="tableName" title="表名称" />
<vxe-column field="engine" title="引擎类型" />
<vxe-column field="tableComment" title="表表述" />
<vxe-column field="createTime" title="创建时间" />
<vxe-column fixed="right" width="120" :showOverflow="false" title="操作">
<template #default="{ row }">
<!-- <a href="javascript:" @click="previewShow(row)">预览</a>-->
<!-- <a-divider type="vertical" />-->
<a href="javascript:" @click="generateShow(row)">生成</a>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
:loading="loading"
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@page-change="handleTableChange"
/>
<code-gen-form ref="codeGenForm" @down="generate" @preview="preview" />
</div>
</div>
</template>
<script lang="ts" setup>
import CodeGenForm from './CodeGenForm.vue'
import { QueryField, STRING } from '/@/components/Bootx/Query/Query'
import useTablePage from '/@/hooks/bootx/useTablePage'
import { $ref } from 'vue/macros'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
import { onMounted } from 'vue'
import { codeGenPreview, genCodeZip, page } from './CodeGen.api'
import { downloadByData } from '/@/utils/file/download'
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
const { handleTableChange, resetQueryParams, pageQueryResHandel, pagination, pages, model, loading } = useTablePage(queryPage)
const fields = [
// { field: 'tableName', type: STRING, name: '名称', placeholder: '请输入表名称' },
// { field: 'tableComment', type: STRING, name: '描述', placeholder: '请输入表描述' },
] as QueryField[]
let xTable = $ref<VxeTableInstance>()
let xToolbar = $ref<VxeToolbarInstance>()
let codeGenForm = $ref<any>()
onMounted(() => {
vxeBind()
queryPage()
})
function vxeBind() {
xTable.connect(xToolbar)
}
// 分页查询
function queryPage() {
loading.value = true
page({
...model.queryParam,
...pages,
}).then(({ data }) => {
pageQueryResHandel(data)
})
}
// 预览代码
function preview(from) {
codeGenPreview(from).then((res) => {
console.log(res.data)
})
}
// 打开预览
function generateShow(record) {
codeGenForm.show(record.tableName, 'down')
}
// 生成代码
function generate(from) {
genCodeZip(from).then((response) => {
downloadByData(response, from.tableName + '.zip')
})
}
</script>
<style scoped></style>

View File

@@ -0,0 +1,5 @@
<template> </template>
<script lang="ts" setup></script>
<style scoped></style>

View File

@@ -65,7 +65,7 @@
import useTablePage from '/@/hooks/bootx/useTablePage'
import ClientEdit from './ClientEdit.vue'
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { STRING } from '/@/components/Bootx/Query/Query'
import { FormEditType } from '/@/enums/formTypeEnum'
import { useMessage } from '/@/hooks/web/useMessage'
import { $ref } from 'vue/macros'

View File

@@ -73,7 +73,7 @@
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { FormEditType } from '/@/enums/formTypeEnum'
import { useMessage } from '/@/hooks/web/useMessage'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { STRING } from '/@/components/Bootx/Query/Query'
import { $ref } from 'vue/macros'
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'

View File

@@ -16,7 +16,7 @@ export const menuTree = (clientCode: string) => {
* 获取单条
*/
export const get = (id) => {
return defHttp.get<Result<Menu>>({
return defHttp.get<Result<Menu | Resource>>({
url: '/perm/menu/findById',
params: { id },
})
@@ -25,7 +25,7 @@ export const get = (id) => {
/**
* 添加
*/
export const add = (obj: Menu) => {
export const add = (obj: Menu | Resource) => {
return defHttp.post({
url: '/perm/menu/add',
data: obj,
@@ -35,7 +35,7 @@ export const add = (obj: Menu) => {
/**
* 更新
*/
export const update = (obj: Menu) => {
export const update = (obj: Menu | Resource) => {
return defHttp.post({
url: '/perm/menu/update',
data: obj,

View File

@@ -142,7 +142,7 @@
if ([FormEditType.Edit, FormEditType.Show].includes(editType)) {
confirmLoading.value = true
get(id).then(({ data }) => {
form = data
form = data as Menu
confirmLoading.value = false
})
// 新增
@@ -162,7 +162,7 @@
// 复制
const { data } = await get(id)
delete data.id
form = data
form = data as Menu
confirmLoading.value = false
}
}

View File

@@ -1,20 +1,37 @@
<template>
<a-modal :title="title" :width="720" :visible="visible" :maskClosable="false" @cancel="handleCancel">
<a-spin :spinning="confirmLoading" />
<basic-modal :loading="confirmLoading" v-bind="$attrs" :title="title" :visible="visible" :mask-closable="showable" @cancel="handleCancel">
<a-form class="small-from-item" :model="form" ref="formRef" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-form-item label="主键" :hidden="true">
<a-input v-model:value="form.id" :disabled="showable" />
</a-form-item>
<a-form-item label="编码" name="permCode">
<a-input v-model:value="form.permCode" :disabled="showable" placeholder="请输入编码" />
</a-form-item>
<a-form-item label="名称" name="title">
<a-input v-model:value="form.title" :disabled="showable" placeholder="请输入名称" />
</a-form-item>
<a-form-item label="是否有效" name="effect">
<a-switch :disabled="showable" checkedChildren="是" unCheckedChildren="否" v-model:checked="form.effect" />
</a-form-item>
<a-form-item label="说明" name="remark">
<a-textarea v-model:value="form.remark" :disabled="showable" placeholder="请输入说明" />
</a-form-item>
</a-form>
<template #footer>
<a-button key="cancel" @click="handleCancel">取消</a-button>
<a-button v-if="!showable" key="forward" :loading="confirmLoading" type="primary" @click="handleOk">保存</a-button>
</template>
</a-modal>
</basic-modal>
</template>
<script lang="ts" setup>
import useFormEdit from '/@/hooks/bootx/useFormEdit'
import { FormEditType } from '/@/enums/formTypeEnum'
import { FormInstance } from 'ant-design-vue/lib/form'
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { $ref } from 'vue/macros'
import { nextTick } from 'vue'
import { add, get, update } from '/@/views/modules/system/loginType/LoginType.api'
import { add, get, Resource, update } from './Menu.api'
import { BasicModal } from '/@/components/Modal/'
const { initFormModel, handleCancel, search, labelCol, wrapperCol, title, confirmLoading, visible, editable, showable, formEditType } =
useFormEdit()
@@ -28,15 +45,21 @@
menuType: 2,
sortNo: 0,
remark: '',
})
} as Resource)
const rules = {
title: [{ required: true, message: '请输入权限名称', trigger: ['blur', 'change'] }],
permCode: [{ required: true, message: '请输入权限编码', trigger: ['blur', 'change'] }],
effect: [{ required: true, message: '' }],
} as Record<string, Rule[]>
const formRef: FormInstance = $ref()
// 事件
const emits = defineEmits(['ok'])
// 入口
function init(id, editType: FormEditType) {
function init(id, editType: FormEditType, clientCode) {
initFormModel(id, editType)
resetForm()
form.clientCode = clientCode
getInfo(id, editType)
}
@@ -45,7 +68,7 @@
if ([FormEditType.Edit, FormEditType.Show].includes(editType)) {
confirmLoading.value = true
get(id).then(({ data }) => {
form.value = data
form = data as Resource
confirmLoading.value = false
})
} else {
@@ -57,9 +80,9 @@
formRef.validate().then(async () => {
confirmLoading.value = true
if (formEditType.value === FormEditType.Add) {
await add(form.value)
await add(form)
} else if (formEditType.value === FormEditType.Edit) {
await update(form.value)
await update(form)
}
confirmLoading.value = false
handleCancel()

View File

@@ -97,7 +97,7 @@
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { FormEditType } from '/@/enums/formTypeEnum'
import { useMessage } from '/@/hooks/web/useMessage'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { STRING } from '/@/components/Bootx/Query/Query'
import Icon from '/@/components/Icon/src/Icon.vue'
// 使用hooks

View File

@@ -56,7 +56,7 @@
import { FormEditType } from '/@/enums/formTypeEnum'
import { useMessage } from '/@/hooks/web/useMessage'
import { $ref } from 'vue/macros'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { QueryField, STRING } from '/@/components/Bootx/Query/Query'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)
@@ -65,7 +65,7 @@
const fields = [
{ field: 'code', type: STRING, name: '角色编号', placeholder: '请输入角色编码' },
{ field: 'name', type: STRING, name: '角色名称', placeholder: '请输入角色名称' },
]
] as QueryField[]
let xTable = $ref<VxeTableInstance>()
let xToolbar = $ref<VxeToolbarInstance>()

View File

@@ -50,7 +50,7 @@
import { FormInstance, Rule } from 'ant-design-vue/lib/form'
import { FormEditType } from '/@/enums/formTypeEnum'
import { BasicModal } from '/@/components/Modal'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { STRING } from '/@/components/Bootx/Query/Query'
import { existsByCode, existsByCodeNotId, existsByName, existsByNameNotId } from '/@/views/modules/system/role/Role.api'
const {

View File

@@ -57,7 +57,7 @@
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
import { FormEditType } from '/@/enums/formTypeEnum'
import { useMessage } from '/@/hooks/web/useMessage'
import { STRING } from '/@/components/Bootx/Query/SuperQueryCode'
import { STRING } from '/@/components/Bootx/Query/Query'
// 使用hooks
const { handleTableChange, pageQueryResHandel, resetQueryParams, pagination, pages, model, loading } = useTablePage(queryPage)