This commit is contained in:
孟帅
2023-02-23 17:53:04 +08:00
parent 7cf1b8ce8e
commit 61d0988d2c
402 changed files with 18340 additions and 35547 deletions

View File

@@ -0,0 +1,23 @@
import { cloneDeep } from 'lodash-es';
export const genInfoObj = {
label: '',
name: '',
group: 1,
version: 'v1.0.0',
brief: '',
description: '',
author: '',
};
export const selectListObj = {
groupType: [],
status: [],
};
export function newState(state) {
if (state !== null) {
return cloneDeep(state);
}
return cloneDeep(genInfoObj);
}

View File

@@ -0,0 +1,502 @@
<template>
<div>
<div class="n-layout-page-header">
<n-card :bordered="false" title="插件管理">
在这里可以管理和创建插件模板开发独立临时性工具类型的功能时推荐使用插件化开发
</n-card>
</div>
<n-card :bordered="false" class="proCard">
<BasicForm
@register="register"
@submit="handleSubmit"
@reset="handleReset"
ref="searchFormRef"
>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1090"
>
<template #tableTitle>
<n-button type="primary" @click="addTable">
<template #icon>
<n-icon>
<PlusOutlined />
</n-icon>
</template>
创建新插件
</n-button>
</template>
</BasicTable>
<n-modal
v-model:show="showModal"
:show-icon="false"
preset="dialog"
title="创建新插件"
:style="{
width: dialogWidth,
}"
>
<n-alert :show-icon="false" type="info">
注意:插件创建成功后会在服务端对应的项目目录中创建插件模块,并自动注册到当前项目中。
</n-alert>
<n-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
>
<n-form-item label="插件标签" path="label">
<n-input placeholder="请输入" v-model:value="formParams.label" />
<template #feedback>显示在插件列表中的标识. 不要超过20个字符</template>
</n-form-item>
<n-form-item label="插件包名" path="name">
<n-input placeholder="请输入" v-model:value="formParams.name" />
<template #feedback>
系统按照此名称创建和查找插件定义, 只能英文和下划线组成建议全部小写例如hgexample
</template>
</n-form-item>
<n-form-item label="功能分组" path="group">
<n-select
placeholder="请选择"
:options="selectList.groupType"
v-model:value="formParams.group"
:on-update:value="onUpdateValueGroup"
/>
</n-form-item>
<n-form-item label="版本" path="version">
<n-input placeholder="请输入" v-model:value="formParams.version" />
<template #feedback>此版本号用于插件的版本更新</template>
</n-form-item>
<n-form-item label="简介" path="brief">
<n-input placeholder="请输入" v-model:value="formParams.brief" />
</n-form-item>
<n-form-item label="使用说明" path="description">
<n-input
type="textarea"
placeholder="使用说明"
v-model:value="formParams.description"
/>
<template #feedback>详细介绍插件的功能和使用方法</template>
</n-form-item>
<n-form-item label="作者" path="author">
<n-input placeholder="请输入" v-model:value="formParams.author" />
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showModal = false)">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确认创建</n-button>
</n-space>
</template>
</n-modal>
</n-card>
</div>
</template>
<script lang="ts" setup>
import { h, onBeforeMount, reactive, ref } from 'vue';
import {
NIcon,
NTag,
NIconWrapper,
useMessage,
NImage,
useDialog,
useNotification,
} from 'naive-ui';
import { BasicTable, TableAction } from '@/components/Table';
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
import { List, Selects, Build, UnInstall, Install, Upgrade } from '@/api/develop/addons';
import { PlusOutlined } from '@vicons/antd';
import { newState } from '@/views/develop/addons/components/model';
import { errorImg } from '@/utils/hotgo';
import { isUrl } from '@/utils/is';
import { getIconComponent } from '@/utils/icons';
const selectList = ref({
groupType: [],
status: [],
});
const columns = [
{
title: '图标',
key: 'logo',
width: 80,
render(row) {
if (isUrl(row.logo)) {
return h(NImage, {
width: 48,
height: 48,
src: row.logo,
onError: errorImg,
style: {
width: '48px',
height: '48px',
'max-width': '100%',
'max-height': '100%',
},
});
} else {
return h(
NIconWrapper,
{
size: 48,
borderRadius: 8,
},
{
default: () =>
h(
NIcon,
{
size: 36,
style: {
marginTop: '-8px',
},
},
{
default: () => h(getIconComponent(row.logo)),
}
),
}
);
}
},
},
{
title: '模块名称',
key: 'name',
width: 120,
render(row) {
return h('div', {
innerHTML:
'<div >' + row.label + '<br><span style="opacity: 0.8;">' + row.name + '</span></div>',
});
},
},
{
title: '作者',
key: 'author',
width: 100,
},
{
title: '分组',
key: 'groupName',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: 'info',
bordered: false,
},
{
default: () => row.groupName,
}
);
},
width: 120,
},
{
title: '简介',
key: 'brief',
render(row) {
return row.brief;
},
width: 180,
},
{
title: '详细描述',
key: 'description',
width: 300,
render(row) {
return h('p', { id: 'app' }, [
h('div', {
innerHTML: '<div style="white-space: pre-wrap">' + row.description + '</div>',
}),
]);
},
},
{
title: '版本',
key: 'version',
width: 100,
},
];
const checkedIds = ref([]);
const searchFormRef = ref<any>();
const schemas = ref<FormSchema[]>([
{
field: 'name',
component: 'NInput',
label: '模块名称',
componentProps: {
placeholder: '请输入模块名称或标签',
onInput: (e: any) => {
console.log(e);
},
},
rules: [{ trigger: ['blur'] }],
},
{
field: 'group',
component: 'NSelect',
label: '分组',
componentProps: {
placeholder: '请选择分组',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
{
field: 'status',
component: 'NSelect',
label: '安装状态',
componentProps: {
placeholder: '请选择状态',
options: [],
onUpdateValue: (e: any) => {
console.log(e);
},
},
},
]);
const notification = useNotification();
const dialog = useDialog();
const showModal = ref(false);
const formBtnLoading = ref(false);
const formRef: any = ref(null);
const message = useMessage();
const actionRef = ref();
const formParams = ref<any>();
const rules = {};
const actionColumn = reactive({
width: 220,
title: '操作',
key: 'action',
// fixed: 'right',
render(record) {
return h(TableAction as any, {
style: 'button',
actions: [
{
label: '安装模块',
onClick: handleInstall.bind(null, record),
ifShow: () => {
return record.installStatus !== 1;
},
},
{
type: 'warning',
label: '更新配置',
onClick: handleUpgrade.bind(null, record),
ifShow: () => {
return record.installStatus === 1;
},
},
{
type: 'error',
label: '卸载模块',
onClick: handleUnInstall.bind(null, record),
ifShow: () => {
return record.installStatus === 1;
},
},
],
});
},
});
const [register, {}] = useForm({
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
labelWidth: 80,
schemas,
});
function onCheckedRow(rowKeys) {
checkedIds.value = rowKeys;
}
const loadDataTable = async (res) => {
mapWidth();
return await List({ ...res, ...searchFormRef.value?.formModel });
};
function reloadTable() {
actionRef.value.reload();
}
function handleInstall(record: Recordable) {
dialog.info({
title: '提示',
content: '你确定要安装 【' + record.label + '】 模块?安装成功后需要重启服务才能生效!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Install(record).then((_res) => {
message.success('操作成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function handleUpgrade(record: Recordable) {
dialog.warning({
title: '提示',
content: '你确定要更新 【' + record.label + '】 模块?更新成功后需要重启服务才能生效!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
Upgrade(record).then((_res) => {
message.success('操作成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function handleUnInstall(record: Recordable) {
dialog.error({
title: '提示',
content: '你确定要卸载 【' + record.label + '】 模块?卸载成功后需要重启服务才能生效!',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
UnInstall(record).then((_res) => {
message.success('操作成功');
reloadTable();
});
},
onNegativeClick: () => {
// message.error('取消');
},
});
}
function handleSubmit(_values: Recordable) {
reloadTable();
}
function handleReset(_values: Recordable) {
reloadTable();
}
function addTable() {
showModal.value = true;
formParams.value = newState(null);
}
function confirmForm(e) {
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
if (!errors) {
console.log('formParams:' + JSON.stringify(formParams.value));
Build(formParams.value).then((_res) => {
showModal.value = false;
buildSuccessNotify();
});
} else {
message.error('请填写完整信息');
}
formBtnLoading.value = false;
});
}
const dialogWidth = ref('50%');
function mapWidth() {
let val = document.body.clientWidth;
const def = 840; // 默认宽度
if (val < def) {
dialogWidth.value = '100%';
} else {
dialogWidth.value = def + 'px';
}
return dialogWidth.value;
}
onBeforeMount(async () => {
await loadSelect();
});
const loadSelect = async () => {
selectList.value = await Selects({});
for (const item of schemas.value) {
switch (item.field) {
case 'status':
item.componentProps.options = selectList.value.status;
break;
case 'group':
item.componentProps.options = selectList.value.groupType;
break;
}
}
};
function onUpdateValueGroup(value) {
formParams.value.group = value;
}
function buildSuccessNotify() {
let count = 10;
const n = notification.success({
title: '插件构建成功',
content: `如果你使用的热编译,页面将在 ${count} 秒后自动刷新插件列表即可生效。否则请手动重启服务后刷新页面!`,
duration: 10000,
closable: false,
onAfterEnter: () => {
const minusCount = () => {
count--;
n.content = `如果你使用的热编译,页面将在 ${count} 秒后自动刷新插件列表即可生效。否则请手动重启服务后刷新页面!`;
if (count > 0) {
window.setTimeout(minusCount, 1000);
}
};
window.setTimeout(minusCount, 1000);
},
onAfterLeave: () => {
location.reload();
},
});
}
</script>
<style lang="less" scoped></style>

View File

@@ -1,306 +1,311 @@
<template>
<div>
<n-card
:bordered="true"
title="基本设置"
class="proCard mt-2"
size="small"
:segmented="{ content: true }"
>
<n-form ref="formRef" :model="formValue">
<n-row :gutter="24">
<n-col :span="6" style="min-width: 200px">
<n-form-item label="生成类型" path="title">
<n-select
placeholder="请选择"
:options="selectList.genType"
v-model:value="formValue.genType"
/>
</n-form-item>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item label="实体命名" path="varName">
<n-input placeholder="请输入" v-model:value="formValue.varName" />
</n-form-item>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item
label="数据库"
path="dbName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-select
placeholder="请选择"
:options="selectList.db"
v-model:value="formValue.dbName"
@update:value="handleDbUpdateValue"
/>
</n-form-item>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item
label="数据库表"
path="tableName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="tablesOption"
v-model:value="formValue.tableName"
@update:value="handleTableUpdateValue"
:disabled="formValue.dbName === ''"
/>
</n-form-item>
</n-col>
<n-col :span="18">
<n-form-item
label="表格头部按钮组"
path="tableName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.headOps">
<n-space item-style="display: flex;">
<n-checkbox value="add" label="新增表单按钮" />
<n-checkbox value="batchDel" label="批量删除按钮" />
<n-checkbox value="export" label="导出按钮" />
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col :span="24">
<n-form-item
label="表格列操作"
path="columnOps"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.columnOps">
<n-space item-style="display: flex;">
<n-checkbox value="edit" label="编辑" />
<n-checkbox value="status" label="状态修改" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>主表中存在`status`字段时才会生效</span>
</n-popover>
<n-checkbox value="del" label="删除" />
<n-checkbox value="view" label="详情页" />
<n-checkbox value="check" label="开启勾选列" />
<n-checkbox value="switch" label="操作开关" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>主表中存在`switch`字段时才会生效</span>
</n-popover>
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col :span="24">
<n-form-item
label="自动化操作"
path="autoOps"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.autoOps">
<n-space item-style="display: flex;">
<n-checkbox value="genMenuPermissions" label="生成菜单权限" />
<n-checkbox value="runDao" label="生成前运行 [gf gen dao]" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>请确保运行环境已安装gf命令</span>
</n-popover>
<n-checkbox value="runService" label="生成后运行 [gf gen service]" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>请确保运行环境已安装gf命令</span>
</n-popover>
<n-checkbox value="forcedCover" label="强制覆盖" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>只会强制覆盖需要生成的文件但不包含SQL文件</span>
</n-popover>
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="上级菜单" path="pid">
<n-tree-select
:options="optionMenuTree"
:value="formValue.options.menu.pid"
@update:value="handleUpdateMenuPid"
/>
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单名称" path="tableComment">
<n-input placeholder="请输入" v-model:value="formValue.tableComment" />
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单图标" path="menuIcon">
<IconSelector style="width: 100%" v-model:value="formValue.options.menu.icon" />
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单排序" path="menuIcon">
<n-input-number
style="width: 100%"
placeholder="请输入"
v-model:value="formValue.options.menu.sort"
clearable
/>
</n-form-item>
</n-col>
</n-row>
</n-form>
</n-card>
<n-card
:bordered="true"
title="关联表设置"
class="proCard mt-2"
size="small"
:segmented="{ content: true }"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<template #header-extra>
<n-space>
<n-button type="warning" @click="addJoin" :disabled="formValue.options?.join?.length >= 3"
>新增关联表</n-button
>
</n-space>
</template>
<n-form ref="formRef" :model="formValue">
<n-alert :show-icon="false">关联表数量建议在三个以下</n-alert>
<n-row :gutter="6" v-for="(join, index) in formValue.options.join" :key="index">
<n-col :span="6" style="min-width: 200px">
<n-form-item label="关联表" path="join.linkTable">
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="linkTablesOption"
v-model:value="join.linkTable"
@update:value="handleLinkTableUpdateValue(join)"
:disabled="formValue.dbName === ''"
/>
</n-form-item>
</n-col>
<n-col :span="3" style="min-width: 100px">
<n-form-item
label="别名"
path="join.alias"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-input
placeholder="请输入"
v-model:value="join.alias"
@update:value="updateJoinAlias"
/>
<template #feedback> {{ joinAliasFeedback }}</template>
</n-form-item>
</n-col>
<n-col :span="3" style="min-width: 100px">
<n-form-item label="关联方式" path="join.linkMode">
<n-select
placeholder="请选择"
:options="selectList.linkMode"
v-model:value="join.linkMode"
/>
</n-form-item>
</n-col>
<n-col :span="5" style="min-width: 180px">
<n-form-item label="关联字段" path="join.field">
<n-select
filterable
tag
:loading="linkColumnsLoading"
placeholder="请选择"
:options="linkColumnsOption[join.uuid]"
v-model:value="join.field"
/>
</n-form-item>
</n-col>
<n-col :span="5" style="min-width: 180px">
<n-form-item label="主表关联字段" path="join.masterField">
<n-select
filterable
tag
:loading="columnsLoading"
placeholder="请选择"
:options="columnsOption"
v-model:value="join.masterField"
/>
</n-form-item>
</n-col>
<n-col :span="2" style="min-width: 50px">
<n-space>
<n-form-item label="操作" path="title">
<n-button @click="delJoin(join, index)" size="small" strong secondary type="error"
>移除</n-button
>
<n-spin :show="bodyShow" description="请稍候...">
<n-card
:bordered="true"
title="基本设置"
class="proCard mt-2"
size="small"
:segmented="{ content: true }"
>
<n-form ref="formRef" :model="formValue">
<n-row :gutter="24">
<n-col :span="6" style="min-width: 200px">
<n-form-item label="生成类型" path="title">
<n-select
placeholder="请选择"
:options="selectList.genType"
v-model:value="formValue.genType"
/>
</n-form-item>
</n-space>
</n-col>
</n-row>
</n-form>
</n-card>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item label="实体命名" path="varName">
<n-input placeholder="请输入" v-model:value="formValue.varName" />
</n-form-item>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item
label="数据库"
path="dbName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-select
placeholder="请选择"
:options="selectList.db"
v-model:value="formValue.dbName"
@update:value="handleDbUpdateValue"
/>
</n-form-item>
</n-col>
<n-col :span="6" style="min-width: 200px">
<n-form-item
label="数据库表"
path="tableName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="tablesOption"
v-model:value="formValue.tableName"
@update:value="handleTableUpdateValue"
:disabled="formValue.dbName === ''"
/>
</n-form-item>
</n-col>
<n-col :span="18">
<n-form-item
label="表格头部按钮组"
path="tableName"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.headOps">
<n-space item-style="display: flex;">
<n-checkbox value="add" label="新增表单按钮" />
<n-checkbox value="batchDel" label="批量删除按钮" />
<n-checkbox value="export" label="导出按钮" />
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col :span="24">
<n-form-item
label="表格列操作"
path="columnOps"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.columnOps">
<n-space item-style="display: flex;">
<n-checkbox value="edit" label="编辑" />
<n-checkbox value="status" label="状态修改" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>主表中存在`status`字段时才会生效</span>
</n-popover>
<n-checkbox value="del" label="删除" />
<n-checkbox value="view" label="详情页" />
<n-checkbox value="check" label="开启勾选列" />
<n-checkbox value="switch" label="操作开关" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>主表中存在`switch`字段时才会生效</span>
</n-popover>
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col :span="24">
<n-form-item
label="自动化操作"
path="autoOps"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-checkbox-group v-model:value="formValue.options.autoOps">
<n-space item-style="display: flex;">
<n-checkbox value="genMenuPermissions" label="生成菜单权限" />
<n-checkbox value="runDao" label="生成前运行 [gf gen dao]" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>如果你选择的表已经生成过dao相关代码可以忽略</span>
</n-popover>
<n-checkbox value="runService" label="生成后运行 [gf gen service]" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>如果是插件模块勾选后也会自动在对应插件下运行service相关代码生成</span>
</n-popover>
<n-checkbox value="forcedCover" label="强制覆盖" />
<n-popover trigger="hover">
<template #trigger>
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
<QuestionCircleOutlined />
</n-icon>
</template>
<span>只会强制覆盖需要生成的文件但不包含SQL文件</span>
</n-popover>
</n-space>
</n-checkbox-group>
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="上级菜单" path="pid">
<n-tree-select
:options="optionMenuTree"
:value="formValue.options.menu.pid"
@update:value="handleUpdateMenuPid"
/>
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单名称" path="tableComment">
<n-input placeholder="请输入" v-model:value="formValue.tableComment" />
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单图标" path="menuIcon">
<IconSelector style="width: 100%" v-model:value="formValue.options.menu.icon" />
</n-form-item>
</n-col>
<n-col
:span="6"
style="min-width: 200px"
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
>
<n-form-item label="菜单排序" path="menuIcon">
<n-input-number
style="width: 100%"
placeholder="请输入"
v-model:value="formValue.options.menu.sort"
clearable
/>
</n-form-item>
</n-col>
</n-row>
</n-form>
</n-card>
<n-card
:bordered="true"
title="关联表设置"
class="proCard mt-2"
size="small"
:segmented="{ content: true }"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<template #header-extra>
<n-space>
<n-button
type="warning"
@click="addJoin"
:disabled="formValue.options?.join?.length >= 3"
>新增关联表</n-button
>
</n-space>
</template>
<n-form ref="formRef" :model="formValue">
<n-alert :show-icon="false">关联表数量建议在三个以下</n-alert>
<n-row :gutter="6" v-for="(join, index) in formValue.options.join" :key="index">
<n-col :span="6" style="min-width: 200px">
<n-form-item label="关联表" path="join.linkTable">
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="linkTablesOption"
v-model:value="join.linkTable"
@update:value="handleLinkTableUpdateValue(join)"
:disabled="formValue.dbName === ''"
/>
</n-form-item>
</n-col>
<n-col :span="3" style="min-width: 100px">
<n-form-item
label="别名"
path="join.alias"
v-show="formValue.genType >= 10 && formValue.genType < 20"
>
<n-input
placeholder="请输入"
v-model:value="join.alias"
@update:value="updateJoinAlias"
/>
<template #feedback> {{ joinAliasFeedback }}</template>
</n-form-item>
</n-col>
<n-col :span="3" style="min-width: 100px">
<n-form-item label="关联方式" path="join.linkMode">
<n-select
placeholder="请选择"
:options="selectList.linkMode"
v-model:value="join.linkMode"
/>
</n-form-item>
</n-col>
<n-col :span="5" style="min-width: 180px">
<n-form-item label="关联字段" path="join.field">
<n-select
filterable
tag
:loading="linkColumnsLoading"
placeholder="请选择"
:options="linkColumnsOption[join.uuid]"
v-model:value="join.field"
/>
</n-form-item>
</n-col>
<n-col :span="5" style="min-width: 180px">
<n-form-item label="主表关联字段" path="join.masterField">
<n-select
filterable
tag
:loading="columnsLoading"
placeholder="请选择"
:options="columnsOption"
v-model:value="join.masterField"
/>
</n-form-item>
</n-col>
<n-col :span="2" style="min-width: 50px">
<n-space>
<n-form-item label="操作" path="title">
<n-button @click="delJoin(join, index)" size="small" strong secondary type="error"
>移除</n-button
>
</n-form-item>
</n-space>
</n-col>
</n-row>
</n-form>
</n-card>
</n-spin>
</div>
</template>
@@ -316,7 +321,9 @@
import { cloneDeep } from 'lodash-es';
import { isLetterBegin } from '@/utils/is';
const timer = ref();
const formRef = ref<FormInst | null>(null);
const bodyShow = ref(true);
const tablesLoading = ref(false);
const columnsLoading = ref(false);
const linkColumnsLoading = ref(false);
@@ -364,12 +371,16 @@
});
onMounted(() => {
setTimeout(async function () {
await instLoad();
// 切换tab时会导致选项被清空这里重新进行加载
await loadLinkColumnsOption();
await loadMenuTreeOption();
}, 500);
timer.value = setInterval(async () => {
if (props.value.id > 0) {
clearTimeout(timer.value);
await instLoad();
// 切换tab时会导致选项被清空这里重新进行加载
await loadLinkColumnsOption();
await loadMenuTreeOption();
bodyShow.value = false;
}
}, 30);
});
const loadMenuTreeOption = async () => {

View File

@@ -38,6 +38,7 @@ export const genInfoObj = {
tableComment: '',
daoName: '',
masterColumns: [],
addonName: null,
status: 2,
createdAt: '',
updatedAt: '',

View File

@@ -82,7 +82,7 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useDialog, useMessage } from 'naive-ui';
import { useDialog, useMessage, useNotification } from 'naive-ui';
import BaseInfo from './components/BaseInfo.vue';
import EditMasterCell from './components/EditMasterCell.vue';
import EditSlaveCell from './components/EditSlaveCell.vue';
@@ -110,6 +110,7 @@
const formBtnLoading = ref(false);
const previewModel = ref<any>();
const dialog = useDialog();
const notification = useNotification();
onMounted(async () => {
if (genId < 1 && props.genId < 1) {
@@ -181,15 +182,6 @@
}
}
function _handleSlaveClose(name: string) {
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
if (!~nameIndex) return;
panels.value.splice(nameIndex, 1);
if (name === value.value) {
value.value = panels.value[Math.min(nameIndex, panels.value.length - 1)];
}
}
function handleClose(name: string) {
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
if (!~nameIndex) return;
@@ -218,10 +210,7 @@
formBtnLoading.value = true;
Build(genInfo.value)
.then((_res) => {
setTimeout(function () {
location.reload();
}, 1500);
message.success('生成提交成功,即将刷新页面..');
buildSuccessNotify();
})
.finally(() => {
formBtnLoading.value = false;
@@ -249,6 +238,29 @@
},
});
}
function buildSuccessNotify() {
let count = 6;
const n = notification.success({
title: '生成提交成功',
content: `如果你使用的热编译,页面将在 ${count} 秒后自动刷新即可生效。否则请手动重启服务后刷新页面!`,
duration: 6000,
closable: false,
onAfterEnter: () => {
const minusCount = () => {
count--;
n.content = `如果你使用的热编译,页面将在 ${count} 秒后自动刷新即可生效。否则请手动重启服务后刷新页面!`;
if (count > 0) {
window.setTimeout(minusCount, 1000);
}
};
window.setTimeout(minusCount, 1000);
},
onAfterLeave: () => {
location.reload();
},
});
}
</script>
<style lang="less" scoped>
::v-deep(.alert-margin) {

View File

@@ -1,130 +1,145 @@
<template>
<n-card :bordered="false" class="proCard" title="代码生成">
<!-- <n-card :bordered="false" title="代码生成"> 你可以在这里查看到平台所有的短信发送记录 </n-card>-->
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" ref="searchFormRef">
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1090"
>
<template #tableTitle>
<n-button type="primary" @click="addTable">
<template #icon>
<n-icon>
<PlusOutlined />
</n-icon>
</template>
立即生成
</n-button>
&nbsp;
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
<template #icon>
<n-icon>
<DeleteOutlined />
</n-icon>
</template>
批量删除
</n-button>
</template>
</BasicTable>
<n-modal
v-model:show="showModal"
:show-icon="false"
preset="dialog"
title="立即生成"
:style="{
width: dialogWidth,
}"
>
<!-- <n-alert :show-icon="false" type="info">-->
<!-- 注意:!-->
<!-- </n-alert>-->
<n-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
<div>
<n-card :bordered="false" class="proCard" title="代码生成">
<BasicForm
@register="register"
@submit="handleSubmit"
@reset="handleReset"
ref="searchFormRef"
>
<n-form-item label="生成类型" path="genType">
<n-select
placeholder="请选择"
:options="selectList.genType"
v-model:value="formParams.genType"
:on-update:value="onUpdateValueGenType"
/>
</n-form-item>
<template #statusSlot="{ model, field }">
<n-input v-model:value="model[field]" />
</template>
</BasicForm>
<n-form-item label="生成模板" path="genTemplate">
<n-select
placeholder="请选择"
:options="genTemplateOptions"
v-model:value="formParams.genTemplate"
:onFocus="onFocusGenTemplate"
/>
</n-form-item>
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="actionRef"
:actionColumn="actionColumn"
@update:checked-row-keys="onCheckedRow"
:scroll-x="1090"
>
<template #tableTitle>
<n-button type="primary" @click="addTable">
<template #icon>
<n-icon>
<PlusOutlined />
</n-icon>
</template>
立即生成
</n-button>
&nbsp;
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
<template #icon>
<n-icon>
<DeleteOutlined />
</n-icon>
</template>
批量删除
</n-button>
</template>
</BasicTable>
<n-form-item
label="数据库"
path="dbName"
v-if="formParams.genType >= 10 && formParams.genType < 20"
<n-modal
v-model:show="showModal"
:show-icon="false"
preset="dialog"
title="立即生成"
:style="{
width: dialogWidth,
}"
>
<!-- <n-alert :show-icon="false" type="info">-->
<!-- 注意:!-->
<!-- </n-alert>-->
<n-form
:model="formParams"
:rules="rules"
ref="formRef"
label-placement="left"
:label-width="80"
class="py-4"
>
<n-select
placeholder="请选择"
:options="selectList.db"
v-model:value="formParams.dbName"
@update:value="handleDbUpdateValue"
/>
</n-form-item>
<n-form-item
label="数据库表"
path="tableName"
v-if="formParams.genType >= 10 && formParams.genType < 20"
>
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="selectList.tables"
v-model:value="formParams.tableName"
@update:value="handleTableUpdateValue"
:disabled="formParams.dbName === ''"
/>
</n-form-item>
<n-form-item label="生成类型" path="genType">
<n-select
placeholder="请选择"
:options="selectList.genType"
v-model:value="formParams.genType"
:on-update:value="onUpdateValueGenType"
/>
</n-form-item>
<n-form-item
label="菜单名称"
path="tableComment"
v-show="formParams.genType >= 10 && formParams.genType < 20"
>
<n-input placeholder="请输入" v-model:value="formParams.tableComment" />
</n-form-item>
<n-form-item
label="数据库"
path="dbName"
v-if="formParams.genType >= 10 && formParams.genType < 20"
>
<n-select
placeholder="请选择"
:options="selectList.db"
v-model:value="formParams.dbName"
@update:value="handleDbUpdateValue"
/>
</n-form-item>
<n-form-item
label="数据库表"
path="tableName"
v-if="formParams.genType >= 10 && formParams.genType < 20"
>
<n-select
filterable
tag
:loading="tablesLoading"
placeholder="请选择"
:options="selectList.tables"
v-model:value="formParams.tableName"
@update:value="handleTableUpdateValue"
:disabled="formParams.dbName === ''"
/>
</n-form-item>
<n-form-item label="实体命名" path="varName">
<n-input placeholder="请输入" v-model:value="formParams.varName" />
</n-form-item>
</n-form>
<n-form-item label="生成模板" path="genTemplate">
<n-select
placeholder="请选择"
:options="genTemplateOptions"
v-model:value="formParams.genTemplate"
:onFocus="onFocusGenTemplate"
@update:value="handleGenTemplateUpdateValue"
/>
</n-form-item>
<template #action>
<n-space>
<n-button @click="() => (showModal = false)">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">生成配置</n-button>
</n-space>
</template>
</n-modal>
</n-card>
<n-form-item label="选择插件" path="addonName" v-show="selectAddon">
<n-select
placeholder="请选择"
:options="selectList.addons"
v-model:value="formParams.addonName"
/>
</n-form-item>
<n-form-item
label="菜单名称"
path="tableComment"
v-show="formParams.genType >= 10 && formParams.genType < 20"
>
<n-input placeholder="请输入" v-model:value="formParams.tableComment" />
</n-form-item>
<n-form-item label="实体命名" path="varName">
<n-input placeholder="请输入" v-model:value="formParams.varName" />
</n-form-item>
</n-form>
<template #action>
<n-space>
<n-button @click="() => (showModal = false)">取消</n-button>
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">生成配置</n-button>
</n-space>
</template>
</n-modal>
</n-card>
</div>
</template>
<script lang="ts" setup>
@@ -147,75 +162,57 @@
formRole: [],
dictMode: [],
whereMode: [],
addons: [],
});
const columns = [
{
title: '生成ID',
title: 'ID',
key: 'id',
width: 80,
width: 60,
},
{
title: '生成类型',
key: 'genType',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: 'info',
bordered: false,
},
{
default: () => getOptionLabel(selectList.value.genType, row.genType),
}
);
},
width: 180,
},
{
title: '生成模板',
title: '模板',
key: 'genTemplate',
render(row) {
return h(
NTag,
{
style: {
marginRight: '6px',
},
type: 'default',
bordered: false,
},
{
default: () => row.genTemplateGroup,
}
);
return h('p', { id: 'app' }, [
h('div', {
innerHTML: '<div><p>' + row.genTemplateGroup + '</p></div>',
}),
h('div', {
innerHTML:
'<div><p>' + getOptionLabel(selectList.value.genType, row.genType) + '</p></div>',
}),
]);
},
width: 120,
},
{
title: '数据库',
key: 'dbName',
width: 280,
render(row) {
return h('p', { id: 'app' }, [
h('div', {
innerHTML: '<div><p>' + row.dbName + '</p></div>',
}),
h('div', {
innerHTML: '<div><p>' + row.tableName + '</p></div>',
}),
]);
},
},
{
title: '实体命名',
key: 'varName',
render(row) {
return row.varName;
},
width: 180,
},
{
title: '数据库',
key: 'dbName',
width: 150,
},
{
title: '数据表',
key: 'tableName',
width: 200,
width: 140,
},
{
title: '菜单名称',
key: 'tableComment',
width: 200,
width: 140,
},
{
title: '生成状态',
@@ -242,11 +239,6 @@
key: 'createdAt',
width: 180,
},
// {
// title: '更新时间',
// key: 'updatedAt',
// width: 180,
// },
];
const dialog = useDialog();
@@ -409,6 +401,7 @@
e.preventDefault();
formBtnLoading.value = true;
formRef.value.validate((errors) => {
console.log('formParams:' + JSON.stringify(formParams.value));
if (!errors) {
console.log('formParams:' + JSON.stringify(formParams.value));
Edit(formParams.value).then((res) => {
@@ -492,6 +485,12 @@
formParams.value.genType = value;
onFocusGenTemplate();
}
const selectAddon = ref(false);
function handleGenTemplateUpdateValue(value, option) {
formParams.value.genTemplate = value;
selectAddon.value = option.isAddon === true;
}
</script>
<style lang="less" scoped></style>