소스 검색

Merge commit 'refs/pull/486/head' of https://gitee.com/zuohuaijun/Admin.NET into next

zuohuaijun 3 년 전
부모
커밋
94c995d716
36개의 변경된 파일6754개의 추가작업 그리고 752개의 파일을 삭제
  1. 6 0
      .gitignore
  2. 5 0
      Admin.NET/Admin.NET.Core/Admin.NET.Core.xml
  3. 6 0
      Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
  4. 23 23
      Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs
  5. 6 0
      Admin.NET/Admin.NET.Core/Service/DataBase/SysDataBaseService.cs
  6. 3 0
      Admin.NET/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj
  7. 0 0
      Admin.NET/Admin.NET.Web.Entry/Test.db
  8. 46 26
      Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Manage.js.vm
  9. 1 0
      Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm
  10. 209 0
      Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm
  11. 260 123
      Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm
  12. 189 546
      Web/package-lock.json
  13. 1 1
      Web/package.json
  14. 2705 0
      Web/pnpm-lock.yaml
  15. 1 0
      Web/src/api-services/models/update-db-table-input.ts
  16. 40 0
      Web/src/api/main/generatetest.ts
  17. 243 0
      Web/src/api/system/admin.ts
  18. 30 0
      Web/src/api/system/enum.ts
  19. 754 0
      Web/src/api/system/interface.ts
  20. 2 0
      Web/src/main.ts
  21. 1 0
      Web/src/stores/interface/index.ts
  22. 13 0
      Web/src/stores/userInfo.ts
  23. 32 0
      Web/src/utils/helper/constSelectorHelper.ts
  24. 175 21
      Web/src/utils/request.ts
  25. 236 0
      Web/src/utils/ruoyi.js
  26. 235 0
      Web/src/views/system/codeGen/component/codeGenerateDialog.vue
  27. 137 0
      Web/src/views/system/codeGen/component/fkDialog.vue
  28. 284 0
      Web/src/views/system/codeGen/component/generateConfigDialog.vue
  29. 155 0
      Web/src/views/system/codeGen/component/treeDialog.vue
  30. 196 0
      Web/src/views/system/codeGen/index.vue
  31. 201 0
      Web/src/views/system/database/component/addColumn.vue
  32. 380 0
      Web/src/views/system/database/component/addTable.vue
  33. 1 1
      Web/src/views/system/database/component/editTable.vue
  34. 98 0
      Web/src/views/system/database/component/generateEntity.vue
  35. 74 11
      Web/src/views/system/database/index.vue
  36. 6 0
      vue-next-admin/.vscode/settings.json

+ 6 - 0
.gitignore

@@ -29,3 +29,9 @@ dist/
 node_modules/
 /Admin.NET/Admin.NET.Web.Entry/wwwroot/Avatar
 /Admin.NET/Admin.NET.Web.Entry/wwwroot/Signature
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Manage.js - Copy.cshtml
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue - Copy.cshtml
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue - Copy (2).cshtml
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue - Copy.vm
+/Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Manage - Copy.js.vm
+/Admin.NET/Admin.NET.Application/AppConfig.json

+ 5 - 0
Admin.NET/Admin.NET.Core/Admin.NET.Core.xml

@@ -2573,6 +2573,11 @@
             数据表不存在
             </summary>
         </member>
+        <member name="F:Admin.NET.Core.ErrorCodeEnum.db1002">
+            <summary>
+            数据表不存在
+            </summary>
+        </member>
         <member name="F:Admin.NET.Core.ErrorCodeEnum.R2000">
             <summary>
             父节点不存在

+ 6 - 0
Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs

@@ -492,6 +492,12 @@ public enum ErrorCodeEnum
     [ErrorCodeItemMetadata("数据表不存在")]
     db1001,
 
+    /// <summary>
+    /// 数据表不存在
+    /// </summary>
+    [ErrorCodeItemMetadata("不允许添加相同字段名")]
+    db1002,
+
     /// <summary>
     /// 父节点不存在
     /// </summary>

+ 23 - 23
Admin.NET/Admin.NET.Core/Service/CodeGen/SysCodeGenService.cs

@@ -200,28 +200,31 @@ public class SysCodeGenService : IDynamicApiController, ITransient
         // 先删除该表已生成的菜单列表
         var templatePathList = GetTemplatePathList();
         var targetPathList = GetTargetPathList(input);
+
+        var tableFieldList = await _codeGenConfigService.List(new CodeGenConfig() { CodeGenId = input.Id }); // 字段集合
+
+        var queryWhetherList = tableFieldList.Where(u => u.QueryWhether == YesNoEnum.Y.ToString()).ToList(); // 前端查询集合
+        var joinTableList = tableFieldList.Where(u => u.EffectType == "Upload" || u.EffectType == "fk").ToList();// 需要连表查询的字段
+        (string joinTableNames, string lowerJoinTableNames) = GetJoinTableStr(joinTableList);// 获取连表的实体名和别名
+
+        var data = new CustomViewEngine(_db)
+        {
+            ConfigId = input.ConfigId,
+            AuthorName = input.AuthorName,
+            BusName = input.BusName,
+            NameSpace = input.NameSpace,
+            ClassName = input.TableName,
+            ProjectLastName = input.NameSpace.Split('.').Last(),
+            QueryWhetherList = queryWhetherList,
+            TableField = tableFieldList,
+            IsJoinTable = joinTableList.Count > 0,
+            IsUpload = joinTableList.Where(u => u.EffectType == "Upload").Any(),
+        };
+
         for (var i = 0; i < templatePathList.Count; i++)
         {
             var tContent = File.ReadAllText(templatePathList[i]);
 
-            var tableFieldList = await _codeGenConfigService.List(new CodeGenConfig() { CodeGenId = input.Id }); // 字段集合
-            var queryWhetherList = tableFieldList.Where(u => u.QueryWhether == YesNoEnum.Y.ToString()).ToList(); // 前端查询集合
-            var joinTableList = tableFieldList.Where(u => u.EffectType == "Upload" || u.EffectType == "fk").ToList();//需要连表查询的字段
-            (string joinTableNames, string lowerJoinTableNames) = GetJoinTableStr(joinTableList);//获取连表的实体名和别名
-
-            var data = new CustomViewEngine(_db)
-            {
-                ConfigId = input.ConfigId,
-                AuthorName = input.AuthorName,
-                BusName = input.BusName,
-                NameSpace = input.NameSpace,
-                ClassName = input.TableName,
-                ProjectLastName = input.NameSpace.Split('.').Last(),
-                QueryWhetherList = queryWhetherList,
-                TableField = tableFieldList,
-                IsJoinTable = joinTableList.Count > 0,
-                IsUpload = joinTableList.Where(u => u.EffectType == "Upload").Any(),
-            };
             var tResult = _viewEngine.RunCompile<CustomViewEngine>(tContent, data, builderAction: builder =>
             {
                 builder.AddAssemblyReferenceByName("System.Linq");
@@ -397,8 +400,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
             Path.Combine(templatePath , "Output.cs.vm"),
             Path.Combine(templatePath , "Dto.cs.vm"),
             Path.Combine(templatePath , "index.vue.vm"),
-            Path.Combine(templatePath , "data.data.ts.vm"),
-            Path.Combine(templatePath , "dataModal.vue.vm"),
+            Path.Combine(templatePath , "editDialog.vue.vm"),
             Path.Combine(templatePath , "manage.js.vm"),
         };
     }
@@ -417,8 +419,7 @@ public class SysCodeGenService : IDynamicApiController, ITransient
         var viewPath = Path.Combine(backendPath, "Dto", input.TableName + "Dto.cs");
         var frontendPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, _codeGenOptions.FrontRootPath, "src", "views", "main");
         var indexPath = Path.Combine(frontendPath, input.TableName, "index.vue");
-        var formDataPath = Path.Combine(frontendPath, input.TableName, "data.data.ts");
-        var formModalPath = Path.Combine(frontendPath, input.TableName, "dataModal.vue");
+        var formModalPath = Path.Combine(frontendPath, input.TableName, "component", "editDialog.vue");
         var apiJsPath = Path.Combine(new DirectoryInfo(App.WebHostEnvironment.ContentRootPath).Parent.Parent.FullName, _codeGenOptions.FrontRootPath, "src", "api", "main", input.TableName + ".ts");
 
         return new List<string>()
@@ -428,7 +429,6 @@ public class SysCodeGenService : IDynamicApiController, ITransient
             outputPath,
             viewPath,
             indexPath,
-            formDataPath,
             formModalPath,
             apiJsPath
         };

+ 6 - 0
Admin.NET/Admin.NET.Core/Service/DataBase/SysDataBaseService.cs

@@ -32,6 +32,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
     /// <param name="configId">ConfigId</param>
     /// <returns></returns>
     [HttpGet("/sysDatabase/columnList")]
+    [AllowAnonymous]
     public List<DbColumnOutput> GetColumnList(string tableName, string configId = SqlSugarConst.ConfigId)
     {
         var db = _db.AsTenant().GetConnectionScope(configId);
@@ -114,6 +115,11 @@ public class SysDatabaseService : IDynamicApiController, ITransient
         if (input.DbColumnInfoList == null || !input.DbColumnInfoList.Any())
             throw Oops.Oh(ErrorCodeEnum.db1000);
 
+        if (input.DbColumnInfoList.GroupBy(q => q.DbColumnName).Any(q => q.Count() > 1))
+        {
+            throw Oops.Oh(ErrorCodeEnum.db1002);
+        }
+
         input.DbColumnInfoList.ForEach(m =>
         {
             columns.Add(new DbColumnInfo

+ 3 - 0
Admin.NET/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -51,6 +51,9 @@
 		<Content Update="wwwroot\Template\Input.cs.vm">
 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 		</Content>
+		<Content Update="wwwroot\Template\Manage - Copy.js.vm">
+		  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+		</Content>
 		<Content Update="wwwroot\Template\Manage.js.vm">
 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 		</Content>

+ 0 - 0
Admin.NET/Admin.NET.Web.Entry/Test.db


+ 46 - 26
Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Manage.js.vm

@@ -1,4 +1,4 @@
-import { defHttp } from '/@@/utils/http/axios';
+import request from '/@@/utils/request';
 enum Api {
   Add@(@Model.ClassName) = '/@(@Model.ClassName)/add',
   Delete@(@Model.ClassName) = '/@(@Model.ClassName)/delete',
@@ -13,30 +13,50 @@ if(@column.EffectType == "fk"){
 }
 }
 
-//增加@(@Model.BusName)
-export function add@(@Model.ClassName)(params: any) {
-  return defHttp.post<any>({ url: Api.Add@(@Model.ClassName), params });
-}
-//删除@(@Model.BusName)
-export function delete@(@Model.ClassName)(params: any) {
-  return defHttp.post<any>({ url: Api.Delete@(@Model.ClassName), params });
-}
-//编辑@(@Model.BusName)
-export function update@(@Model.ClassName)(params: any) {
-  return defHttp.post<any>({ url: Api.Update@(@Model.ClassName), params });
-}
-//分页查询@(@Model.BusName)
-export function get@(@Model.ClassName)PageList(params?: any) {
-  return defHttp.post<any>({ url: Api.Get@(@Model.ClassName)Page, params });
-}
+// 增加@(@Model.BusName)
+export const add@(@Model.ClassName) = (params?: any) =>
+	request({
+		url: Api.Add@(@Model.ClassName),
+		method: 'post',
+		data: params,
+	});
+
+// 删除@(@Model.BusName)
+export const delete@(@Model.ClassName) = (params?: any) => 
+	request({
+			url: Api.Delete@(@Model.ClassName),
+			method: 'post',
+			data: params,
+		});
+
+// 编辑@(@Model.BusName)
+export const update@(@Model.ClassName) = (params?: any) => 
+	request({
+			url: Api.Update@(@Model.ClassName),
+			method: 'post',
+			data: params,
+		});
+
+// 分页查询@(@Model.BusName)
+export const get@(@Model.ClassName)PageList = (params?: any) => 
+	request({
+			url: Api.Get@(@Model.ClassName)Page,
+			method: 'get',
+			data: params,
+		});
+
 @foreach (var column in Model.TableField){
-if(@column.EffectType == "fk"){
-@:export function get@(@column.FkEntityName)Dropdown() {
-  @:return defHttp.get<any>({ url: Api.Get@(@column.FkEntityName)Dropdown });
-@:}
-}else if(@column.EffectType == "ApiTreeSelect"){
-@:export function get@(@column.FkEntityName)Tree() {
-  @:return defHttp.get<any>({ url: Api.Get@(@column.FkEntityName)Tree });
-@:}
-}
+	if(@column.EffectType == "fk"){
+		@:export const get@(@column.FkEntityName)Dropdown = () =>
+		@:request({
+		@:url: Api.Get@(@column.FkEntityName)Dropdown,
+		@:method: 'get'
+		@:});
+	}else if(@column.EffectType == "ApiTreeSelect"){
+		@:export const get@(@column.FkEntityName)Tree = () =>
+		@:request({
+		@:url: Api.Get@(@column.FkEntityName)Tree,
+		@:method: 'get'
+		@:});
+		}
 }

+ 1 - 0
Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/Service.cs.vm

@@ -1,5 +1,6 @@
 using @(@Model.NameSpace).Const;
 using @(@Model.NameSpace).Entity;
+using Mapster;
 
 namespace @Model.NameSpace;
 /// <summary>

+ 209 - 0
Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/editDialog.vue.vm

@@ -0,0 +1,209 @@
+<template>
+	<div class="@(@Model.ClassName)-container">
+		<el-dialog
+		v-model="isShowDialog"
+		:title="title"
+		:width="700"
+		draggable>
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px" :rules="rules">
+				<el-row :gutter="35">
+					@foreach (var column in Model.TableField){
+					if(@column.ColumnKey == "True"){
+					@:<el-form-item v-show="false"><el-input v-model="ruleForm.@(@column.ColumnName)" /></el-form-item>
+					}else{
+					if (@column.WhetherAddUpdate == "Y"){
+					if(@column.EffectType == "fk"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-select clearable= v-model="ruleForm.@(@column.ColumnName)" placeholder="请选择@(@column.ColumnComment)">
+								@:<el-select-option v-for="(item,index) in get@(@column.FkEntityName)DropdownList" :key="index" :value="item.code">{{ item.name }}</el-select-option>
+								@:</el-select>
+							@:</el-form-item>
+						@:</el-col>
+					}else if(@column.EffectType == "Input"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-input v-model="ruleForm.@(@column.ColumnName)" placeholder="ruleForm.@(@column.ColumnName)" clearable/>
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "InputNumber"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-input-number v-model="ruleForm.@(@column.ColumnName)" placeholder="ruleForm.@(@column.ColumnName)" clearable/>
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "InputTextArea"){
+					@:<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-input v-model="ruleForm.@(@column.ColumnName)" placeholder="ruleForm.@(@column.ColumnName)" type="textarea" clearable/>
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "Select"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-select clearable v-model="ruleForm.@(@column.ColumnName)" placeholder="请选择@(@column.ColumnComment)">
+								@:<el-select-option v-for="(item,index) in getDictDataDropdownList('@(@column.DictTypeCode)')" :key="index" :value="item.value">{{ item.label }}</el-select-option>
+							@:</el-select>
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "ConstSelector"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-select clearable="" v-model="ruleForm.@(@column.ColumnName)" placeholder="请选择@(@column.ColumnComment)">
+								@:<el-select-option v-for="(item,index) in getSelectorList('@(@column.DictTypeCode)')" :key="index" :value="item.code">{{ item.name }}</el-select-option>
+								@:</el-select>
+							@:</el-form-item>
+						@:</el-col>
+					}else if(@column.EffectType == "Switch"){				
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-switch v-model="ruleForm.@(@column.ColumnName)" active-text="是" inactive-text="否" />
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "DatePicker"){
+					@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						@:<el-form-item label="@column.ColumnComment">
+							@:<el-date-picker v-model="ruleForm.@(@column.ColumnName)" type="datetime" placeholder="@column.ColumnComment"  />
+						@:</el-form-item>
+					@:</el-col>
+					}else if(@column.EffectType == "Upload"){
+					
+					}else{
+
+					}
+					}
+					}
+					}
+						</el-row>
+					</el-form>
+					<template #footer>
+						<span class="dialog-footer">
+							<el-button @@click="cancel" size="default">取 消</el-button>
+							<el-button type="primary" @@click="submit" size="default">确 定</el-button>
+						</span>
+					</template>
+		</el-dialog>	
+	</div>
+</template>
+
+<script lang="ts">
+	import { ref, toRefs, reactive, onMounted, defineComponent, getCurrentInstance, onUnmounted } from 'vue';
+	import { ElMessageBox, ElMessage } from 'element-plus';
+	import { auth } from '/@@/utils/authFunction';
+	import { formatDate } from '/@@/utils/formatTime';
+	import type { FormInstance, FormRules } from 'element-plus'
+
+	@foreach (var column in Model.TableField){
+	if(@column.EffectType == "fk"){
+	@:import { get@(@column.FkEntityName)Dropdown } from '/@@/api/main/@(@Model.ClassName)';
+	}
+	}
+	@foreach (var column in Model.TableField){
+	if(@column.EffectType == "Select"){
+	@:import { getDictDataDropdown } from '/@@/api/system/admin';
+	}
+	}
+
+	export default defineComponent({
+	name: 'edit@(@Model.ClassName)',
+	props: {
+	title: {
+	type: String,
+	default: '',
+	},
+	},
+	setup() {
+	const { proxy } = getCurrentInstance() as any;
+	const ruleFormRef = ref();
+	const state = reactive({
+	isShowDialog: false,
+	ruleForm: {} as any,
+	});
+
+	const rules = reactive<FormRules>({
+	@foreach (var column in Model.TableField){
+		if(@column.WhetherRequired == "Y"){
+			if(@column.EffectType == "Input" || @column.EffectType == "InputNumber" ||@column.EffectType == "InputTextArea"){
+			@:@column.ColumnName: [{required: true, message: '请输入@(@column.ColumnComment)!', trigger: 'blur',},],
+			}else if(@column.EffectType == "DatePicker" || @column.EffectType == "Select" ||@column.EffectType == "ApiTreeSelect"){
+			@:@column.ColumnName: [{required: true, message: '请选择@(@column.ColumnComment)!', trigger: 'change',},],
+			}
+		}
+	}
+	});
+
+	// 打开弹窗
+	const openDialog = (row: any) => {
+	state.ruleForm = row;
+	state.isShowDialog = true;
+	};
+
+	// 关闭弹窗
+	const closeDialog = () => {
+	proxy.mittBus.emit('submitRefresh');
+	state.isShowDialog = false;
+	};
+
+	// 取消
+	const cancel = () => {
+	state.isShowDialog = false;
+	};
+
+	// 提交
+	const submit = () => {
+	ruleFormRef.value.validate(async (valid: boolean) => {
+	if (!valid) return;
+	if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
+	await update@(@Model.ClassName)(values);
+	} else {
+	await add@(@Model.ClassName)(state.ruleForm);
+	}
+	closeDialog();
+	});
+	};
+
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "fk"){
+	@:const get@(@column.FkEntityName)DropdownList = await () => {
+	@:let list = await get@(@column.FkEntityName)Dropdown();
+	@:return list.data.result ?? [];
+	@:};
+	break;
+	}
+	}
+
+	@foreach (var column in Model.TableField){
+	if(@column.EffectType == "Select"){
+	@:const getDictDataDropdownList = await (val: any) => {
+	@:let list = await getDictDataDropdownList(val);
+	@:return list.data.result ?? [];
+	@:};
+	break;
+	}
+	}
+	return {
+	@foreach (var column in Model.TableField){
+	if(@column.EffectType == "fk"){
+	@:get@(@column.FkEntityName)DropdownList,
+	break;
+	}
+	}
+	@foreach (var column in Model.TableField){
+	if(@column.EffectType == "Select"){
+	@:getDictDataDropdownList,
+	break;
+	}
+	}
+	ruleFormRef,
+	openDialog,
+	closeDialog,
+	cancel,
+	submit,
+	...toRefs(state),
+	rules,
+	};
+	}
+	})
+
+	}
+</script>

+ 260 - 123
Admin.NET/Admin.NET.Web.Entry/wwwroot/Template/index.vue.vm

@@ -1,133 +1,270 @@
 <template>
-  <div>
-    <BasicTable @@register="registerTable">
-      <template #toolbar>
-        <a-button type="primary" @@click="handleCreate" :disabled="!hasPermission('@(@Model.ClassName):add')">新增@(@Model.BusName)</a-button>
-      </template>
-@foreach (var column in Model.TableField){
-if(@column.EffectType == "Upload"){
-      @:<template #@(@column.LowerColumnName)="{ text, record }">
-        <TableImg
-          v-if="record.@(@column.LowerColumnName)Attachment"
-          :size="60"
-          :simpleShow="true"
-          :showBadge="false"
-          :imgList="[downUrl + '/' + record.@(@column.LowerColumnName)Attachment.id + record.@(@column.LowerColumnName)Attachment.suffix]"
-        />
-      </template>
-}
+  <div class="@(@Model.ClassName)-container">
+    <el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+		          
+@if(Model.QueryWhetherList.Count > 0){
+     @:<el-form :model="queryParams" ref="queryForm" :inline="true">
+		 @:<el-row>
+foreach (var column in Model.QueryWhetherList){
+    if(@column.EffectType == "Input" || @column.EffectType == "InputTextArea"){
+       @:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" >
+       @:<el-form-item label="@column.ColumnComment">
+       @:<el-input v-model="queryParams.@(@column.ColumnName)" clearable placeholder="请输入@(@column.ColumnComment)"/>
+       @:</el-form-item>
+       @:</el-col>
+    }else if(@column.EffectType == "InputTextArea"){
+		@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" >
+        @:<el-form-item label="@column.ColumnComment">
+        @:<el-input-number v-model="queryParams.@(@column.ColumnName)"  clearable placeholder="请输入@(@column.ColumnComment)"/>
+        @:</el-form-item>
+        @:</el-col>
+    }else if(@column.EffectType == "InputNumber"){
+		@:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" >
+        @:<el-form-item label="@column.ColumnComment">
+        @:<el-input-number v-model="queryParams.@(@column.ColumnName)"  clearable placeholder="请输入@(@column.ColumnComment)"/>
+        @:</el-form-item>
+        @:</el-col>
+    }else if(@column.EffectType == "fk"){
+        @:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" >
+        @:<el-form-item label="@column.ColumnComment">
+        @:<el-select clearable v-model="queryParams.@(@column.ColumnName)" placeholder="请选择@(@column.ColumnComment)">
+        @:<el-select-option v-for="(item,index) in get@(@column.FkEntityName)DropdownList" :key="index" :value="item.vaue">{{ item.label }}</el-select-option>
+        @:</el-select>
+        @:</el-form-item>
+        @:</el-col>
+    }else if(@column.EffectType == "Select"){
+         @:<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" >
+         @:<el-form-item label="@column.ColumnComment">
+         @:<el-select clearable v-model="queryParams.@(@column.ColumnName)" placeholder="请选择@(@column.ColumnComment)">
+         @:<el-select-option v-for="(item,index) in getDictDataDropdownList('@(@column.DictTypeCode)')" :key="index" :value="item.code">{{ item.name }}</el-select-option>
+         @:</el-select>
+         @:</el-form-item>
+         @:</el-col>
+    }else if(@column.EffectType == "DatePicker"){
+        @:<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
+        @:<el-form-item label="@column.ColumnComment">
+        @:<el-date-picker placeholder="请选择@(@column.ColumnComment)" v-model="queryParams.@(@column.ColumnName)Date" />
+        @:</el-form-item>
+        @:</el-col>
+			 }
+
+			 }
+			 @:<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" >
+				 @: <span class="table-page-search-submitButtons">
+					 @: <el-button icon="ele-Refresh" @@click="() => queryParams = {}"> 重置 </el-button>
+					 @: <el-button type="primary" icon="ele-Search" @@click="handleQuery" v-auth="'@(@Model.ClassName):page'"> 查询 </el-button>
+					 @:  <el-button icon="ele-Plus" @@click="openAdd@(@Model.ClassName)" v-auth="'@(@Model.ClassName):add'"> 新增 </el-button>
+					 @:</span>
+				 @:</el-col>
+			 @:</el-row>
+		 @:</el-form>
 }
-      <template #bodyCell="{ column, record }">
-        <template v-if="column.key === 'action'">
-          <TableAction
-            :actions="[
-              {
-                icon: 'clarity:note-edit-line',
-                label: '编辑',
-                onClick: handleEdit.bind(null, record),
-                disabled: !hasPermission('@(@Model.ClassName):edit'),
-              },
-              {
-                icon: 'ant-design:delete-outlined',
-                color: 'error',
-                label: '删除',
-                ifShow: hasPermission('@(@Model.ClassName):delete'),
-                popConfirm: {
-                  title: '是否确认删除',
-                  placement: 'left',
-                  confirm: handleDelete.bind(null, record),
-                },
-              },
-            ]"
-          />
-        </template>
-      </template>
-    </BasicTable>
-    <@(@Model.ClassName)Modal @@register="registerModal" @@success="handleSuccess" />
+      
+    </el-card>
+    <el-card :bordered="false">
+	<el-table 
+		:data="tableData" 
+		style="width: 100%" 
+		v-loading="loading" 
+		tooltip-effect="light"
+		row-key="id"
+		border>
+		<el-table-column type="index" label="序号" width="55" align="center" fixed />
+		@foreach (var column in Model.TableField){		   
+		     if(@column.WhetherTable == "Y"){
+			     if(@column.EffectType == "Upload"||@column.EffectType == "fk"||@column.EffectType == "Switch"||@column.EffectType == "ConstSelector"){
+				 @: <el-table-column prop="@column.ColumnName" label="@column.ColumnComment" fixed show-overflow-tooltip>
+					    @:<template #default="scope">
+			                if(@column.EffectType == "Upload"){
+								@:<el-image
+							        @:style="width: 60px; height: 60px"
+							        @::src="scope.row.url"
+							        @::lazy="true"
+							        @::hide-on-click-modal="true"
+							        @::preview-src-list="[scope.row.url]"
+							        @::initial-index="0"
+							        @:fit="scale-down"
+							        @:preview-teleported
+						         @:/>
+                            }else if(@column.EffectType == "fk"){
+                                @:<span>{{scope.row.fk@(@column.ColumnName).@(@column.LowerFkColumnName)}}</span>
+                            }else if(@column.EffectType == "Switch"){
+								@:<el-tag v-if="scope.row.@(@column.LowerColumnName)"> 是 </el-tag>
+								@:<el-tag type="danger" v-else> 否 </el-tag>
+                            }else if(@column.EffectType == "ConstSelector"){
+								@:<span>{{codeToName(scope.row.@(@column.LowerColumnName), '@(@column.DictTypeCode)')}</span>
+                            }
+					    @:</template>
+					@:</el-table-column>
+			     }
+                 else {
+				    @: <el-table-column prop="@column.ColumnName" label="@column.ColumnComment" fixed show-overflow-tooltip />
+				 }
+		    }
+			}
+			           <el-table-column label="操作" width="110" align="center" fixed="right" show-overflow-tooltip v-if="auth('@(@Model.ClassName):edit') || auth('@(@Model.ClassName):delete')">
+							<template #default="scope">
+								<el-button icon="ele-Edit" size="small" text type="primary" @@click="openEdit@(@Model.ClassName)(scope.row)" v-auth="'@(@Model.ClassName):update'"> 编辑 </el-button>
+								<el-button icon="ele-Edit" size="small" text type="primary" @@click="del@(@Model.ClassName)(scope.row)" v-auth="'@(@Model.ClassName):delete'"> 删除 </el-button>								
+							</template>
+		</el-table-column>
+	</el-table>
+	<el-pagination
+		v-model:currentPage="tableParams.page"
+		v-model:page-size="tableParams.pageSize"
+		:total="tableParams.total"
+		:page-sizes="[10, 20, 50, 100]"
+		small
+		background
+		@@size-change="handleSizeChange"
+		@@current-change="handleCurrentChange"
+		layout="total, sizes, prev, pager, next, jumper"
+	/>	 
+<editDialog ref="editDialogRef" :title="edit@(@Model.ClassName)Title"/>
+    </el-card>
   </div>
 </template>
+
 <script lang="ts">
-  import { defineComponent } from 'vue';
-  import { usePermission } from '/@@/hooks/web/usePermission';
-  @if(Model.IsUpload){
-  @:import { BasicTable, useTable, TableAction, TableImg } from '/@@/components/Table';
-  }else{
-  @:import { BasicTable, useTable, TableAction } from '/@@/components/Table';
-  }
-  import { useModal } from '/@@/components/Modal';
-  import @(@Model.ClassName)Modal from './dataModal.vue';
+	import { ref, toRefs, reactive, onMounted, defineComponent, getCurrentInstance, onUnmounted } from 'vue';
+	import { ElMessageBox, ElMessage } from 'element-plus';
+	import { auth } from '/@@/utils/authFunction';
+	import { formatDate } from '/@@/utils/formatTime';
 
-  import { columns, searchFormSchema } from './data.data';
-  import { useMessage } from '/@@/hooks/web/useMessage';
-  import { get@(@Model.ClassName)PageList, delete@(@Model.ClassName) } from '/@@/api/main/@(@Model.ClassName)';
-  export default defineComponent({
-  @if(Model.IsUpload){
-    @:components: { BasicTable, @(@Model.ClassName)Modal, TableAction, TableImg },
-  }else{
-     @:components:{ BasicTable, @(@Model.ClassName)Modal, TableAction },
-  }
-    setup() {
-      const { hasPermission } = usePermission();
-      const { createMessage } = useMessage();
-      const [registerModal, { openModal }] = useModal();
-	  const hasPage = hasPermission('@(@Model.ClassName):page');
-      const [registerTable, { reload }] = useTable({
-        title: '@(@Model.BusName)列表',
-        api: get@(@Model.ClassName)PageList,
-        pagination: true,
-        rowKey: 'id',
-        columns,
-        formConfig: {
-          labelWidth: 120,
-          schemas: searchFormSchema,
-          autoSubmitOnEnter: true,
-        },
-        useSearchForm: hasPage,
-        immediate: hasPage,
-        showTableSetting: hasPage,
-        bordered: true,
-        canResize: true,
-        actionColumn: {
-          width: 160,
-          title: '操作',
-          dataIndex: 'action',
-          //slots: { customRender: 'action' },
-        },
-      });
+	import editDialog from '/@@/views/main/@(@Model.ClassName)/component/editDialog.vue'
+	import { get@(@Model.ClassName)PageList, delete@(@Model.ClassName) } from '/@@/api/main/@(@Model.ClassName)';
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "fk"){
+	@:import { get@(@column.FkEntityName)Dropdown } from '/@@/api/main/@(@Model.ClassName)';
+	}
+	}
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "Select"){
+	@:import { getDictDataDropdown } from '/@@/api/system/admin';
+	break;
+	}
+	}
+	export default defineComponent({
+	name: '@(@Model.ClassName)',
+	components: { editDialog },
+	setup() {
+	const { proxy } = getCurrentInstance() as any;
+	const editDialogRef = ref();
+	const state = reactive({
+	loading: false,
+	tableData: [] as any,
+	queryParams: {} as any,
+	tableParams: {
+	page: 1,
+	pageSize: 10,
+	total: 0 as any,
+	},
+	edit@(@Model.ClassName)Title: '',
+	});
 
-      function handleCreate() {
-        openModal(true, {
-          isUpdate: false,
-        });
-      }
+	onMounted(async () => {
+	handleQuery();
 
-      function handleEdit(record: Recordable) {
-        openModal(true, {
-          record,
-          isUpdate: true,
-        });
-      }
+	proxy.mittBus.on('submitRefresh', () => {
+	handleQuery();
+	});
+	});
 
-      async function handleDelete(record: Recordable) {
-        await delete@(@Model.ClassName)(record);
-        reload();
-        createMessage.success('删除成功!');
-      }
-      function handleSuccess() {
-        reload();
-      }
-      return {
-        hasPermission,
-        registerTable,
-        registerModal,
-        handleCreate,
-        handleEdit,
-        handleDelete,
-        handleSuccess,
-@if(@Model.IsUpload){
-        @:downUrl: import.meta.env.VITE_GLOB_DOWNLOAD_URL,
-}
-      };
-    },
-  });
+	onUnmounted(() => {
+	proxy.mittBus.off('submitRefresh');
+	});
+
+	// 查询操作
+	const handleQuery = async () => {
+	state.loading = true;
+	var res = await get@(@Model.ClassName)PageList(Object.assign(state.queryParams, state.tableParams));
+	state.tableData = res.data.result?.items ?? [];
+	state.tableParams.total = res.data.result?.total;
+	state.loading = false;
+	};
+
+	// 打开新增页面
+	const openAdd@(@Model.ClassName) = () => {
+	state.edit@(@Model.ClassName)Title = '添加@(@Model.BusName)';
+	editDialogRef.value.openDialog({});
+	};
+
+	// 打开编辑页面
+	const openEdit@(@Model.ClassName) = (row: any) => {
+	state.edit@(@Model.ClassName)Title = '编辑@(@Model.BusName)';
+	editDialogRef.value.openDialog(row);
+	};
+
+	// 删除
+	const del@(@Model.ClassName) = (row: any) => {
+	ElMessageBox.confirm(`确定要删除吗?`, '提示', {
+	confirmButtonText: '确定',
+	cancelButtonText: '取消',
+	type: 'warning',
+	})
+	.then(async () => {
+	await delete@(@Model.ClassName)(row);
+	handleQuery();
+	ElMessage.success('删除成功');
+	})
+	.catch(() => {});
+	};
+
+	// 改变页面容量
+	const handleSizeChange = (val: number) => {
+	state.tableParams.pageSize = val;
+	handleQuery();
+	};
+
+	// 改变页码序号
+	const handleCurrentChange = (val: number) => {
+	state.tableParams.page = val;
+	handleQuery();
+	};
+
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "fk"){
+	@:const get@(@column.FkEntityName)DropdownList = await () => {
+	@:let list = await get@(@column.FkEntityName)Dropdown();
+	@:return list.data.result ?? [];
+	@:};
+	break;
+	}
+	}
+
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "Select"){
+	@:const getDictDataDropdownList = await (val: any) => {
+	@:let list = await getDictDataDropdownList(val);
+	@:return list.data.result ?? [];
+	@:};
+	break;
+	}
+	}
+	return {
+	handleQuery,
+	editDialogRef,
+	openAdd@(@Model.ClassName),
+	openEdit@(@Model.ClassName),
+	del@(@Model.ClassName),
+	handleSizeChange,
+	handleCurrentChange,
+	formatDate,
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "fk"){
+	@:get@(@column.FkEntityName)DropdownList,
+	break;
+	}
+	}
+	@foreach (var column in Model.QueryWhetherList){
+	if(@column.EffectType == "Select"){
+	@:getDictDataDropdownList,
+	break;
+	}
+	}
+	auth,
+	...toRefs(state),
+	};
+	}
+	})
 </script>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 189 - 546
Web/package-lock.json


+ 1 - 1
Web/package.json

@@ -41,7 +41,7 @@
 		"vue3-tree-org": "^4.1.1"
 	},
 	"devDependencies": {
-		"@types/node": "^18.0.6",
+		"@types/node": "^18.8.4",
 		"@types/nprogress": "^0.2.0",
 		"@types/sortablejs": "^1.13.0",
 		"@typescript-eslint/eslint-plugin": "^5.30.7",

+ 2705 - 0
Web/pnpm-lock.yaml

@@ -0,0 +1,2705 @@
+lockfileVersion: 5.4
+
+specifiers:
+  '@element-plus/icons-vue': ^2.0.6
+  '@types/node': ^18.0.6
+  '@types/nprogress': ^0.2.0
+  '@types/sortablejs': ^1.13.0
+  '@typescript-eslint/eslint-plugin': ^5.30.7
+  '@typescript-eslint/parser': ^5.30.7
+  '@vitejs/plugin-vue': ^3.1.0
+  '@vue/compiler-sfc': ^3.2.37
+  '@wangeditor/editor': ^5.1.11
+  axios: ^0.27.2
+  countup.js: ^2.3.2
+  cropperjs: ^1.5.12
+  dotenv: ^16.0.1
+  echarts: ^5.3.3
+  echarts-gl: ^2.0.9
+  echarts-wordcloud: ^2.0.0
+  element-plus: ^2.2.9
+  eslint: ^8.20.0
+  eslint-plugin-vue: ^9.2.0
+  js-cookie: ^3.0.1
+  jsplumb: ^2.15.6
+  mitt: ^3.0.0
+  nprogress: ^0.2.0
+  pinia: ^2.0.16
+  prettier: ^2.7.1
+  print-js: ^1.6.0
+  qrcodejs2-fixes: ^0.0.2
+  sass: ^1.53.0
+  sass-loader: ^13.0.2
+  screenfull: ^6.0.2
+  sortablejs: ^1.15.0
+  splitpanes: ^3.1.1
+  typescript: ^4.7.4
+  vite: ^3.0.4
+  vue: ^3.2.37
+  vue-clipboard3: ^2.0.0
+  vue-eslint-parser: ^9.0.3
+  vue-grid-layout: ^3.0.0-beta1
+  vue-i18n: ^9.2.2
+  vue-router: ^4.1.2
+
+dependencies:
+  '@element-plus/icons-vue': 2.0.10_vue@3.2.40
+  '@wangeditor/editor': 5.1.21
+  axios: 0.27.2
+  countup.js: 2.3.2
+  cropperjs: 1.5.12
+  echarts: 5.4.0
+  echarts-gl: 2.0.9_echarts@5.4.0
+  echarts-wordcloud: 2.0.0_echarts@5.4.0
+  element-plus: 2.2.17_vue@3.2.40
+  js-cookie: 3.0.1
+  jsplumb: 2.15.6
+  mitt: 3.0.0
+  nprogress: 0.2.0
+  pinia: 2.0.23_bfjwoga25wxjazzogo7o372nwq
+  print-js: 1.6.0
+  qrcodejs2-fixes: 0.0.2
+  screenfull: 6.0.2
+  sortablejs: 1.15.0
+  splitpanes: 3.1.1
+  vue: 3.2.40
+  vue-clipboard3: 2.0.0
+  vue-grid-layout: 3.0.0-beta1
+  vue-i18n: 9.2.2_vue@3.2.40
+  vue-router: 4.1.5_vue@3.2.40
+
+devDependencies:
+  '@types/node': 18.8.4
+  '@types/nprogress': 0.2.0
+  '@types/sortablejs': 1.15.0
+  '@typescript-eslint/eslint-plugin': 5.40.0_25sstg4uu2sk4pm7xcyzuov7xq
+  '@typescript-eslint/parser': 5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q
+  '@vitejs/plugin-vue': 3.1.2_vite@3.1.7+vue@3.2.40
+  '@vue/compiler-sfc': 3.2.40
+  dotenv: 16.0.3
+  eslint: 8.25.0
+  eslint-plugin-vue: 9.6.0_eslint@8.25.0
+  prettier: 2.7.1
+  sass: 1.55.0
+  sass-loader: 13.1.0_sass@1.55.0
+  typescript: 4.8.4
+  vite: 3.1.7_sass@1.55.0
+  vue-eslint-parser: 9.1.0_eslint@8.25.0
+
+packages:
+
+  /@babel/helper-string-parser/7.19.4:
+    resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
+    engines: {node: '>=6.9.0'}
+
+  /@babel/helper-validator-identifier/7.19.1:
+    resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
+    engines: {node: '>=6.9.0'}
+
+  /@babel/parser/7.19.4:
+    resolution: {integrity: sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+    dependencies:
+      '@babel/types': 7.19.4
+
+  /@babel/runtime/7.19.4:
+    resolution: {integrity: sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      regenerator-runtime: 0.13.9
+    dev: false
+
+  /@babel/types/7.19.4:
+    resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==}
+    engines: {node: '>=6.9.0'}
+    dependencies:
+      '@babel/helper-string-parser': 7.19.4
+      '@babel/helper-validator-identifier': 7.19.1
+      to-fast-properties: 2.0.0
+
+  /@ctrl/tinycolor/3.4.1:
+    resolution: {integrity: sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==}
+    engines: {node: '>=10'}
+    dev: false
+
+  /@element-plus/icons-vue/2.0.10_vue@3.2.40:
+    resolution: {integrity: sha512-ygEZ1mwPjcPo/OulhzLE7mtDrQBWI8vZzEWSNB2W/RNCRjoQGwbaK4N8lV4rid7Ts4qvySU3njMN7YCiSlSaTQ==}
+    peerDependencies:
+      vue: ^3.2.0
+    dependencies:
+      vue: 3.2.40
+    dev: false
+
+  /@esbuild/android-arm/0.15.10:
+    resolution: {integrity: sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@esbuild/linux-loong64/0.15.10:
+    resolution: {integrity: sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==}
+    engines: {node: '>=12'}
+    cpu: [loong64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /@eslint/eslintrc/1.3.3:
+    resolution: {integrity: sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.3.4
+      espree: 9.4.0
+      globals: 13.17.0
+      ignore: 5.2.0
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@floating-ui/core/1.0.1:
+    resolution: {integrity: sha512-bO37brCPfteXQfFY0DyNDGB3+IMe4j150KFQcgJ5aBP295p9nBGeHEs/p0czrRbtlHq4Px/yoPXO/+dOCcF4uA==}
+    dev: false
+
+  /@floating-ui/dom/1.0.2:
+    resolution: {integrity: sha512-5X9WSvZ8/fjy3gDu8yx9HAA4KG1lazUN2P4/VnaXLxTO9Dz53HI1oYoh1OlhqFNlHgGDiwFX5WhFCc2ljbW3yA==}
+    dependencies:
+      '@floating-ui/core': 1.0.1
+    dev: false
+
+  /@humanwhocodes/config-array/0.10.7:
+    resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==}
+    engines: {node: '>=10.10.0'}
+    dependencies:
+      '@humanwhocodes/object-schema': 1.2.1
+      debug: 4.3.4
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@humanwhocodes/module-importer/1.0.1:
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+    dev: true
+
+  /@humanwhocodes/object-schema/1.2.1:
+    resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
+    dev: true
+
+  /@interactjs/actions/1.10.17:
+    resolution: {integrity: sha512-wyB1ZqpaZy5gmz6VDqK9KWh98xKnFgL7VyLvxHODFi9V0IYX4HJAAOBlhtfze0D1R1f1cY+gqPDK+dLaHMlE+w==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/actions/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-wyB1ZqpaZy5gmz6VDqK9KWh98xKnFgL7VyLvxHODFi9V0IYX4HJAAOBlhtfze0D1R1f1cY+gqPDK+dLaHMlE+w==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/auto-scroll/1.10.17_@interactjs+utils@1.10.17:
+    resolution: {integrity: sha512-IQcW7N3xOaoL8RnAGOGMk0Y2gue7L4S3BT6Id4VBBu8so163DtLiZVW6jXu9rKVntzbluaAeqNZlfAVyu3kIWg==}
+    peerDependencies:
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/auto-start/1.10.17:
+    resolution: {integrity: sha512-qYVxhAbYnwxjD/NLEegUoAST7WASJ4VmWNjsyWRx/js5Op+I4E2zteARIeZGgrutcGIXMCcQzhCMgE3PjOpbpw==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/auto-start/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-qYVxhAbYnwxjD/NLEegUoAST7WASJ4VmWNjsyWRx/js5Op+I4E2zteARIeZGgrutcGIXMCcQzhCMgE3PjOpbpw==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/core/1.10.17_@interactjs+utils@1.10.17:
+    resolution: {integrity: sha512-rL9w+83HDRuXub8Ezqs+97CYLl/ne7bLT/sAeduUWaxYhsW9iOqBoob9JnkkCZOaOsYizWI1EWy0+fNc5ibtLQ==}
+    peerDependencies:
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/utils': 1.10.17
+    dev: false
+
+  /@interactjs/dev-tools/1.10.17_cn5slzagijafj3kjb52cs5znym:
+    resolution: {integrity: sha512-Oi9nEw3FfSwkNmW+V0WwdHqvzEkVHc24mH1v5EjRn60sqgrGLK9nTQ+NSuqcnUY8GxC3TkyuxnsOodxiadIRmA==}
+    peerDependencies:
+      '@interactjs/modifiers': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/modifiers': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/dev-tools/1.10.17_xbmse7bb75tf4dexy2xpppeyve:
+    resolution: {integrity: sha512-Oi9nEw3FfSwkNmW+V0WwdHqvzEkVHc24mH1v5EjRn60sqgrGLK9nTQ+NSuqcnUY8GxC3TkyuxnsOodxiadIRmA==}
+    peerDependencies:
+      '@interactjs/modifiers': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/modifiers': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/inertia/1.10.17_orxel6eubagr4ggpgjxuetzvmi:
+    resolution: {integrity: sha512-41vbYUjZIDCKt2/yhmjPrEW5+0uoL/hldFsll9pkvnLhmm12Xk0VXOlmR2zXKAmsTK3fJlKMyBYUX92qHLkyVQ==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/modifiers': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/modifiers': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/offset': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/interact/1.10.17:
+    resolution: {integrity: sha512-NyKsf8EFudvdahBjPz1Gt5QnynVwa/2LUfBc2/w8QOnOBiyzUm0HLloJSaB8a50QbQkSWN243/Lgpd8GTMQvuQ==}
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/types': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dev: false
+
+  /@interactjs/interactjs/1.10.17:
+    resolution: {integrity: sha512-hHmiukARbZhiM12zNKx0yQlFVl4C+NMeYNAYh6Mf9U3ZziQ47C+JEW8Gr7Zr/MxfNZyPu5nLKCpVQjh/JvBO9g==}
+    dependencies:
+      '@interactjs/actions': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/auto-scroll': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/auto-start': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/dev-tools': 1.10.17_xbmse7bb75tf4dexy2xpppeyve
+      '@interactjs/inertia': 1.10.17_orxel6eubagr4ggpgjxuetzvmi
+      '@interactjs/interact': 1.10.17
+      '@interactjs/modifiers': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/offset': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/pointer-events': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/reflow': 1.10.17_farzh4kmmmdsqeu7trbjloi3zi
+      '@interactjs/utils': 1.10.17
+    dev: false
+
+  /@interactjs/modifiers/1.10.17:
+    resolution: {integrity: sha512-Dxw8kv9VBIxnhNvQncR6CKAGMzKXczLvuAUIdSPFYtyerX/XiDulJUqhR+jVKNp/WjF1DvdBxWo0kGGLbM84LQ==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/snappers': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/modifiers/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-Dxw8kv9VBIxnhNvQncR6CKAGMzKXczLvuAUIdSPFYtyerX/XiDulJUqhR+jVKNp/WjF1DvdBxWo0kGGLbM84LQ==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/snappers': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/offset/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-wWBnIQWgLrmJNTBbd/FdxHxAJjiXl/5ND8Jbw2DuP9gIGDxhFSdEt62Fgqimn9ICb8v8ycvSLObEmcvJF/8hQQ==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/pointer-events/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-VsfluouEKb8QRGyH6jQATCW+QdAd/3dkENS7rj2m+EcVUhz2Ob5mpMRopjALi4pwltMowqTfuJ4LtwMSX2G29A==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/reflow/1.10.17_farzh4kmmmdsqeu7trbjloi3zi:
+    resolution: {integrity: sha512-ncpWP5k93FRQptEhjzPZsbuRRajd4rkW17lDavCrEjrDi/LHnYekWGqZTaFzfJ80n1x8xUm9ujDjxCTylNqEIA==}
+    peerDependencies:
+      '@interactjs/core': 1.10.17
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/core': 1.10.17_@interactjs+utils@1.10.17
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/snappers/1.10.17:
+    resolution: {integrity: sha512-m753DGsNOts797e3zDT6wqELoc+BlpIC1w+TyMyISRxU6n1RlS8Q6LHBGgwAgV79LHLaahv/a5haFF9H1VG0FQ==}
+    peerDependencies:
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/snappers/1.10.17_@interactjs+utils@1.10.17:
+    resolution: {integrity: sha512-m753DGsNOts797e3zDT6wqELoc+BlpIC1w+TyMyISRxU6n1RlS8Q6LHBGgwAgV79LHLaahv/a5haFF9H1VG0FQ==}
+    peerDependencies:
+      '@interactjs/utils': 1.10.17
+    dependencies:
+      '@interactjs/utils': 1.10.17
+    optionalDependencies:
+      '@interactjs/interact': 1.10.17
+    dev: false
+
+  /@interactjs/types/1.10.17:
+    resolution: {integrity: sha512-X2JpoM7xUw0p9Me0tMaI0HNfcF/Hd07ZZlzpnpEMpGerUZOLoyeThrV9P+CrBHxZrluWJrigJbcdqXliFd0YMA==}
+    dev: false
+
+  /@interactjs/utils/1.10.17:
+    resolution: {integrity: sha512-sZAW08CkqgvqRjUIaLRjScjObcCzN9D75yekLA21EClYAZIhi4A+GEt2z/WqOCOksTaEPLYmQyhkpXcboc0LhQ==}
+    dev: false
+
+  /@intlify/core-base/9.2.2:
+    resolution: {integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/devtools-if': 9.2.2
+      '@intlify/message-compiler': 9.2.2
+      '@intlify/shared': 9.2.2
+      '@intlify/vue-devtools': 9.2.2
+    dev: false
+
+  /@intlify/devtools-if/9.2.2:
+    resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/shared': 9.2.2
+    dev: false
+
+  /@intlify/message-compiler/9.2.2:
+    resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/shared': 9.2.2
+      source-map: 0.6.1
+    dev: false
+
+  /@intlify/shared/9.2.2:
+    resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
+    engines: {node: '>= 14'}
+    dev: false
+
+  /@intlify/vue-devtools/9.2.2:
+    resolution: {integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/core-base': 9.2.2
+      '@intlify/shared': 9.2.2
+    dev: false
+
+  /@nodelib/fs.scandir/2.1.5:
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+    dev: true
+
+  /@nodelib/fs.stat/2.0.5:
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+    dev: true
+
+  /@nodelib/fs.walk/1.2.8:
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.13.0
+    dev: true
+
+  /@sxzz/popperjs-es/2.11.7:
+    resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
+    dev: false
+
+  /@transloadit/prettier-bytes/0.0.7:
+    resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
+    dev: false
+
+  /@types/event-emitter/0.3.3:
+    resolution: {integrity: sha512-UfnOK1pIxO7P+EgPRZXD9jMpimd8QEFcEZ5R67R1UhGbv4zghU5+NE7U8M8G9H5Jc8FI51rqDWQs6FtUfq2e/Q==}
+    dev: false
+
+  /@types/json-schema/7.0.11:
+    resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
+    dev: true
+
+  /@types/lodash-es/4.17.6:
+    resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==}
+    dependencies:
+      '@types/lodash': 4.14.186
+    dev: false
+
+  /@types/lodash/4.14.186:
+    resolution: {integrity: sha512-eHcVlLXP0c2FlMPm56ITode2AgLMSa6aJ05JTTbYbI+7EMkCEE5qk2E41d5g2lCVTqRe0GnnRFurmlCsDODrPw==}
+    dev: false
+
+  /@types/node/18.8.4:
+    resolution: {integrity: sha512-WdlVphvfR/GJCLEMbNA8lJ0lhFNBj4SW3O+O5/cEGw9oYrv0al9zTwuQsq+myDUXgNx2jgBynoVgZ2MMJ6pbow==}
+    dev: true
+
+  /@types/nprogress/0.2.0:
+    resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==}
+    dev: true
+
+  /@types/sortablejs/1.15.0:
+    resolution: {integrity: sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==}
+    dev: true
+
+  /@types/web-bluetooth/0.0.15:
+    resolution: {integrity: sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA==}
+    dev: false
+
+  /@typescript-eslint/eslint-plugin/5.40.0_25sstg4uu2sk4pm7xcyzuov7xq:
+    resolution: {integrity: sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^5.0.0
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q
+      '@typescript-eslint/scope-manager': 5.40.0
+      '@typescript-eslint/type-utils': 5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q
+      '@typescript-eslint/utils': 5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q
+      debug: 4.3.4
+      eslint: 8.25.0
+      ignore: 5.2.0
+      regexpp: 3.2.0
+      semver: 7.3.8
+      tsutils: 3.21.0_typescript@4.8.4
+      typescript: 4.8.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/parser/5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q:
+    resolution: {integrity: sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/scope-manager': 5.40.0
+      '@typescript-eslint/types': 5.40.0
+      '@typescript-eslint/typescript-estree': 5.40.0_typescript@4.8.4
+      debug: 4.3.4
+      eslint: 8.25.0
+      typescript: 4.8.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/scope-manager/5.40.0:
+    resolution: {integrity: sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.40.0
+      '@typescript-eslint/visitor-keys': 5.40.0
+    dev: true
+
+  /@typescript-eslint/type-utils/5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q:
+    resolution: {integrity: sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '*'
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/typescript-estree': 5.40.0_typescript@4.8.4
+      '@typescript-eslint/utils': 5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q
+      debug: 4.3.4
+      eslint: 8.25.0
+      tsutils: 3.21.0_typescript@4.8.4
+      typescript: 4.8.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/types/5.40.0:
+    resolution: {integrity: sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: true
+
+  /@typescript-eslint/typescript-estree/5.40.0_typescript@4.8.4:
+    resolution: {integrity: sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/types': 5.40.0
+      '@typescript-eslint/visitor-keys': 5.40.0
+      debug: 4.3.4
+      globby: 11.1.0
+      is-glob: 4.0.3
+      semver: 7.3.8
+      tsutils: 3.21.0_typescript@4.8.4
+      typescript: 4.8.4
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /@typescript-eslint/utils/5.40.0_z4bbprzjrhnsfa24uvmcbu7f5q:
+    resolution: {integrity: sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      '@types/json-schema': 7.0.11
+      '@typescript-eslint/scope-manager': 5.40.0
+      '@typescript-eslint/types': 5.40.0
+      '@typescript-eslint/typescript-estree': 5.40.0_typescript@4.8.4
+      eslint: 8.25.0
+      eslint-scope: 5.1.1
+      eslint-utils: 3.0.0_eslint@8.25.0
+      semver: 7.3.8
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+    dev: true
+
+  /@typescript-eslint/visitor-keys/5.40.0:
+    resolution: {integrity: sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.40.0
+      eslint-visitor-keys: 3.3.0
+    dev: true
+
+  /@uppy/companion-client/2.2.2:
+    resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
+    dependencies:
+      '@uppy/utils': 4.1.3
+      namespace-emitter: 2.0.1
+    dev: false
+
+  /@uppy/core/2.3.4:
+    resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
+    dependencies:
+      '@transloadit/prettier-bytes': 0.0.7
+      '@uppy/store-default': 2.1.1
+      '@uppy/utils': 4.1.3
+      lodash.throttle: 4.1.1
+      mime-match: 1.0.2
+      namespace-emitter: 2.0.1
+      nanoid: 3.3.4
+      preact: 10.11.1
+    dev: false
+
+  /@uppy/store-default/2.1.1:
+    resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
+    dev: false
+
+  /@uppy/utils/4.1.3:
+    resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
+    dependencies:
+      lodash.throttle: 4.1.1
+    dev: false
+
+  /@uppy/xhr-upload/2.1.3_@uppy+core@2.3.4:
+    resolution: {integrity: sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==}
+    peerDependencies:
+      '@uppy/core': ^2.3.3
+    dependencies:
+      '@uppy/companion-client': 2.2.2
+      '@uppy/core': 2.3.4
+      '@uppy/utils': 4.1.3
+      nanoid: 3.3.4
+    dev: false
+
+  /@vitejs/plugin-vue/3.1.2_vite@3.1.7+vue@3.2.40:
+    resolution: {integrity: sha512-3zxKNlvA3oNaKDYX0NBclgxTQ1xaFdL7PzwF6zj9tGFziKwmBa3Q/6XcJQxudlT81WxDjEhHmevvIC4Orc1LhQ==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      vite: ^3.0.0
+      vue: ^3.2.25
+    dependencies:
+      vite: 3.1.7_sass@1.55.0
+      vue: 3.2.40
+    dev: true
+
+  /@vue/compiler-core/3.2.40:
+    resolution: {integrity: sha512-2Dc3Stk0J/VyQ4OUr2yEC53kU28614lZS+bnrCbFSAIftBJ40g/2yQzf4mPBiFuqguMB7hyHaujdgZAQ67kZYA==}
+    dependencies:
+      '@babel/parser': 7.19.4
+      '@vue/shared': 3.2.40
+      estree-walker: 2.0.2
+      source-map: 0.6.1
+
+  /@vue/compiler-dom/3.2.40:
+    resolution: {integrity: sha512-OZCNyYVC2LQJy4H7h0o28rtk+4v+HMQygRTpmibGoG9wZyomQiS5otU7qo3Wlq5UfHDw2RFwxb9BJgKjVpjrQw==}
+    dependencies:
+      '@vue/compiler-core': 3.2.40
+      '@vue/shared': 3.2.40
+
+  /@vue/compiler-sfc/3.2.40:
+    resolution: {integrity: sha512-tzqwniIN1fu1PDHC3CpqY/dPCfN/RN1thpBC+g69kJcrl7mbGiHKNwbA6kJ3XKKy8R6JLKqcpVugqN4HkeBFFg==}
+    dependencies:
+      '@babel/parser': 7.19.4
+      '@vue/compiler-core': 3.2.40
+      '@vue/compiler-dom': 3.2.40
+      '@vue/compiler-ssr': 3.2.40
+      '@vue/reactivity-transform': 3.2.40
+      '@vue/shared': 3.2.40
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+      postcss: 8.4.17
+      source-map: 0.6.1
+
+  /@vue/compiler-ssr/3.2.40:
+    resolution: {integrity: sha512-80cQcgasKjrPPuKcxwuCx7feq+wC6oFl5YaKSee9pV3DNq+6fmCVwEEC3vvkf/E2aI76rIJSOYHsWSEIxK74oQ==}
+    dependencies:
+      '@vue/compiler-dom': 3.2.40
+      '@vue/shared': 3.2.40
+
+  /@vue/devtools-api/6.4.4:
+    resolution: {integrity: sha512-Ku31WzpOV/8cruFaXaEZKF81WkNnvCSlBY4eOGtz5WMSdJvX1v1WWlSMGZeqUwPtQ27ZZz7B62erEMq8JDjcXw==}
+    dev: false
+
+  /@vue/reactivity-transform/3.2.40:
+    resolution: {integrity: sha512-HQUCVwEaacq6fGEsg2NUuGKIhUveMCjOk8jGHqLXPI2w6zFoPrlQhwWEaINTv5kkZDXKEnCijAp+4gNEHG03yw==}
+    dependencies:
+      '@babel/parser': 7.19.4
+      '@vue/compiler-core': 3.2.40
+      '@vue/shared': 3.2.40
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+
+  /@vue/reactivity/3.2.40:
+    resolution: {integrity: sha512-N9qgGLlZmtUBMHF9xDT4EkD9RdXde1Xbveb+niWMXuHVWQP5BzgRmE3SFyUBBcyayG4y1lhoz+lphGRRxxK4RA==}
+    dependencies:
+      '@vue/shared': 3.2.40
+
+  /@vue/runtime-core/3.2.40:
+    resolution: {integrity: sha512-U1+rWf0H8xK8aBUZhnrN97yoZfHbjgw/bGUzfgKPJl69/mXDuSg8CbdBYBn6VVQdR947vWneQBFzdhasyzMUKg==}
+    dependencies:
+      '@vue/reactivity': 3.2.40
+      '@vue/shared': 3.2.40
+
+  /@vue/runtime-dom/3.2.40:
+    resolution: {integrity: sha512-AO2HMQ+0s2+MCec8hXAhxMgWhFhOPJ/CyRXnmTJ6XIOnJFLrH5Iq3TNwvVcODGR295jy77I6dWPj+wvFoSYaww==}
+    dependencies:
+      '@vue/runtime-core': 3.2.40
+      '@vue/shared': 3.2.40
+      csstype: 2.6.21
+
+  /@vue/server-renderer/3.2.40_vue@3.2.40:
+    resolution: {integrity: sha512-gtUcpRwrXOJPJ4qyBpU3EyxQa4EkV8I4f8VrDePcGCPe4O/hd0BPS7v9OgjIQob6Ap8VDz9G+mGTKazE45/95w==}
+    peerDependencies:
+      vue: 3.2.40
+    dependencies:
+      '@vue/compiler-ssr': 3.2.40
+      '@vue/shared': 3.2.40
+      vue: 3.2.40
+
+  /@vue/shared/3.2.40:
+    resolution: {integrity: sha512-0PLQ6RUtZM0vO3teRfzGi4ltLUO5aO+kLgwh4Um3THSR03rpQWLTuRCkuO5A41ITzwdWeKdPHtSARuPkoo5pCQ==}
+
+  /@vueuse/core/9.3.0_vue@3.2.40:
+    resolution: {integrity: sha512-64Rna8IQDWpdrJxgitDg7yv1yTp41ZmvV8zlLEylK4QQLWAhz1OFGZDPZ8bU4lwcGgbEJ2sGi2jrdNh4LttUSQ==}
+    dependencies:
+      '@types/web-bluetooth': 0.0.15
+      '@vueuse/metadata': 9.3.0
+      '@vueuse/shared': 9.3.0_vue@3.2.40
+      vue-demi: 0.13.11_vue@3.2.40
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
+  /@vueuse/metadata/9.3.0:
+    resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==}
+    dev: false
+
+  /@vueuse/shared/9.3.0_vue@3.2.40:
+    resolution: {integrity: sha512-caGUWLY0DpPC6l31KxeUy6vPVNA0yKxx81jFYLoMpyP6cF84FG5Dkf69DfSUqL57wX8JcUkJDMnQaQIZPWFEQQ==}
+    dependencies:
+      vue-demi: 0.13.11_vue@3.2.40
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+    dev: false
+
+  /@wangeditor/basic-modules/1.1.6_r2od6lkt4jeumi2rq32wnno7pu:
+    resolution: {integrity: sha512-wckcFm/kEAHpTn7dTmN0+7POFoygqt9bZdNHJUkdKObXtAerml8RdjrkHRcwJFCkSELbrNK63fvkwS0+FsabfA==}
+    peerDependencies:
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      lodash.throttle: ^4.1.1
+      nanoid: ^3.2.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      is-url: 1.2.4
+      lodash.throttle: 4.1.1
+      nanoid: 3.3.4
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/code-highlight/1.0.3_bhxad6qx4irfgcgbuqicoe77z4:
+    resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
+    peerDependencies:
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      prismjs: 1.29.0
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/core/1.1.17_qokc4m5r26t2nkvzejrgzroa7e:
+    resolution: {integrity: sha512-u0jThy5qrpZo969LNykhb2fpHxEO6p3eKIeouZVnWpA2k9WjbOwtG35bmsUSQhjI5eb316t0ijJhaO4aDfwpuw==}
+    peerDependencies:
+      '@uppy/core': ^2.1.1
+      '@uppy/xhr-upload': ^2.0.3
+      dom7: ^3.0.0
+      is-hotkey: ^0.2.0
+      lodash.camelcase: ^4.3.0
+      lodash.clonedeep: ^4.5.0
+      lodash.debounce: ^4.0.8
+      lodash.foreach: ^4.5.0
+      lodash.isequal: ^4.5.0
+      lodash.throttle: ^4.1.1
+      lodash.toarray: ^4.4.0
+      nanoid: ^3.2.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@types/event-emitter': 0.3.3
+      '@uppy/core': 2.3.4
+      '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
+      dom7: 3.0.0
+      event-emitter: 0.3.5
+      html-void-elements: 2.0.1
+      i18next: 20.6.1
+      is-hotkey: 0.2.0
+      lodash.camelcase: 4.3.0
+      lodash.clonedeep: 4.5.0
+      lodash.debounce: 4.0.8
+      lodash.foreach: 4.5.0
+      lodash.isequal: 4.5.0
+      lodash.throttle: 4.1.1
+      lodash.toarray: 4.4.0
+      nanoid: 3.3.4
+      scroll-into-view-if-needed: 2.2.29
+      slate: 0.72.8
+      slate-history: 0.66.0_slate@0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/editor/5.1.21:
+    resolution: {integrity: sha512-fGMWXA3w/i72lRFvScQ/CaEiWE5nGlAzej6R33vOhJCArQZk8EMgCVEGh+jiqKA900NeXDTXRW+4mfuYjGv1ow==}
+    dependencies:
+      '@uppy/core': 2.3.4
+      '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
+      '@wangeditor/basic-modules': 1.1.6_r2od6lkt4jeumi2rq32wnno7pu
+      '@wangeditor/code-highlight': 1.0.3_bhxad6qx4irfgcgbuqicoe77z4
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      '@wangeditor/list-module': 1.0.5_bhxad6qx4irfgcgbuqicoe77z4
+      '@wangeditor/table-module': 1.1.4_kjpiouw2pn7pcp6kyhk2ialgaa
+      '@wangeditor/upload-image-module': 1.0.2_gnwmms55wok3k7ver5osxhqrn4
+      '@wangeditor/video-module': 1.1.4_hshvde7ra5hzmg3cnxpopqyu5e
+      dom7: 3.0.0
+      is-hotkey: 0.2.0
+      lodash.camelcase: 4.3.0
+      lodash.clonedeep: 4.5.0
+      lodash.debounce: 4.0.8
+      lodash.foreach: 4.5.0
+      lodash.isequal: 4.5.0
+      lodash.throttle: 4.1.1
+      lodash.toarray: 4.4.0
+      nanoid: 3.3.4
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/list-module/1.0.5_bhxad6qx4irfgcgbuqicoe77z4:
+    resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
+    peerDependencies:
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/table-module/1.1.4_kjpiouw2pn7pcp6kyhk2ialgaa:
+    resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
+    peerDependencies:
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      lodash.isequal: ^4.5.0
+      lodash.throttle: ^4.1.1
+      nanoid: ^3.2.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      lodash.isequal: 4.5.0
+      lodash.throttle: 4.1.1
+      nanoid: 3.3.4
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/upload-image-module/1.0.2_gnwmms55wok3k7ver5osxhqrn4:
+    resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
+    peerDependencies:
+      '@uppy/core': ^2.0.3
+      '@uppy/xhr-upload': ^2.0.3
+      '@wangeditor/basic-modules': 1.x
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      lodash.foreach: ^4.5.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@uppy/core': 2.3.4
+      '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
+      '@wangeditor/basic-modules': 1.1.6_r2od6lkt4jeumi2rq32wnno7pu
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      lodash.foreach: 4.5.0
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /@wangeditor/video-module/1.1.4_hshvde7ra5hzmg3cnxpopqyu5e:
+    resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
+    peerDependencies:
+      '@uppy/core': ^2.1.4
+      '@uppy/xhr-upload': ^2.0.7
+      '@wangeditor/core': 1.x
+      dom7: ^3.0.0
+      nanoid: ^3.2.0
+      slate: ^0.72.0
+      snabbdom: ^3.1.0
+    dependencies:
+      '@uppy/core': 2.3.4
+      '@uppy/xhr-upload': 2.1.3_@uppy+core@2.3.4
+      '@wangeditor/core': 1.1.17_qokc4m5r26t2nkvzejrgzroa7e
+      dom7: 3.0.0
+      nanoid: 3.3.4
+      slate: 0.72.8
+      snabbdom: 3.5.1
+    dev: false
+
+  /acorn-jsx/5.3.2_acorn@8.8.0:
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      acorn: 8.8.0
+    dev: true
+
+  /acorn/8.8.0:
+    resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+    dev: true
+
+  /ajv/6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+    dev: true
+
+  /ansi-regex/5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /ansi-styles/4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+    dependencies:
+      color-convert: 2.0.1
+    dev: true
+
+  /anymatch/3.1.2:
+    resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
+    engines: {node: '>= 8'}
+    dependencies:
+      normalize-path: 3.0.0
+      picomatch: 2.3.1
+    dev: true
+
+  /argparse/2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+    dev: true
+
+  /array-union/2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /async-validator/4.2.5:
+    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
+    dev: false
+
+  /asynckit/0.4.0:
+    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+    dev: false
+
+  /axios/0.27.2:
+    resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
+    dependencies:
+      follow-redirects: 1.15.2
+      form-data: 4.0.0
+    transitivePeerDependencies:
+      - debug
+    dev: false
+
+  /balanced-match/1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+    dev: true
+
+  /batch-processor/1.0.0:
+    resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==}
+    dev: false
+
+  /binary-extensions/2.2.0:
+    resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /boolbase/1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+    dev: true
+
+  /brace-expansion/1.1.11:
+    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+    dependencies:
+      balanced-match: 1.0.2
+      concat-map: 0.0.1
+    dev: true
+
+  /braces/3.0.2:
+    resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+    engines: {node: '>=8'}
+    dependencies:
+      fill-range: 7.0.1
+    dev: true
+
+  /callsites/3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /chalk/4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+    dev: true
+
+  /chokidar/3.5.3:
+    resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+    engines: {node: '>= 8.10.0'}
+    dependencies:
+      anymatch: 3.1.2
+      braces: 3.0.2
+      glob-parent: 5.1.2
+      is-binary-path: 2.1.0
+      is-glob: 4.0.3
+      normalize-path: 3.0.0
+      readdirp: 3.6.0
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /claygl/1.3.0:
+    resolution: {integrity: sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==}
+    dev: false
+
+  /clipboard/2.0.11:
+    resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==}
+    dependencies:
+      good-listener: 1.2.2
+      select: 1.1.2
+      tiny-emitter: 2.1.0
+    dev: false
+
+  /color-convert/2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+    dependencies:
+      color-name: 1.1.4
+    dev: true
+
+  /color-name/1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+    dev: true
+
+  /combined-stream/1.0.8:
+    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+    engines: {node: '>= 0.8'}
+    dependencies:
+      delayed-stream: 1.0.0
+    dev: false
+
+  /compute-scroll-into-view/1.0.17:
+    resolution: {integrity: sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==}
+    dev: false
+
+  /concat-map/0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+    dev: true
+
+  /countup.js/2.3.2:
+    resolution: {integrity: sha512-dQ7F/CmKGjaO6cDfhtEXwsKVlXIpJ89dFs8PvkaZH9jBVJ2Z8GU4iwG/qP7MgY8qwr+1skbwR6qecWWQLUzB8Q==}
+    dev: false
+
+  /cropperjs/1.5.12:
+    resolution: {integrity: sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw==}
+    dev: false
+
+  /cross-spawn/7.0.3:
+    resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+    engines: {node: '>= 8'}
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+    dev: true
+
+  /cssesc/3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+    dev: true
+
+  /csstype/2.6.21:
+    resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
+
+  /d/1.0.1:
+    resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
+    dependencies:
+      es5-ext: 0.10.62
+      type: 1.2.0
+    dev: false
+
+  /dayjs/1.11.5:
+    resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==}
+    dev: false
+
+  /debug/4.3.4:
+    resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.1.2
+    dev: true
+
+  /deep-is/0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+    dev: true
+
+  /delayed-stream/1.0.0:
+    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+    engines: {node: '>=0.4.0'}
+    dev: false
+
+  /delegate/3.2.0:
+    resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==}
+    dev: false
+
+  /dir-glob/3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+    dependencies:
+      path-type: 4.0.0
+    dev: true
+
+  /doctrine/3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      esutils: 2.0.3
+    dev: true
+
+  /dom7/3.0.0:
+    resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
+    dependencies:
+      ssr-window: 3.0.0
+    dev: false
+
+  /dotenv/16.0.3:
+    resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /echarts-gl/2.0.9_echarts@5.4.0:
+    resolution: {integrity: sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==}
+    peerDependencies:
+      echarts: ^5.1.2
+    dependencies:
+      claygl: 1.3.0
+      echarts: 5.4.0
+      zrender: 5.4.0
+    dev: false
+
+  /echarts-wordcloud/2.0.0_echarts@5.4.0:
+    resolution: {integrity: sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g==}
+    peerDependencies:
+      echarts: ^5.0.1
+    dependencies:
+      echarts: 5.4.0
+    dev: false
+
+  /echarts/5.4.0:
+    resolution: {integrity: sha512-uPsO9VRUIKAdFOoH3B0aNg7NRVdN7aM39/OjovjO9MwmWsAkfGyeXJhK+dbRi51iDrQWliXV60/XwLA7kg3z0w==}
+    dependencies:
+      tslib: 2.3.0
+      zrender: 5.4.0
+    dev: false
+
+  /element-plus/2.2.17_vue@3.2.40:
+    resolution: {integrity: sha512-MGwMIE/q+FFD3kgS23x8HIe5043tmD1cTRwjhIX9o6fim1avFnUkrsfYRvybbz4CkyqSb185EheZS5AUPpXh2g==}
+    peerDependencies:
+      vue: ^3.2.0
+    dependencies:
+      '@ctrl/tinycolor': 3.4.1
+      '@element-plus/icons-vue': 2.0.10_vue@3.2.40
+      '@floating-ui/dom': 1.0.2
+      '@popperjs/core': /@sxzz/popperjs-es/2.11.7
+      '@types/lodash': 4.14.186
+      '@types/lodash-es': 4.17.6
+      '@vueuse/core': 9.3.0_vue@3.2.40
+      async-validator: 4.2.5
+      dayjs: 1.11.5
+      escape-html: 1.0.3
+      lodash: 4.17.21
+      lodash-es: 4.17.21
+      lodash-unified: 1.0.2_3ib2ivapxullxkx3xftsimdk7u
+      memoize-one: 6.0.0
+      normalize-wheel-es: 1.2.0
+      vue: 3.2.40
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+    dev: false
+
+  /element-resize-detector/1.2.4:
+    resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==}
+    dependencies:
+      batch-processor: 1.0.0
+    dev: false
+
+  /es5-ext/0.10.62:
+    resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==}
+    engines: {node: '>=0.10'}
+    requiresBuild: true
+    dependencies:
+      es6-iterator: 2.0.3
+      es6-symbol: 3.1.3
+      next-tick: 1.1.0
+    dev: false
+
+  /es6-iterator/2.0.3:
+    resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
+    dependencies:
+      d: 1.0.1
+      es5-ext: 0.10.62
+      es6-symbol: 3.1.3
+    dev: false
+
+  /es6-symbol/3.1.3:
+    resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==}
+    dependencies:
+      d: 1.0.1
+      ext: 1.7.0
+    dev: false
+
+  /esbuild-android-64/0.15.10:
+    resolution: {integrity: sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-android-arm64/0.15.10:
+    resolution: {integrity: sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-darwin-64/0.15.10:
+    resolution: {integrity: sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-darwin-arm64/0.15.10:
+    resolution: {integrity: sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-freebsd-64/0.15.10:
+    resolution: {integrity: sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-freebsd-arm64/0.15.10:
+    resolution: {integrity: sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-32/0.15.10:
+    resolution: {integrity: sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-64/0.15.10:
+    resolution: {integrity: sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-arm/0.15.10:
+    resolution: {integrity: sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-arm64/0.15.10:
+    resolution: {integrity: sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-mips64le/0.15.10:
+    resolution: {integrity: sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-ppc64le/0.15.10:
+    resolution: {integrity: sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-riscv64/0.15.10:
+    resolution: {integrity: sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-linux-s390x/0.15.10:
+    resolution: {integrity: sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-netbsd-64/0.15.10:
+    resolution: {integrity: sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-openbsd-64/0.15.10:
+    resolution: {integrity: sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-sunos-64/0.15.10:
+    resolution: {integrity: sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-windows-32/0.15.10:
+    resolution: {integrity: sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-windows-64/0.15.10:
+    resolution: {integrity: sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild-windows-arm64/0.15.10:
+    resolution: {integrity: sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /esbuild/0.15.10:
+    resolution: {integrity: sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    optionalDependencies:
+      '@esbuild/android-arm': 0.15.10
+      '@esbuild/linux-loong64': 0.15.10
+      esbuild-android-64: 0.15.10
+      esbuild-android-arm64: 0.15.10
+      esbuild-darwin-64: 0.15.10
+      esbuild-darwin-arm64: 0.15.10
+      esbuild-freebsd-64: 0.15.10
+      esbuild-freebsd-arm64: 0.15.10
+      esbuild-linux-32: 0.15.10
+      esbuild-linux-64: 0.15.10
+      esbuild-linux-arm: 0.15.10
+      esbuild-linux-arm64: 0.15.10
+      esbuild-linux-mips64le: 0.15.10
+      esbuild-linux-ppc64le: 0.15.10
+      esbuild-linux-riscv64: 0.15.10
+      esbuild-linux-s390x: 0.15.10
+      esbuild-netbsd-64: 0.15.10
+      esbuild-openbsd-64: 0.15.10
+      esbuild-sunos-64: 0.15.10
+      esbuild-windows-32: 0.15.10
+      esbuild-windows-64: 0.15.10
+      esbuild-windows-arm64: 0.15.10
+    dev: true
+
+  /escape-html/1.0.3:
+    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+    dev: false
+
+  /escape-string-regexp/4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /eslint-plugin-vue/9.6.0_eslint@8.25.0:
+    resolution: {integrity: sha512-zzySkJgVbFCylnG2+9MDF7N+2Rjze2y0bF8GyUNpFOnT8mCMfqqtLDJkHBuYu9N/psW1A6DVbQhPkP92E+qakA==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      eslint: 8.25.0
+      eslint-utils: 3.0.0_eslint@8.25.0
+      natural-compare: 1.4.0
+      nth-check: 2.1.1
+      postcss-selector-parser: 6.0.10
+      semver: 7.3.8
+      vue-eslint-parser: 9.1.0_eslint@8.25.0
+      xml-name-validator: 4.0.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-scope/5.1.1:
+    resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
+    engines: {node: '>=8.0.0'}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 4.3.0
+    dev: true
+
+  /eslint-scope/7.1.1:
+    resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+    dev: true
+
+  /eslint-utils/3.0.0_eslint@8.25.0:
+    resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
+    engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
+    peerDependencies:
+      eslint: '>=5'
+    dependencies:
+      eslint: 8.25.0
+      eslint-visitor-keys: 2.1.0
+    dev: true
+
+  /eslint-visitor-keys/2.1.0:
+    resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /eslint-visitor-keys/3.3.0:
+    resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: true
+
+  /eslint/8.25.0:
+    resolution: {integrity: sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+    dependencies:
+      '@eslint/eslintrc': 1.3.3
+      '@humanwhocodes/config-array': 0.10.7
+      '@humanwhocodes/module-importer': 1.0.1
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.3
+      debug: 4.3.4
+      doctrine: 3.0.0
+      escape-string-regexp: 4.0.0
+      eslint-scope: 7.1.1
+      eslint-utils: 3.0.0_eslint@8.25.0
+      eslint-visitor-keys: 3.3.0
+      espree: 9.4.0
+      esquery: 1.4.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.17.0
+      globby: 11.1.0
+      grapheme-splitter: 1.0.4
+      ignore: 5.2.0
+      import-fresh: 3.3.0
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      js-sdsl: 4.1.5
+      js-yaml: 4.1.0
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.1
+      regexpp: 3.2.0
+      strip-ansi: 6.0.1
+      strip-json-comments: 3.1.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /espree/9.4.0:
+    resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      acorn: 8.8.0
+      acorn-jsx: 5.3.2_acorn@8.8.0
+      eslint-visitor-keys: 3.3.0
+    dev: true
+
+  /esquery/1.4.0:
+    resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
+    engines: {node: '>=0.10'}
+    dependencies:
+      estraverse: 5.3.0
+    dev: true
+
+  /esrecurse/4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+    dependencies:
+      estraverse: 5.3.0
+    dev: true
+
+  /estraverse/4.3.0:
+    resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+    engines: {node: '>=4.0'}
+    dev: true
+
+  /estraverse/5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+    dev: true
+
+  /estree-walker/2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  /esutils/2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /event-emitter/0.3.5:
+    resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
+    dependencies:
+      d: 1.0.1
+      es5-ext: 0.10.62
+    dev: false
+
+  /ext/1.7.0:
+    resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+    dependencies:
+      type: 2.7.2
+    dev: false
+
+  /fast-deep-equal/3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+    dev: true
+
+  /fast-glob/3.2.12:
+    resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
+    engines: {node: '>=8.6.0'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.5
+    dev: true
+
+  /fast-json-stable-stringify/2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+    dev: true
+
+  /fast-levenshtein/2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+    dev: true
+
+  /fastq/1.13.0:
+    resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
+    dependencies:
+      reusify: 1.0.4
+    dev: true
+
+  /file-entry-cache/6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flat-cache: 3.0.4
+    dev: true
+
+  /fill-range/7.0.1:
+    resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      to-regex-range: 5.0.1
+    dev: true
+
+  /find-up/5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+    dev: true
+
+  /flat-cache/3.0.4:
+    resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flatted: 3.2.7
+      rimraf: 3.0.2
+    dev: true
+
+  /flatted/3.2.7:
+    resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
+    dev: true
+
+  /follow-redirects/1.15.2:
+    resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+    dev: false
+
+  /form-data/4.0.0:
+    resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+    engines: {node: '>= 6'}
+    dependencies:
+      asynckit: 0.4.0
+      combined-stream: 1.0.8
+      mime-types: 2.1.35
+    dev: false
+
+  /fs.realpath/1.0.0:
+    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+    dev: true
+
+  /fsevents/2.3.2:
+    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+    requiresBuild: true
+    dev: true
+    optional: true
+
+  /function-bind/1.1.1:
+    resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+    dev: true
+
+  /glob-parent/5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+    dependencies:
+      is-glob: 4.0.3
+    dev: true
+
+  /glob-parent/6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      is-glob: 4.0.3
+    dev: true
+
+  /glob/7.2.3:
+    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+    dependencies:
+      fs.realpath: 1.0.0
+      inflight: 1.0.6
+      inherits: 2.0.4
+      minimatch: 3.1.2
+      once: 1.4.0
+      path-is-absolute: 1.0.1
+    dev: true
+
+  /globals/13.17.0:
+    resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==}
+    engines: {node: '>=8'}
+    dependencies:
+      type-fest: 0.20.2
+    dev: true
+
+  /globby/11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+    dependencies:
+      array-union: 2.1.0
+      dir-glob: 3.0.1
+      fast-glob: 3.2.12
+      ignore: 5.2.0
+      merge2: 1.4.1
+      slash: 3.0.0
+    dev: true
+
+  /good-listener/1.2.2:
+    resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==}
+    dependencies:
+      delegate: 3.2.0
+    dev: false
+
+  /grapheme-splitter/1.0.4:
+    resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==}
+    dev: true
+
+  /has-flag/4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /has/1.0.3:
+    resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+    engines: {node: '>= 0.4.0'}
+    dependencies:
+      function-bind: 1.1.1
+    dev: true
+
+  /html-void-elements/2.0.1:
+    resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
+    dev: false
+
+  /i18next/20.6.1:
+    resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
+    dependencies:
+      '@babel/runtime': 7.19.4
+    dev: false
+
+  /ignore/5.2.0:
+    resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==}
+    engines: {node: '>= 4'}
+    dev: true
+
+  /immer/9.0.15:
+    resolution: {integrity: sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==}
+    dev: false
+
+  /immutable/4.1.0:
+    resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==}
+    dev: true
+
+  /import-fresh/3.3.0:
+    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+    engines: {node: '>=6'}
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
+    dev: true
+
+  /imurmurhash/0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+    dev: true
+
+  /inflight/1.0.6:
+    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+    dependencies:
+      once: 1.4.0
+      wrappy: 1.0.2
+    dev: true
+
+  /inherits/2.0.4:
+    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+    dev: true
+
+  /is-binary-path/2.1.0:
+    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+    engines: {node: '>=8'}
+    dependencies:
+      binary-extensions: 2.2.0
+    dev: true
+
+  /is-core-module/2.10.0:
+    resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
+    dependencies:
+      has: 1.0.3
+    dev: true
+
+  /is-extglob/2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /is-glob/4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      is-extglob: 2.1.1
+    dev: true
+
+  /is-hotkey/0.2.0:
+    resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==}
+    dev: false
+
+  /is-number/7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+    dev: true
+
+  /is-plain-object/5.0.0:
+    resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
+  /is-url/1.2.4:
+    resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
+    dev: false
+
+  /isexe/2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+    dev: true
+
+  /js-cookie/3.0.1:
+    resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==}
+    engines: {node: '>=12'}
+    dev: false
+
+  /js-sdsl/4.1.5:
+    resolution: {integrity: sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==}
+    dev: true
+
+  /js-yaml/4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+    dependencies:
+      argparse: 2.0.1
+    dev: true
+
+  /json-schema-traverse/0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+    dev: true
+
+  /json-stable-stringify-without-jsonify/1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+    dev: true
+
+  /jsplumb/2.15.6:
+    resolution: {integrity: sha512-sIpbpz5eMVM+vV+MQzFCidlaa1RsknrQs6LOTKYDjYUDdTAi2AN2bFi94TxB33TifcIsRNV1jebcaxg0tCoPzg==}
+    dev: false
+
+  /klona/2.0.5:
+    resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==}
+    engines: {node: '>= 8'}
+    dev: true
+
+  /levn/0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+    dev: true
+
+  /locate-path/6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-locate: 5.0.0
+    dev: true
+
+  /lodash-es/4.17.21:
+    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+    dev: false
+
+  /lodash-unified/1.0.2_3ib2ivapxullxkx3xftsimdk7u:
+    resolution: {integrity: sha512-OGbEy+1P+UT26CYi4opY4gebD8cWRDxAT6MAObIVQMiqYdxZr1g3QHWCToVsm31x2NkLS4K3+MC2qInaRMa39g==}
+    peerDependencies:
+      '@types/lodash-es': '*'
+      lodash: '*'
+      lodash-es: '*'
+    dependencies:
+      '@types/lodash-es': 4.17.6
+      lodash: 4.17.21
+      lodash-es: 4.17.21
+    dev: false
+
+  /lodash.camelcase/4.3.0:
+    resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
+    dev: false
+
+  /lodash.clonedeep/4.5.0:
+    resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
+    dev: false
+
+  /lodash.debounce/4.0.8:
+    resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+    dev: false
+
+  /lodash.foreach/4.5.0:
+    resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==}
+    dev: false
+
+  /lodash.isequal/4.5.0:
+    resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+    dev: false
+
+  /lodash.merge/4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+    dev: true
+
+  /lodash.throttle/4.1.1:
+    resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
+    dev: false
+
+  /lodash.toarray/4.4.0:
+    resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
+    dev: false
+
+  /lodash/4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+  /lru-cache/6.0.0:
+    resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+    engines: {node: '>=10'}
+    dependencies:
+      yallist: 4.0.0
+    dev: true
+
+  /magic-string/0.25.9:
+    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+    dependencies:
+      sourcemap-codec: 1.4.8
+
+  /memoize-one/6.0.0:
+    resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
+    dev: false
+
+  /merge2/1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+    dev: true
+
+  /micromatch/4.0.5:
+    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+    engines: {node: '>=8.6'}
+    dependencies:
+      braces: 3.0.2
+      picomatch: 2.3.1
+    dev: true
+
+  /mime-db/1.52.0:
+    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+    engines: {node: '>= 0.6'}
+    dev: false
+
+  /mime-match/1.0.2:
+    resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
+    dependencies:
+      wildcard: 1.1.2
+    dev: false
+
+  /mime-types/2.1.35:
+    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+    engines: {node: '>= 0.6'}
+    dependencies:
+      mime-db: 1.52.0
+    dev: false
+
+  /minimatch/3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+    dependencies:
+      brace-expansion: 1.1.11
+    dev: true
+
+  /mitt/2.1.0:
+    resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==}
+    dev: false
+
+  /mitt/3.0.0:
+    resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==}
+    dev: false
+
+  /ms/2.1.2:
+    resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+    dev: true
+
+  /namespace-emitter/2.0.1:
+    resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
+    dev: false
+
+  /nanoid/3.3.4:
+    resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  /natural-compare/1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+    dev: true
+
+  /neo-async/2.6.2:
+    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+    dev: true
+
+  /next-tick/1.1.0:
+    resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
+    dev: false
+
+  /normalize-path/3.0.0:
+    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /normalize-wheel-es/1.2.0:
+    resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
+    dev: false
+
+  /nprogress/0.2.0:
+    resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
+    dev: false
+
+  /nth-check/2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+    dependencies:
+      boolbase: 1.0.0
+    dev: true
+
+  /once/1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+    dependencies:
+      wrappy: 1.0.2
+    dev: true
+
+  /optionator/0.9.1:
+    resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.3
+    dev: true
+
+  /p-limit/3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      yocto-queue: 0.1.0
+    dev: true
+
+  /p-locate/5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-limit: 3.1.0
+    dev: true
+
+  /parent-module/1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+    dependencies:
+      callsites: 3.1.0
+    dev: true
+
+  /path-exists/4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /path-is-absolute/1.0.1:
+    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /path-key/3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /path-parse/1.0.7:
+    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+    dev: true
+
+  /path-type/4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /picocolors/1.0.0:
+    resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
+  /picomatch/2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+    dev: true
+
+  /pinia/2.0.23_bfjwoga25wxjazzogo7o372nwq:
+    resolution: {integrity: sha512-N15hFf4o5STrxpNrib1IEb1GOArvPYf1zPvQVRGOO1G1d74Ak0J0lVyalX/SmrzdT4Q0nlEFjbURsmBmIGUR5Q==}
+    peerDependencies:
+      '@vue/composition-api': ^1.4.0
+      typescript: '>=4.4.4'
+      vue: ^2.6.14 || ^3.2.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+      typescript:
+        optional: true
+    dependencies:
+      '@vue/devtools-api': 6.4.4
+      typescript: 4.8.4
+      vue: 3.2.40
+      vue-demi: 0.13.11_vue@3.2.40
+    dev: false
+
+  /postcss-selector-parser/6.0.10:
+    resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
+    engines: {node: '>=4'}
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+    dev: true
+
+  /postcss/8.4.17:
+    resolution: {integrity: sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==}
+    engines: {node: ^10 || ^12 || >=14}
+    dependencies:
+      nanoid: 3.3.4
+      picocolors: 1.0.0
+      source-map-js: 1.0.2
+
+  /preact/10.11.1:
+    resolution: {integrity: sha512-1Wz5PCRm6Fg+6BTXWJHhX4wRK9MZbZBHuwBqfZlOdVm2NqPe8/rjYpufvYCwJSGb9layyzB2jTTXfpCTynLqFQ==}
+    dev: false
+
+  /prelude-ls/1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+    dev: true
+
+  /prettier/2.7.1:
+    resolution: {integrity: sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    dev: true
+
+  /print-js/1.6.0:
+    resolution: {integrity: sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==}
+    dev: false
+
+  /prismjs/1.29.0:
+    resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
+    engines: {node: '>=6'}
+    dev: false
+
+  /punycode/2.1.1:
+    resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
+    engines: {node: '>=6'}
+    dev: true
+
+  /qrcodejs2-fixes/0.0.2:
+    resolution: {integrity: sha512-wMUXYMOixAEJlLnjk5MbLiFaz0gQObWYm/TIFWB5+j7sTY5gPyr09Cx1EpcLYbsgfFdN3wHjrKAhZofTuCBGhg==}
+    dev: false
+
+  /queue-microtask/1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+    dev: true
+
+  /readdirp/3.6.0:
+    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+    engines: {node: '>=8.10.0'}
+    dependencies:
+      picomatch: 2.3.1
+    dev: true
+
+  /regenerator-runtime/0.13.9:
+    resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
+    dev: false
+
+  /regexpp/3.2.0:
+    resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /resolve-from/4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+    dev: true
+
+  /resolve/1.22.1:
+    resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.10.0
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: true
+
+  /reusify/1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+    dev: true
+
+  /rimraf/3.0.2:
+    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+    hasBin: true
+    dependencies:
+      glob: 7.2.3
+    dev: true
+
+  /rollup/2.78.1:
+    resolution: {integrity: sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==}
+    engines: {node: '>=10.0.0'}
+    hasBin: true
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /run-parallel/1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+    dependencies:
+      queue-microtask: 1.2.3
+    dev: true
+
+  /sass-loader/13.1.0_sass@1.55.0:
+    resolution: {integrity: sha512-tZS1RJQ2n2+QNyf3CCAo1H562WjL/5AM6Gi8YcPVVoNxQX8d19mx8E+8fRrMWsyc93ZL6Q8vZDSM0FHVTJaVnQ==}
+    engines: {node: '>= 14.15.0'}
+    peerDependencies:
+      fibers: '>= 3.1.0'
+      node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+      sass: ^1.3.0
+      sass-embedded: '*'
+      webpack: ^5.0.0
+    peerDependenciesMeta:
+      fibers:
+        optional: true
+      node-sass:
+        optional: true
+      sass:
+        optional: true
+      sass-embedded:
+        optional: true
+    dependencies:
+      klona: 2.0.5
+      neo-async: 2.6.2
+      sass: 1.55.0
+    dev: true
+
+  /sass/1.55.0:
+    resolution: {integrity: sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==}
+    engines: {node: '>=12.0.0'}
+    hasBin: true
+    dependencies:
+      chokidar: 3.5.3
+      immutable: 4.1.0
+      source-map-js: 1.0.2
+    dev: true
+
+  /screenfull/6.0.2:
+    resolution: {integrity: sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw==}
+    engines: {node: ^14.13.1 || >=16.0.0}
+    dev: false
+
+  /scroll-into-view-if-needed/2.2.29:
+    resolution: {integrity: sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==}
+    dependencies:
+      compute-scroll-into-view: 1.0.17
+    dev: false
+
+  /select/1.1.2:
+    resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==}
+    dev: false
+
+  /semver/7.3.8:
+    resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      lru-cache: 6.0.0
+    dev: true
+
+  /shebang-command/2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+    dependencies:
+      shebang-regex: 3.0.0
+    dev: true
+
+  /shebang-regex/3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /slash/3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /slate-history/0.66.0_slate@0.72.8:
+    resolution: {integrity: sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==}
+    peerDependencies:
+      slate: '>=0.65.3'
+    dependencies:
+      is-plain-object: 5.0.0
+      slate: 0.72.8
+    dev: false
+
+  /slate/0.72.8:
+    resolution: {integrity: sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==}
+    dependencies:
+      immer: 9.0.15
+      is-plain-object: 5.0.0
+      tiny-warning: 1.0.3
+    dev: false
+
+  /snabbdom/3.5.1:
+    resolution: {integrity: sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==}
+    engines: {node: '>=8.3.0'}
+    dev: false
+
+  /sortablejs/1.15.0:
+    resolution: {integrity: sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==}
+    dev: false
+
+  /source-map-js/1.0.2:
+    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+    engines: {node: '>=0.10.0'}
+
+  /source-map/0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  /sourcemap-codec/1.4.8:
+    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+
+  /splitpanes/3.1.1:
+    resolution: {integrity: sha512-VUkxDJfIGSvTM/fm/+OSrx8ha9URwE/9B8FPvfzoBuAxVELIHBWpsfnJXIXv77zVwuex//QQL4kTU9SDBPeHjA==}
+    dev: false
+
+  /ssr-window/3.0.0:
+    resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
+    dev: false
+
+  /strip-ansi/6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+    dependencies:
+      ansi-regex: 5.0.1
+    dev: true
+
+  /strip-json-comments/3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+    dev: true
+
+  /supports-color/7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+    dependencies:
+      has-flag: 4.0.0
+    dev: true
+
+  /supports-preserve-symlinks-flag/1.0.0:
+    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
+  /text-table/0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+    dev: true
+
+  /tiny-emitter/2.1.0:
+    resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==}
+    dev: false
+
+  /tiny-warning/1.0.3:
+    resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+    dev: false
+
+  /to-fast-properties/2.0.0:
+    resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
+    engines: {node: '>=4'}
+
+  /to-regex-range/5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+    dependencies:
+      is-number: 7.0.0
+    dev: true
+
+  /tslib/1.14.1:
+    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+    dev: true
+
+  /tslib/2.3.0:
+    resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
+    dev: false
+
+  /tsutils/3.21.0_typescript@4.8.4:
+    resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+    engines: {node: '>= 6'}
+    peerDependencies:
+      typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+    dependencies:
+      tslib: 1.14.1
+      typescript: 4.8.4
+    dev: true
+
+  /type-check/0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+    dev: true
+
+  /type-fest/0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /type/1.2.0:
+    resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==}
+    dev: false
+
+  /type/2.7.2:
+    resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==}
+    dev: false
+
+  /typescript/4.8.4:
+    resolution: {integrity: sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==}
+    engines: {node: '>=4.2.0'}
+    hasBin: true
+
+  /uri-js/4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+    dependencies:
+      punycode: 2.1.1
+    dev: true
+
+  /util-deprecate/1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+    dev: true
+
+  /vite/3.1.7_sass@1.55.0:
+    resolution: {integrity: sha512-5vCAmU4S8lyVdFCInu9M54f/g8qbOMakVw5xJ4pjoaDy5wgy9sLLZkGdSLN52dlsBqh0tBqxjaqqa8LgPqwRAA==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    hasBin: true
+    peerDependencies:
+      less: '*'
+      sass: '*'
+      stylus: '*'
+      terser: ^5.4.0
+    peerDependenciesMeta:
+      less:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+      terser:
+        optional: true
+    dependencies:
+      esbuild: 0.15.10
+      postcss: 8.4.17
+      resolve: 1.22.1
+      rollup: 2.78.1
+      sass: 1.55.0
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: true
+
+  /vue-clipboard3/2.0.0:
+    resolution: {integrity: sha512-Q9S7dzWGax7LN5iiSPcu/K1GGm2gcBBlYwmMsUc5/16N6w90cbKow3FnPmPs95sungns4yvd9/+JhbAznECS2A==}
+    dependencies:
+      clipboard: 2.0.11
+    dev: false
+
+  /vue-demi/0.13.11_vue@3.2.40:
+    resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+    dependencies:
+      vue: 3.2.40
+    dev: false
+
+  /vue-eslint-parser/9.1.0_eslint@8.25.0:
+    resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==}
+    engines: {node: ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: '>=6.0.0'
+    dependencies:
+      debug: 4.3.4
+      eslint: 8.25.0
+      eslint-scope: 7.1.1
+      eslint-visitor-keys: 3.3.0
+      espree: 9.4.0
+      esquery: 1.4.0
+      lodash: 4.17.21
+      semver: 7.3.8
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /vue-grid-layout/3.0.0-beta1:
+    resolution: {integrity: sha512-MsW0yfYNtnAO/uDhfZvkP6effxSJxvhAFbIL37x6Rn3vW9xf0WHVefKaSbQMLpSq3mXnR6ut0pg2Cd5lqIIZzg==}
+    dependencies:
+      '@interactjs/actions': 1.10.17
+      '@interactjs/auto-start': 1.10.17
+      '@interactjs/dev-tools': 1.10.17_cn5slzagijafj3kjb52cs5znym
+      '@interactjs/interactjs': 1.10.17
+      '@interactjs/modifiers': 1.10.17
+      element-resize-detector: 1.2.4
+      mitt: 2.1.0
+    transitivePeerDependencies:
+      - '@interactjs/core'
+      - '@interactjs/utils'
+    dev: false
+
+  /vue-i18n/9.2.2_vue@3.2.40:
+    resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==}
+    engines: {node: '>= 14'}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      '@intlify/core-base': 9.2.2
+      '@intlify/shared': 9.2.2
+      '@intlify/vue-devtools': 9.2.2
+      '@vue/devtools-api': 6.4.4
+      vue: 3.2.40
+    dev: false
+
+  /vue-router/4.1.5_vue@3.2.40:
+    resolution: {integrity: sha512-IsvoF5D2GQ/EGTs/Th4NQms9gd2NSqV+yylxIyp/OYp8xOwxmU8Kj/74E9DTSYAyH5LX7idVUngN3JSj1X4xcQ==}
+    peerDependencies:
+      vue: ^3.2.0
+    dependencies:
+      '@vue/devtools-api': 6.4.4
+      vue: 3.2.40
+    dev: false
+
+  /vue/3.2.40:
+    resolution: {integrity: sha512-1mGHulzUbl2Nk3pfvI5aXYYyJUs1nm4kyvuz38u4xlQkLUn1i2R7nDbI4TufECmY8v1qNBHYy62bCaM+3cHP2A==}
+    dependencies:
+      '@vue/compiler-dom': 3.2.40
+      '@vue/compiler-sfc': 3.2.40
+      '@vue/runtime-dom': 3.2.40
+      '@vue/server-renderer': 3.2.40_vue@3.2.40
+      '@vue/shared': 3.2.40
+
+  /which/2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+    dependencies:
+      isexe: 2.0.0
+    dev: true
+
+  /wildcard/1.1.2:
+    resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
+    dev: false
+
+  /word-wrap/1.2.3:
+    resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+    engines: {node: '>=0.10.0'}
+    dev: true
+
+  /wrappy/1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+    dev: true
+
+  /xml-name-validator/4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+    dev: true
+
+  /yallist/4.0.0:
+    resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+    dev: true
+
+  /yocto-queue/0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+    dev: true
+
+  /zrender/5.4.0:
+    resolution: {integrity: sha512-rOS09Z2HSVGFs2dn/TuYk5BlCaZcVe8UDLLjj1ySYF828LATKKdxuakSZMvrDz54yiKPDYVfjdKqcX8Jky3BIA==}
+    dependencies:
+      tslib: 2.3.0
+    dev: false

+ 1 - 0
Web/src/api-services/models/update-db-table-input.ts

@@ -42,3 +42,4 @@ export interface UpdateDbTableInput {
      */
     description?: string | null;
 }
+

+ 40 - 0
Web/src/api/main/generatetest.ts

@@ -0,0 +1,40 @@
+import request from '/@/utils/request';
+enum Api {
+  Addgeneratetest = '/generatetest/add',
+  Deletegeneratetest = '/generatetest/delete',
+  Updategeneratetest = '/generatetest/edit',
+  GetgeneratetestPage = '/generatetest/page',
+}
+
+// 增加GenerateTest
+export const addgeneratetest = (params?: any) =>
+	request({
+		url: Api.Addgeneratetest,
+		method: 'post',
+		data: params,
+	});
+
+// 删除GenerateTest
+export const deletegeneratetest = (params?: any) => 
+	request({
+			url: Api.Deletegeneratetest,
+			method: 'post',
+			data: params,
+		});
+
+// 编辑GenerateTest
+export const updategeneratetest = (params?: any) => 
+	request({
+			url: Api.Updategeneratetest,
+			method: 'post',
+			data: params,
+		});
+
+// 分页查询GenerateTest
+export const getgeneratetestPageList = (params?: any) => 
+	request({
+			url: Api.GetgeneratetestPage,
+			method: 'get',
+			data: params,
+		});
+

+ 243 - 0
Web/src/api/system/admin.ts

@@ -0,0 +1,243 @@
+import request from '/@/utils/request';
+
+enum Api {
+	// 获取菜单列表
+	GetMenuList = '/sysMenu/list',
+	// 字典接口
+	GetDictTypePageList = '/sysDictType/pageList',
+	GetDictTypeList = '/sysDictType/list',
+	AddDictType = '/sysDictType/add',
+	UpdateDictType = '/sysDictType/update',
+	DeleteDictType = '/sysDictType/delete',
+
+	GetDictDataPageList = '/sysDictData/pageList',
+	AddDictData = '/sysDictData/add',
+	UpdateDictData = '/sysDictData/update',
+	DeleteDictData = '/sysDictData/delete',
+	GetDictDataDropdown = '/sysDictData/DictDataDropdown',
+	QueryDictDataDropdown = '/sysDictData/queryDictDataDropdown',
+	// 代码生成接口
+	GetGeneratePage = '/codeGenerate/page',
+	AddGenerate = '/codeGenerate/add',
+	UpdateGenerate = '/codeGenerate/edit',
+	DeleGenerate = '/codeGenerate/delete',
+	GetTableList = '/codeGenerate/InformationList',
+	GetColumnList = '/codeGenerate/ColumnList',
+	GenerateRunLocal = '/codeGenerate/runLocal',
+	GenerateRunDown = '/codeGenerate/runDown',
+	GetGenerateConfigList = '/sysCodeGenerateConfig/list',
+	UpdateGenerateConfig = '/sysCodeGenerateConfig/edit',
+	GetDatabaseList = '/codeGenerate/DatabaseList',
+
+	// 数据库接口
+	GetColumnInfoList = '/sysDatabase/columnList',
+	GetTableInfoList = '/sysDatabase/tableList',
+	AddTable = '/sysDatabase/table/add',
+	UpdateTable = '/sysDatabase/table/update',
+	DeleTetable = '/sysDatabase/table/delete',
+	AddColumn = '/sysDatabase/column/add',
+	UpdateColumn = '/sysDatabase/column/update',
+	DeleteColumn = '/sysDatabase/column/delete',
+	CreateEntity = '/sysDatabase/entity/create',
+
+	// 常量下拉框接口
+	AllConstSelector = '/constSelector/allConstSelector',
+	ConstSelector = '/constSelector/constSelector',
+	AllConstSelectorWithOptions = '/constSelector/allConstSelectorWithOptions',
+}
+
+////////// 常量下拉框管理接口 //////////
+// 获取所有常量下拉框列表
+export const getAllConstSelector = () =>
+	request({
+		url: Api.AllConstSelector,
+		method: 'get',
+	});
+
+// 根据类名获取下拉框数据
+export const getConstSelector = (typeName?: string) =>
+	request({
+		url: Api.ConstSelector,
+		method: 'get',
+		data: { typeName },
+	});
+
+// 获取所有下拉框及选项
+export const getAllConstSelectorWithOptions = () =>
+	request({
+		url: Api.AllConstSelectorWithOptions,
+		method: 'get',
+	});
+
+export const getDictTypeList = (params?: any) =>
+	request({
+		url: Api.GetDictTypeList,
+		method: 'get',
+		data: params,
+	});
+
+export const getMenuList = (params?: any) =>
+	request({
+		url: Api.GetMenuList,
+		method: 'get',
+		data: params,
+	});
+
+// 从字典中值,下拉框控件使用
+export const getDictDataDropdown = (params: any) =>
+	request({
+		url: Api.GetDictDataDropdown + '/' + params,
+		method: 'get',
+	});
+
+////////// 代码生成接口 //////////
+// 分页查询代码生成
+export const getGeneratePage = (params?: any) =>
+	request({
+		url: Api.GetGeneratePage,
+		method: 'get',
+		data: params,
+	});
+
+// 增加代码生成
+export const addGenerate = (params: any) =>
+	request({
+		url: Api.AddGenerate,
+		method: 'post',
+		data: params,
+	});
+
+// 修改代码生成
+export const updateGenerate = (params: any) =>
+	request({
+		url: Api.UpdateGenerate,
+		method: 'post',
+		data: params,
+	});
+
+// 删除代码生成
+export const deleGenerate = (params: any) =>
+	request({
+		url: Api.DeleGenerate,
+		method: 'post',
+		data: params,
+	});
+
+// 获取数据库(上下文定位器)集合
+export const getDatabaseList = (params?: any) =>
+	request({
+		url: Api.GetDatabaseList,
+		method: 'get',
+		data: params,
+	});
+
+// 获取数据库表(实体)集合
+export const getTableList = (configId: string) =>
+	request({
+		url: Api.GetTableList + '/' + configId,
+		method: 'get',
+	});
+
+// 根据表名获取列
+export const getColumnList = (configId: string, tableName: string) =>
+	request({
+		url: Api.GetColumnList + '/' + configId + '/' + tableName,
+		method: 'get',
+	});
+
+// 本地生成
+export const generateRunLocal = (params: any) =>
+	request({
+		url: Api.GenerateRunLocal,
+		method: 'post',
+		data: params,
+	});
+
+// 代码生成详细配置列表
+export const getGenerateConfigList = (params?: any) =>
+	request({
+		url: Api.GetGenerateConfigList,
+		method: 'get',
+		data: params,
+	});
+
+// 编辑代码生成详细配置
+export const updateGenerateConfig = (params: any) =>
+	request({
+		url: Api.UpdateGenerateConfig,
+		method: 'post',
+		data: params,
+	});
+
+//////////数据库管理接口 //////////
+// 获取表字段
+export const getColumnInfoList = (params: any) =>
+	request({
+		url: Api.GetColumnInfoList,
+		method: 'get',
+		data: params,
+	});
+
+// 获取所有表
+export const getTableInfoList = (params?: any) =>
+	request({
+		url: Api.GetTableInfoList,
+		method: 'get',
+		data: params,
+	});
+
+// 添加表
+export const addTable = (params: any) =>
+	request({
+		url: Api.AddTable,
+		method: 'post',
+		data: params,
+	});
+
+// 修改表
+export const updateTable = (params: any) =>
+	request({
+		url: Api.UpdateTable,
+		method: 'post',
+		data: params,
+	});
+
+// 删除表
+export const deleteTable = (params: any) =>
+	request({
+		url: Api.DeleTetable,
+		method: 'post',
+		data: params,
+	});
+
+// 添加字段
+export const addColumn = (params: any) =>
+	request({
+		url: Api.AddColumn,
+		method: 'post',
+		data: params,
+	});
+
+// 修改字段
+export const updateColumn = (params: any) =>
+	request({
+		url: Api.UpdateColumn,
+		method: 'post',
+		data: params,
+	});
+
+// 删除字段
+export const deleteColumn = (params: any) =>
+	request({
+		url: Api.DeleteColumn,
+		method: 'post',
+		data: params,
+	});
+
+// 生成实体
+export const createEntity = (params: any) =>
+	request({
+		url: Api.CreateEntity,
+		method: 'post',
+		data: params,
+	});

+ 30 - 0
Web/src/api/system/enum.ts

@@ -0,0 +1,30 @@
+/**
+ * 
+ * @export
+ * @enum {string}
+ */
+ export enum DbObjectType {
+    NUMBER_0 = 0,
+    NUMBER_1 = 1,
+    NUMBER_2 = 2
+}
+/**
+ * 系统菜单类型枚举<br />&nbsp;目录 Dir = 1<br />&nbsp;菜单 Menu = 2<br />&nbsp;按钮 Btn = 3<br />
+ * @export
+ * @enum {string}
+ */
+ export enum MenuTypeEnum {
+    NUMBER_1 = 1,
+    NUMBER_2 = 2,
+    NUMBER_3 = 3
+}
+
+/**
+ * 通用状态枚举<br />&nbsp;启用 Enable = 1<br />&nbsp;停用 Disable = 2<br />
+ * @export
+ * @enum {string}
+ */
+ export enum StatusEnum {
+    NUMBER_1 = 1,
+    NUMBER_2 = 2
+}

+ 754 - 0
Web/src/api/system/interface.ts

@@ -0,0 +1,754 @@
+import { DbObjectType, MenuTypeEnum, StatusEnum } from './enum';
+
+/**
+ *
+ * @export
+ * @interface DbTableInfo
+ */
+export interface DbTableInfo {
+	/**
+	 *
+	 * @type {string}
+	 * @memberof DbTableInfo
+	 */
+	name?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof DbTableInfo
+	 */
+	description?: string | null;
+	/**
+	 *
+	 * @type {DbObjectType}
+	 * @memberof DbTableInfo
+	 */
+	// dbObjectType?: DbObjectType;
+}
+
+/**
+ *
+ * @export
+ * @interface EditRecordRow
+ */
+export interface EditRecordRow {
+	columnDescription?: string | null;
+	dataType?: string | null;
+	dbColumnName?: string | null;
+	decimalDigits: number;
+	isIdentity: number;
+	isNullable: number;
+	isPrimarykey: number;
+	length: number;
+	key?: number;
+	editable?: boolean;
+	isNew: boolean;
+}
+
+/**
+ *
+ * @export
+ * @interface UpdateDbTableInput
+ */
+export interface UpdateDbTableInput {
+	/**
+	 *
+	 * @type {string}
+	 * @memberof UpdateDbTableInput
+	 */
+	configId?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof UpdateDbTableInput
+	 */
+	tableName?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof UpdateDbTableInput
+	 */
+	oldTableName?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof UpdateDbTableInput
+	 */
+	description?: string | null;
+}
+
+/**
+ *
+ * @export
+ * @interface AddDbColumnInput
+ */
+export interface AddDbColumnInput {
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	configId?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	tableName?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	columnDescription?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	dataType?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	dbColumnName?: string | null;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	decimalDigits: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	isIdentity: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	isNullable: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	isPrimarykey: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	length: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	key: number;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	editable: boolean;
+	/**
+	 *
+	 * @type {string}
+	 * @memberof AddDbColumnInput
+	 */
+	isNew: boolean;
+}
+
+/**
+ *
+ * @export
+ * @interface AddCodeGenInput
+ */
+export interface AddCodeGenInput {
+	/**
+	 * 当前页码
+	 * @type {number}
+	 * @memberof AddCodeGenInput
+	 */
+	page?: number;
+	/**
+	 * 页码容量
+	 * @type {number}
+	 * @memberof AddCodeGenInput
+	 */
+	pageSize?: number;
+	/**
+	 * 排序字段
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	field?: string | null;
+	/**
+	 * 排序方向
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	order?: string | null;
+	/**
+	 * 降序排序
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	descStr?: string | null;
+	/**
+	 * 类名
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	className?: string | null;
+	/**
+	 * 是否移除表前缀
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	tablePrefix?: string | null;
+	/**
+	 * 库定位器名
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	configId?: string | null;
+	/**
+	 * 数据库名(保留字段)
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	dbName?: string | null;
+	/**
+	 * 数据库类型
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	dbType: string;
+	/**
+	 * 数据库类型
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	dbTypeString?: string | null;
+	/**
+	 * 数据库链接
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	connectionString?: string | null;
+	/**
+	 * 功能名(数据库表名称)
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	tableComment?: string | null;
+	/**
+	 * 菜单应用分类(应用编码)
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	menuApplication?: string | null;
+	/**
+	 * 数据库表名
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	tableName: string;
+	/**
+	 * 业务名(业务代码包名称)
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	busName: string;
+	/**
+	 * 命名空间
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	nameSpace: string;
+	/**
+	 * 作者姓名
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	authorName: string;
+	/**
+	 * 生成方式
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	generateType: string;
+	/**
+	 * 菜单父级
+	 * @type {number}
+	 * @memberof AddCodeGenInput
+	 */
+	menuPid: number;
+	/**
+	 * 菜单父级
+	 * @type {number}
+	 * @memberof AddCodeGenInput
+	 */
+	id: number;
+	/**
+	 * 生成方式
+	 * @type {string}
+	 * @memberof AddCodeGenInput
+	 */
+	type: string;
+}
+/**
+ * 代码生成表
+ * @export
+ * @interface SysCodeGen
+ */
+export interface SysCodeGen {
+	/**
+	 * 雪花Id
+	 * @type {number}
+	 * @memberof SysCodeGen
+	 */
+	id?: number;
+	/**
+	 * 创建时间
+	 * @type {Date}
+	 * @memberof SysCodeGen
+	 */
+	createTime?: Date | null;
+	/**
+	 * 更新时间
+	 * @type {Date}
+	 * @memberof SysCodeGen
+	 */
+	updateTime?: Date | null;
+	/**
+	 * 创建者Id
+	 * @type {number}
+	 * @memberof SysCodeGen
+	 */
+	createUserId?: number | null;
+	/**
+	 * 修改者Id
+	 * @type {number}
+	 * @memberof SysCodeGen
+	 */
+	updateUserId?: number | null;
+	/**
+	 * 软删除
+	 * @type {boolean}
+	 * @memberof SysCodeGen
+	 */
+	isDelete?: boolean;
+	/**
+	 * 作者姓名
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	authorName?: string | null;
+	/**
+	 * 是否移除表前缀
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	tablePrefix?: string | null;
+	/**
+	 * 生成方式
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	generateType?: string | null;
+	/**
+	 * 库定位器名
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	configId?: string | null;
+	/**
+	 * 数据库名(保留字段)
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	dbName?: string | null;
+	/**
+	 * 数据库类型
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	dbType?: string | null;
+	/**
+	 * 数据库链接
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	connectionString?: string | null;
+	/**
+	 * 数据库表名
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	tableName?: string | null;
+	/**
+	 * 命名空间
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	nameSpace?: string | null;
+	/**
+	 * 业务名
+	 * @type {string}
+	 * @memberof SysCodeGen
+	 */
+	busName?: string | null;
+	/**
+	 * 菜单编码
+	 * @type {number}
+	 * @memberof SysCodeGen
+	 */
+	menuPid?: number;
+}
+
+/**
+ * 系统菜单表
+ * @export
+ * @interface SysMenu
+ */
+export interface SysMenu {
+	/**
+	 * 雪花Id
+	 * @type {number}
+	 * @memberof SysMenu
+	 */
+	id?: number;
+	/**
+	 * 创建时间
+	 * @type {Date}
+	 * @memberof SysMenu
+	 */
+	createTime?: Date | null;
+	/**
+	 * 更新时间
+	 * @type {Date}
+	 * @memberof SysMenu
+	 */
+	updateTime?: Date | null;
+	/**
+	 * 创建者Id
+	 * @type {number}
+	 * @memberof SysMenu
+	 */
+	createUserId?: number | null;
+	/**
+	 * 修改者Id
+	 * @type {number}
+	 * @memberof SysMenu
+	 */
+	updateUserId?: number | null;
+	/**
+	 * 软删除
+	 * @type {boolean}
+	 * @memberof SysMenu
+	 */
+	isDelete?: boolean;
+	/**
+	 * 父Id
+	 * @type {number}
+	 * @memberof SysMenu
+	 */
+	pid?: number;
+	/**
+	 *
+	 * @type {MenuTypeEnum}
+	 * @memberof SysMenu
+	 */
+	type?: MenuTypeEnum;
+	/**
+	 * 名称
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	name?: string | null;
+	/**
+	 * 路由地址
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	path?: string | null;
+	/**
+	 * 组件路径
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	component?: string | null;
+	/**
+	 * 重定向
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	redirect?: string | null;
+	/**
+	 * 权限标识
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	permission?: string | null;
+	/**
+	 * 标题
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	title: string;
+	/**
+	 * 图标
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	icon?: string | null;
+	/**
+	 * 是否内嵌
+	 * @type {boolean}
+	 * @memberof SysMenu
+	 */
+	isIframe?: boolean;
+	/**
+	 * 外链链接
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	outLink?: string | null;
+	/**
+	 * 是否隐藏
+	 * @type {boolean}
+	 * @memberof SysMenu
+	 */
+	isHide?: boolean;
+	/**
+	 * 是否缓存
+	 * @type {boolean}
+	 * @memberof SysMenu
+	 */
+	isKeepAlive?: boolean;
+	/**
+	 * 是否固定
+	 * @type {boolean}
+	 * @memberof SysMenu
+	 */
+	isAffix?: boolean;
+	/**
+	 * 排序
+	 * @type {number}
+	 * @memberof SysMenu
+	 */
+	order?: number;
+	/**
+	 *
+	 * @type {StatusEnum}
+	 * @memberof SysMenu
+	 */
+	status?: StatusEnum;
+	/**
+	 * 备注
+	 * @type {string}
+	 * @memberof SysMenu
+	 */
+	remark?: string | null;
+	/**
+	 * 菜单子项
+	 * @type {Array<SysMenu>}
+	 * @memberof SysMenu
+	 */
+	children?: Array<SysMenu> | null;
+}
+
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Admin.NET
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 代码生成字段配置表
+ * @export
+ * @interface SysCodeGenConfig
+ */
+ export interface SysCodeGenConfig {
+    /**
+     * 雪花Id
+     * @type {number}
+     * @memberof SysCodeGenConfig
+     */
+    id?: number;
+    /**
+     * 创建时间
+     * @type {Date}
+     * @memberof SysCodeGenConfig
+     */
+    createTime?: Date | null;
+    /**
+     * 更新时间
+     * @type {Date}
+     * @memberof SysCodeGenConfig
+     */
+    updateTime?: Date | null;
+    /**
+     * 创建者Id
+     * @type {number}
+     * @memberof SysCodeGenConfig
+     */
+    createUserId?: number | null;
+    /**
+     * 修改者Id
+     * @type {number}
+     * @memberof SysCodeGenConfig
+     */
+    updateUserId?: number | null;
+    /**
+     * 软删除
+     * @type {boolean}
+     * @memberof SysCodeGenConfig
+     */
+    isDelete?: boolean;
+    /**
+     * 代码生成主表Id
+     * @type {number}
+     * @memberof SysCodeGenConfig
+     */
+    codeGenId?: number;
+    /**
+     * 数据库字段名
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    columnName: string;
+    /**
+     * 字段描述
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    columnComment?: string | null;
+    /**
+     * .NET数据类型
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    netType?: string | null;
+    /**
+     * 作用类型(字典)
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    effectType?: string | null;
+    /**
+     * 外键实体名称
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    fkEntityName?: string | null;
+    /**
+     * 外键表名称
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    fkTableName?: string | null;
+    /**
+     * 外键显示字段
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    fkColumnName?: string | null;
+    /**
+     * 外键显示字段.NET类型
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    fkColumnNetType?: string | null;
+    /**
+     * 字典编码
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    dictTypeCode?: string | null;
+    /**
+     * 列表是否缩进(字典)
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    whetherRetract?: string | null;
+    /**
+     * 是否必填(字典)
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    whetherRequired?: string | null;
+    /**
+     * 是否是查询条件
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    queryWhether?: string | null;
+    /**
+     * 查询方式
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    queryType?: string | null;
+    /**
+     * 列表显示
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    whetherTable?: string | null;
+    /**
+     * 增改
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    whetherAddUpdate?: string | null;
+    /**
+     * 主键
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    columnKey?: string | null;
+    /**
+     * 数据库中类型(物理类型)
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    dataType?: string | null;
+    /**
+     * 是否通用字段
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    whetherCommon?: string | null;
+    /**
+     * 显示文本字段
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    displayColumn?: string | null;
+    /**
+     * 选中值字段
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    valueColumn?: string | null;
+    /**
+     * 父级字段
+     * @type {string}
+     * @memberof SysCodeGenConfig
+     */
+    pidColumn?: string | null;
+}

+ 2 - 0
Web/src/main.ts

@@ -17,11 +17,13 @@ import VueGridLayout from 'vue-grid-layout';
 import VueSignaturePad from 'vue-signature-pad'; // 电子签名
 import vue3TreeOrg from 'vue3-tree-org'; // 组织架构图
 import 'vue3-tree-org/lib/vue3-tree-org.css';
+import { setupConstSelectorFilter } from './utils/helper/constSelectorHelper';
 
 const app = createApp(App);
 
 directive(app);
 other.elSvg(app);
+setupConstSelectorFilter(app);
 
 app.use(pinia).use(router).use(ElementPlus, { i18n: i18n.global.t }).use(VForm3).use(i18n).use(VueGridLayout).use(VueSignaturePad).use(vue3TreeOrg).mount('#app');
 

+ 1 - 0
Web/src/stores/interface/index.ts

@@ -19,6 +19,7 @@ export interface UserInfosState {
 }
 export interface UserInfosStates {
 	userInfos: UserInfosState;
+	constSelectorWithOptions: [];
 }
 
 // 路由缓存列表

+ 13 - 0
Web/src/stores/userInfo.ts

@@ -4,6 +4,8 @@ import { Session } from '/@/utils/storage';
 
 import { getAPI } from '/@/utils/axios-utils';
 import { SysAuthApi } from '/@/api-services/api';
+import request from '/@/utils/request';
+import { getAllConstSelectorWithOptions } from '/@/api/system/admin';
 
 /**
  * 用户信息
@@ -12,7 +14,13 @@ import { SysAuthApi } from '/@/api-services/api';
 export const useUserInfo = defineStore('userInfo', {
 	state: (): UserInfosStates => ({
 		userInfos: {} as UserInfosState,
+		constSelectorWithOptions: [],
 	}),
+	getters: {
+		getAllConstSelectorWithOptions(): any[] {
+			return this.constSelectorWithOptions || getAllConstSelectorWithOptions();
+		},
+	},
 	actions: {
 		async setUserInfos() {
 			// 缓存用户信息
@@ -48,5 +56,10 @@ export const useUserInfo = defineStore('userInfo', {
 					});
 			});
 		},
+		// 获取当前用户信息
+		async getAllConstSelectorWithOptionsAction() {
+			var res = await getAllConstSelectorWithOptions();
+			this.constSelectorWithOptions = res.data.result ?? [];
+		},
 	},
 });

+ 32 - 0
Web/src/utils/helper/constSelectorHelper.ts

@@ -0,0 +1,32 @@
+import type { App } from 'vue';
+import { useUserInfo } from '/@/stores/userInfo';
+
+export function setupConstSelectorFilter(app: App) {
+  // 全局过滤器  在vue文件中调用  $filters.codeToName(code,type)
+  app.config.globalProperties.$filters = {
+    codeToName(code:any, type:any) {
+      return codeToName(code, type);
+    },
+  };
+}
+
+//常量值转换
+export function codeToName(code:any, type:any) {
+  const userStore = useUserInfo();
+  try {
+    const name = userStore.constSelectorWithOptions
+      .filter((x:any) => x.code === type)
+      .map((x:any) => x.data)
+      .map((x:any) => x.filter((y:any) => y.code === code))
+      .map((x:any) => x[0].name);
+    return name[0];
+  } catch (error) {
+    return code;
+  }
+}
+
+export function getSelector(type:any) {
+  const userStore = useUserInfo();
+  const selector = userStore.constSelectorWithOptions.filter((x:any) => x.code === type)[0].data;
+  return selector;
+}

+ 175 - 21
Web/src/utils/request.ts

@@ -1,20 +1,74 @@
-import axios from 'axios';
+import axios, { AxiosInstance } from 'axios';
 import { ElMessage, ElMessageBox } from 'element-plus';
-import { Session } from '/@/utils/storage';
+import { Local, Session } from '/@/utils/storage';
 
 // 配置新建一个 axios 实例
-const service = axios.create({
+export const service = axios.create({
 	baseURL: import.meta.env.VITE_API_URL as any,
 	timeout: 50000,
 	headers: { 'Content-Type': 'application/json' },
 });
 
+// token 键定义
+export const accessTokenKey = 'access-token';
+export const refreshAccessTokenKey = `x-${accessTokenKey}`;
+
+// 获取 token
+export const getToken = () => {
+	return Local.get(accessTokenKey);
+};
+
+// 清除 token
+export const clearAccessTokens = () => {
+	Local.remove(accessTokenKey);
+	Local.remove(refreshAccessTokenKey);
+
+	// 清除其他
+	Session.clear();
+
+	// 刷新浏览器
+	window.location.reload();
+};
+
+// axios 默认实例
+export const axiosInstance: AxiosInstance = axios;
+
 // 添加请求拦截器
 service.interceptors.request.use(
 	(config) => {
-		// 在发送请求之前做些什么 token
-		if (Session.get('token')) {
-			(<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
+		// // 在发送请求之前做些什么 token
+		// if (Session.get('token')) {
+		// 	(<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
+		// }
+
+		// 获取本地的 token
+		const accessToken = Local.get(accessTokenKey);
+		if (accessToken) {
+			// 将 token 添加到请求报文头中
+			config.headers!['Authorization'] = `Bearer ${accessToken}`;
+
+			// 判断 accessToken 是否过期
+			const jwt: any = decryptJWT(accessToken);
+			const exp = getJWTDate(jwt.exp as number);
+
+			// token 已经过期
+			if (new Date() >= exp) {
+				// 获取刷新 token
+				const refreshAccessToken = Local.get(refreshAccessTokenKey);
+
+				// 携带刷新 token
+				if (refreshAccessToken) {
+					config.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`;
+				}
+			}
+			// debugger
+			// get请求映射params参数
+			if (config.method?.toLowerCase() === 'get' && config.data) {
+				let url = config.url + '?' + tansParams(config.data);
+				url = url.slice(0, -1);
+				config.data = {};
+				config.url = url;
+			}
 		}
 		return config;
 	},
@@ -26,24 +80,76 @@ service.interceptors.request.use(
 
 // 添加响应拦截器
 service.interceptors.response.use(
-	(response) => {
-		// 对响应数据做点什么
-		const res = response.data;
-		if (res.code && res.code !== 0) {
-			// `token` 过期或者账号已在别处登录
-			if (res.code === 401 || res.code === 4001) {
-				Session.clear(); // 清除浏览器全部临时缓存
-				window.location.href = '/'; // 去登录页
-				ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
-					.then(() => {})
-					.catch(() => {});
-			}
-			return Promise.reject(service.interceptors.response);
-		} else {
-			return response.data;
+	(res) => {
+		// // 对响应数据做点什么
+		// const res = response.data;
+		// if (res.code && res.code !== 0) {
+		// 	// `token` 过期或者账号已在别处登录
+		// 	if (res.code === 401 || res.code === 4001) {
+		// 		Session.clear(); // 清除浏览器全部临时缓存
+		// 		window.location.href = '/'; // 去登录页
+		// 		ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
+		// 			.then(() => {})
+		// 			.catch(() => {});
+		// 	}
+		// 	return Promise.reject(service.interceptors.response);
+		// } else {
+		// 	return response.data;
+		// }
+		// 获取状态码和返回数据
+		var status = res.status;
+		var serve = res.data;
+
+		// 处理 401
+		if (status === 401) {
+			clearAccessTokens();
+		}
+
+		// 处理未进行规范化处理的
+		if (status >= 400) {
+			throw new Error(res.statusText || 'Request Error.');
+		}
+
+		// 处理规范化结果错误
+		if (serve && serve.hasOwnProperty('errors') && serve.errors) {
+			throw new Error(JSON.stringify(serve.errors || 'Request Error.'));
+		}
+
+		// 读取响应报文头 token 信息
+		var accessToken = res.headers[accessTokenKey];
+		var refreshAccessToken = res.headers[refreshAccessTokenKey];
+
+		// 判断是否是无效 token
+		if (accessToken === 'invalid_token') {
+			clearAccessTokens();
+		}
+		// 判断是否存在刷新 token,如果存在则存储在本地
+		else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
+			Local.set(accessTokenKey, accessToken);
+			Local.set(refreshAccessTokenKey, refreshAccessToken);
 		}
+
+		// 响应拦截及自定义处理
+		if (serve.code === 401) {
+			clearAccessTokens();
+		} else if (serve.code === undefined) {
+			return Promise.resolve(res);
+		} else if (serve.code !== 200) {
+			var message = JSON.stringify(serve.message);
+			ElMessage.error(message);
+			throw new Error(message);
+		}
+
+		return res;
 	},
 	(error) => {
+		// 处理响应错误
+		if (error.response) {
+			if (error.response.status === 401) {
+				clearAccessTokens();
+			}
+		}
+
 		// 对响应错误做点什么
 		if (error.message.indexOf('timeout') != -1) {
 			ElMessage.error('网络超时');
@@ -53,9 +159,57 @@ service.interceptors.response.use(
 			if (error.response.data) ElMessage.error(error.response.statusText);
 			else ElMessage.error('接口路径找不到');
 		}
+
 		return Promise.reject(error);
 	}
 );
 
+/**
+ *  参数处理
+ * @param {*} params  参数
+ */
+export function tansParams(params: any) {
+	let result = '';
+	for (const propName of Object.keys(params)) {
+		const value = params[propName];
+		var part = encodeURIComponent(propName) + '=';
+		if (value !== null && value !== '' && typeof value !== 'undefined') {
+			if (typeof value === 'object') {
+				for (const key of Object.keys(value)) {
+					if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
+						let params = propName + '[' + key + ']';
+						var subPart = encodeURIComponent(params) + '=';
+						result += subPart + encodeURIComponent(value[key]) + '&';
+					}
+				}
+			} else {
+				result += part + encodeURIComponent(value) + '&';
+			}
+		}
+	}
+	return result;
+}
+
+/**
+ * 解密 JWT token 的信息
+ * @param token jwt token 字符串
+ * @returns <any>object
+ */
+export function decryptJWT(token: string): any {
+	token = token.replace(/_/g, '/').replace(/-/g, '+');
+	var json = decodeURIComponent(escape(window.atob(token.split('.')[1])));
+	return JSON.parse(json);
+}
+
+/**
+ * 将 JWT 时间戳转换成 Date
+ * @description 主要针对 `exp`,`iat`,`nbf`
+ * @param timestamp 时间戳
+ * @returns Date 对象
+ */
+export function getJWTDate(timestamp: number): Date {
+	return new Date(timestamp * 1000);
+}
+
 // 导出 axios 实例
 export default service;

+ 236 - 0
Web/src/utils/ruoyi.js

@@ -0,0 +1,236 @@
+
+
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+// 日期格式化
+export function parseTime(time, pattern) {
+  if (arguments.length === 0 || !time) {
+    return null
+  }
+  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+      time = parseInt(time)
+    } else if (typeof time === 'string') {
+      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
+    }
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+// 表单重置
+export function resetForm(refName) {
+  if (this.$refs[refName]) {
+    this.$refs[refName].resetFields();
+  }
+}
+
+// 添加日期范围
+export function addDateRange(params, dateRange, propName) {
+  let search = params;
+  search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
+  dateRange = Array.isArray(dateRange) ? dateRange : [];
+  if (typeof (propName) === 'undefined') {
+    search.params['beginTime'] = dateRange[0];
+    search.params['endTime'] = dateRange[1];
+  } else {
+    search.params['begin' + propName] = dateRange[0];
+    search.params['end' + propName] = dateRange[1];
+  }
+  return search;
+}
+
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+  if (value === undefined) {
+    return "";
+  }
+  var actions = [];
+  Object.keys(datas).some((key) => {
+    if (datas[key].value == ('' + value)) {
+      actions.push(datas[key].label);
+      return true;
+    }
+  })
+  if (actions.length === 0) {
+    actions.push(value);
+  }
+  return actions.join('');
+}
+
+// 回显数据字典(字符串数组)
+export function selectDictLabels(datas, value, separator) {
+  if (value === undefined) {
+    return "";
+  }
+  var actions = [];
+  var currentSeparator = undefined === separator ? "," : separator;
+  var temp = value.split(currentSeparator);
+  Object.keys(value.split(currentSeparator)).some((val) => {
+    var match = false;
+    Object.keys(datas).some((key) => {
+      if (datas[key].value == ('' + temp[val])) {
+        actions.push(datas[key].label + currentSeparator);
+        match = true;
+      }
+    })
+    if (!match) {
+      actions.push(temp[val] + currentSeparator);
+    }
+  })
+  return actions.join('').substring(0, actions.join('').length - 1);
+}
+
+// 字符串格式化(%s )
+export function sprintf(str) {
+  var args = arguments, flag = true, i = 1;
+  str = str.replace(/%s/g, function () {
+    var arg = args[i++];
+    if (typeof arg === 'undefined') {
+      flag = false;
+      return '';
+    }
+    return arg;
+  });
+  return flag ? str : '';
+}
+
+// 转换字符串,undefined,null等转化为""
+export function parseStrEmpty(str) {
+  if (!str || str == "undefined" || str == "null") {
+    return "";
+  }
+  return str;
+}
+
+// 数据合并
+export function mergeRecursive(source, target) {
+  for (var p in target) {
+    try {
+      if (target[p].constructor == Object) {
+        source[p] = mergeRecursive(source[p], target[p]);
+      } else {
+        source[p] = target[p];
+      }
+    } catch (e) {
+      source[p] = target[p];
+    }
+  }
+  return source;
+};
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ */
+export function handleTree(data, id, parentId, children) {
+  let config = {
+    id: id || 'id',
+    parentId: parentId || 'parentId',
+    childrenList: children || 'children'
+  };
+
+  var childrenListMap = {};
+  var nodeIds = {};
+  var tree = [];
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (childrenListMap[parentId] == null) {
+      childrenListMap[parentId] = [];
+    }
+    nodeIds[d[config.id]] = d;
+    childrenListMap[parentId].push(d);
+  }
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (nodeIds[parentId] == null) {
+      tree.push(d);
+    }
+  }
+
+  for (let t of tree) {
+    adaptToChildrenList(t);
+  }
+
+  function adaptToChildrenList(o) {
+    if (childrenListMap[o[config.id]] !== null) {
+      o[config.childrenList] = childrenListMap[o[config.id]];
+    }
+    if (o[config.childrenList]) {
+      for (let c of o[config.childrenList]) {
+        adaptToChildrenList(c);
+      }
+    }
+  }
+  return tree;
+}
+
+/**
+* 参数处理
+* @param {*} params  参数
+*/
+export function tansParams(params) {
+  let result = ''
+  for (const propName of Object.keys(params)) {
+    const value = params[propName];
+    var part = encodeURIComponent(propName) + "=";
+    if (value !== null && value !== "" && typeof (value) !== "undefined") {
+      if (typeof value === 'object') {
+        for (const key of Object.keys(value)) {
+          if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
+            let params = propName + '[' + key + ']';
+            var subPart = encodeURIComponent(params) + "=";
+            result += subPart + encodeURIComponent(value[key]) + "&";
+          }
+        }
+      } else {
+        result += part + encodeURIComponent(value) + "&";
+      }
+    }
+  }
+  return result
+}
+
+// 验证是否为blob格式
+export async function blobValidate(data) {
+  try {
+    const text = await data.text();
+    JSON.parse(text);
+    return false;
+  } catch (error) {
+    return true;
+  }
+}

+ 235 - 0
Web/src/views/system/codeGen/component/codeGenerateDialog.vue

@@ -0,0 +1,235 @@
+<template>
+	<div class="sys-codeGenerate-container">
+		<el-dialog v-model="isShowDialog" :title="title" draggable width="700px">
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="库定位器" prop="configId">
+							<el-select clearable v-model="ruleForm.configId" placeholder="库名" filterable @change="DbChanged()">
+								<el-option v-for="item in dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="数据库类型" prop="dbType" :rules="[{ required: true, message: '描述不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.dbTypeString" disabled />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="链接串" prop="connectionString">
+							<el-input v-model="ruleForm.connectionString" disabled clearable type="textarea" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="生成表" prop="tableName" :rules="[{ required: true, message: '生成表不能为空', trigger: 'blur' }]">
+							<el-select v-model="ruleForm.tableName" class="m-2" filterable clearable>
+								<el-option v-for="item in tableData" :key="item.entityName" :label="item.tableName" :value="item.entityName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="业务名" prop="busName">
+							<el-input v-model="ruleForm.busName" placeholder="请输入" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="父级菜单" prop="menuPid">
+							<el-cascader
+								:options="menuData"
+								:props="{ checkStrictly: true, emitPath: false, value: 'id', label: 'title' }"
+								placeholder="请选择上级菜单"
+								clearable
+								class="w100"
+								v-model="ruleForm.menuPid"
+							>
+								<template #default="{ node, data }">
+									<span>{{ data.title }}</span>
+									<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
+								</template>
+							</el-cascader>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="命名空间" prop="nameSpace">
+							<el-input v-model="ruleForm.nameSpace" clearable placeholder="请输入" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="作者姓名" prop="authorName">
+							<el-input v-model="ruleForm.authorName" clearable placeholder="请输入" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="生成方式" prop="generateType">
+							<el-select v-model="ruleForm.generateType" class="m-2" filterable clearable>
+								<el-option v-for="item in codeGenerateTypeList" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, onMounted, defineComponent, getCurrentInstance, ref } from 'vue';
+
+import { getDatabaseList, getTableList, addGenerate, updateGenerate } from '/@/api/system/admin';
+import { AddCodeGenInput, DbTableInfo } from '/@/api/system/interface';
+
+export default defineComponent({
+	name: 'codeGenerateDialog',
+	components: {},
+	props: {
+		title: {
+			type: String,
+			default: '',
+		},
+		menuData: {
+			type: Array,
+			default: () => [],
+		},
+		codeGenerateTypeList: {
+			type: Array,
+			default: () => [] as any,
+		},
+	},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as AddCodeGenInput,
+			tableData: [] as any,
+			dbData: [] as any,
+		});
+
+		onMounted(async () => {
+			var res = await getDatabaseList();
+			state.dbData = res.data.result;
+		});
+
+		// DbChanged
+		const DbChanged = async () => {
+			if (state.ruleForm.configId === '') return;
+			let res = await getTableList(state.ruleForm.configId as string);
+			state.tableData = res.data.result ?? [];
+
+			let db = state.dbData.filter((u: any) => u.configId == state.ruleForm.configId);
+			state.ruleForm.connectionString = db[0].connectionString;
+			state.ruleForm.dbType = db[0].dbType.toString();
+			state.ruleForm.dbTypeString = convertDbType(db[0].dbType);
+		};
+
+		// 打开弹窗
+		const openDialog = (addRow: AddCodeGenInput) => {
+			state.ruleForm = addRow;
+			if (state.ruleForm .type === '1') {
+				state.ruleForm.nameSpace = 'Admin.NET.Application';
+				state.ruleForm.authorName = 'one';
+				state.ruleForm.generateType = '2';
+			} else {
+				state.ruleForm.dbTypeString = convertDbType(parseInt(state.ruleForm.dbType));
+			}
+			state.isShowDialog = true;
+		};
+
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('submitRefresh');
+			state.isShowDialog = false;
+		};
+
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+
+				if (state.ruleForm.type === '1') {
+					await addGenerate(state.ruleForm);
+				} else {
+					await updateGenerate(state.ruleForm);
+				}
+				closeDialog();
+			});
+		};
+
+		const convertDbType = (dbType: number) => {
+			let result = '';
+			switch (dbType) {
+				case 0:
+					result = 'MySql';
+					break;
+				case 1:
+					result = 'SqlServer';
+					break;
+				case 2:
+					result = 'Sqlite';
+					break;
+				case 3:
+					result = 'Oracle';
+					break;
+				case 4:
+					result = 'PostgreSql';
+					break;
+				case 5:
+					result = 'Dm';
+					break;
+				case 6:
+					result = 'Kdbndp';
+					break;
+				case 7:
+					result = 'Oscar';
+					break;
+				case 8:
+					result = 'MySqlConnector';
+					break;
+				case 9:
+					result = 'Access';
+					break;
+				default:
+					result = 'Custom';
+					break;
+			}
+			return result;
+		};
+
+		const isOrNotSelect = () => {
+			return [
+				{
+					label: '是',
+					value: 1,
+				},
+				{
+					label: '否',
+					value: 0,
+				},
+			];
+		};
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			convertDbType,
+			isOrNotSelect,
+			DbChanged,
+		};
+	},
+});
+</script>

+ 137 - 0
Web/src/views/system/codeGen/component/fkDialog.vue

@@ -0,0 +1,137 @@
+<template>
+	<div class="fk-container">
+		<el-dialog v-model="isShowDialog" title="外键配置" draggable width="600px">
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="库定位器" prop="configId">
+							<el-select clearable v-model="ruleForm.configId" placeholder="库名" filterable @change="DbChanged()">
+								<el-option v-for="item in dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="数据库表" prop="tableName">
+							<el-select v-model="ruleForm.tableName" class="m-2" filterable clearable @change="TableChanged()">
+								<el-option v-for="item in tableData" :key="item.entityName" :label="item.tableName" :value="item.tableName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="显示字段" prop="columnName">
+							<el-select v-model="ruleForm.columnName">
+								<el-option v-for="item in columnData" :key="item.columnName" :label="item.columnName" :value="item.columnName" />
+							</el-select>
+						</el-form-item>
+					</el-col>					
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref, onMounted } from 'vue';
+
+import { getDatabaseList, getTableList, getColumnList } from '/@/api/system/admin';
+
+export default defineComponent({
+	name: 'fk',
+	components: {},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		var rowdata = {} as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as any,
+			dbData: [] as any,
+			tableData: [] as any,
+			columnData: [] as any,
+		});
+
+		onMounted(async () => {
+			var res = await getDatabaseList();
+			state.dbData = res.data.result;
+		});
+
+		const DbChanged = async () => {
+			state.tableData = [];
+			state.columnData = [];
+			await getTableInfoList();
+		};
+
+		const TableChanged = async () => {
+			state.columnData = [];
+			await getColumnInfoList();
+		};
+
+		const getDbList = async () => {
+			var res = await getDatabaseList();
+			state.dbData = res.data.result;
+		};
+
+		const getTableInfoList = async () => {
+			if (state.ruleForm.configId == '') return;
+			var res = await getTableList(state.ruleForm.configId);
+			state.tableData = res.data.result;
+		};
+
+		const getColumnInfoList = async () => {
+			if (state.ruleForm.configId == '' || state.ruleForm.tableName == '') return;
+            console.log(state.ruleForm.configId, state.ruleForm.tableName)
+			var res = await getColumnList(state.ruleForm.configId, state.ruleForm.tableName);
+			state.columnData = res.data.result;
+		};
+
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			rowdata = row;
+			state.isShowDialog = true;
+		};
+
+		// 关闭弹窗
+		const closeDialog = () => {
+			rowdata.fkTableName = state.ruleForm.tableName;
+			// rowdata.fkEntityName = state.ruleForm.entityName;
+			rowdata.fkColumnName = state.ruleForm.columnName;
+			// rowdata.fkColumnNetType = state.ruleForm.columnNetType;
+			proxy.mittBus.emit('submitRefreshFk', rowdata);
+			state.isShowDialog = false;
+		};
+
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+				closeDialog();
+			});
+		};
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			DbChanged,
+			TableChanged,
+			getDbList,
+			getTableInfoList,
+			getColumnInfoList,
+		};
+	},
+});
+</script>

+ 284 - 0
Web/src/views/system/codeGen/component/generateConfigDialog.vue

@@ -0,0 +1,284 @@
+<template>
+	<div class="codeGenerateConfig-container">
+		<el-dialog v-model="isShowDialog" title="配置" draggable width="100%">
+			<el-table :data="tableData" style="width: 100%" v-loading="loading" border>
+				<el-table-column type="index" label="序号" width="55" align="center" />
+				<el-table-column prop="columnName" label="字段" show-overflow-tooltip />
+				<el-table-column prop="columnComment" label="描述" show-overflow-tooltip>
+					<template #default="scope">
+						<el-input v-model="scope.row.columnComment" autocomplete="off" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="netType" label="数据类型" show-overflow-tooltip />
+				<el-table-column prop="effectType" label="作用类型" show-overflow-tooltip>
+					<template #default="scope">
+						<el-select v-model="scope.row.effectType" class="m-2" placeholder="Select" :disabled="judgeColumns(scope.row)" @change="effectTypeChange(scope.row, scope.$index)">
+							<el-option v-for="item in effectTypeList" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+				<el-table-column prop="dictTypeCode" label="字典" show-overflow-tooltip>
+					<template #default="scope">
+						<el-select v-model="scope.row.dictTypeCode" class="m-2" :disabled="effectTypeEnable(scope.row)">
+							<el-option v-for="item in dictTypeCodeList" :key="item.code" :label="item.name" :value="item.code" />
+						</el-select>
+					</template>
+				</el-table-column>
+
+				<el-table-column prop="whetherTable" label="列表显示" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-checkbox v-model="scope.row.whetherTable" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="whetherAddUpdate" label="增改" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-checkbox v-model="scope.row.whetherAddUpdate" :disabled="judgeColumns(scope.row)" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="whetherRequired" label="必填" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-checkbox v-model="scope.row.whetherRequired" :disabled="judgeColumns(scope.row)" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="queryWhether" label="是否是查询" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-switch v-model="scope.row.queryWhether" :active-value="true" :inactive-value="false" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="queryType" label="查询方式" show-overflow-tooltip>
+					<template #default="scope">
+						<el-select v-model="scope.row.queryType" class="m-2" placeholder="Select" :disabled="!scope.row.queryWhether">
+							<el-option v-for="item in queryTypeList" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+			</el-table>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+		<fkDialog ref="fkDialogRef" />
+		<treeDialog ref="treeDialogRef" />
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, onMounted, onUnmounted, defineComponent, getCurrentInstance, ref } from 'vue';
+import fkDialog from '/@/views/system/codeGen/component/fkDialog.vue';
+import treeDialog from '/@/views/system/codeGen/component/treeDialog.vue';
+
+import { getGenerateConfigList, getDictDataDropdown, getDictTypeList, updateGenerateConfig, getAllConstSelector } from '/@/api/system/admin';
+import { AddCodeGenInput, DbTableInfo } from '/@/api/system/interface';
+
+export default defineComponent({
+	name: 'codeGenerateConfig',
+	components: { fkDialog, treeDialog },
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const fkDialogRef = ref();
+		const treeDialogRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			loading: false,
+			tableData: [] as any,
+			dbData: [] as any,
+			effectTypeList: [] as any,
+			dictTypeCodeList: [] as any,
+			dictDataAll: [] as any,
+			queryTypeList: [] as any,
+			allConstSelector: [] as any,
+		});
+
+		onMounted(async () => {
+			let res = await getDictDataDropdown('code_gen_effect_type');
+			state.effectTypeList = res.data.result;
+
+			res = await getDictTypeList();
+			state.dictTypeCodeList = res.data.result;
+			state.dictDataAll = res.data.result;
+
+			res = await getDictDataDropdown('code_gen_query_type');
+			state.queryTypeList = res.data.result;
+
+			res = await getAllConstSelector();
+			state.allConstSelector = res.data.result;
+
+			proxy.mittBus.on('submitRefreshFk', (data: any) => {
+				state.tableData[data.index] = data;
+			});
+		});
+
+		onUnmounted(() => {
+			proxy.mittBus.off('submitRefresh');
+			proxy.mittBus.off('submitRefreshFk');
+		});
+		// 控件类型改变
+		const effectTypeChange = (data: any, index: number) => {
+			let value = data.effectType;
+			if (value === 'fk') {
+				openFkDialog(data, index);
+			} else if (value === 'ApiTreeSelect') {
+				openTreeDialog(data, index);
+			} else if (value === 'Select') {
+				data.dictTypeCode = '';
+				state.dictTypeCodeList = state.dictDataAll;
+			} else if (value === 'ConstSelector') {
+				data.dictTypeCode = '';
+				state.dictTypeCodeList = state.allConstSelector;
+			}
+		};
+
+		// 查询操作
+		const handleQuery = async (row: any) => {
+			state.loading = true;
+			var res = await getGenerateConfigList({ codeGenId: row.id });
+			var data = res.data.result ?? [];
+			data.forEach((item: any) => {
+				for (const key in item) {
+					if (item[key] === 'Y') {
+						item[key] = true;
+					}
+					if (item[key] === 'N') {
+						item[key] = false;
+					}
+				}
+			});
+			state.tableData = data;
+			state.loading = false;
+		};
+
+		// 判断是否(用于是否能选择或输入等)
+		function judgeColumns(data: any) {
+			var lst = ['createdUserName', 'createdTime', 'updatedUserName', 'updatedTime'];
+			return lst.indexOf(data.columnName) > -1 || data.columnKey === 'True';
+		}
+
+		function effectTypeEnable(data: any) {
+			var lst = ['Radio', 'Select', 'Checkbox', 'ConstSelector'];
+			return lst.indexOf(data.effectType) === -1;
+		}
+
+		// 打开弹窗
+		const openDialog = (addRow: any) => {
+			handleQuery(addRow);
+			state.isShowDialog = true;
+		};
+
+		// 打开弹窗
+		const openFkDialog = (addRow: any, index: number) => {
+			addRow.index = index;
+			fkDialogRef.value.openDialog(addRow);
+		};
+
+		const openTreeDialog = (addRow: any, index: number) => {
+			addRow.index = index;
+			treeDialogRef.value.openDialog(addRow);
+		};
+
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('submitRefresh');
+			state.isShowDialog = false;
+		};
+
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+
+		// 提交
+		const submit = async () => {
+			state.loading = true;
+			var lst = state.tableData;
+			lst.forEach((item: any) => {
+				// 必填那一项转换
+				for (const key in item) {
+					if (item[key] === true) {
+						item[key] = 'Y';
+					}
+					if (item[key] === false) {
+						item[key] = 'N';
+					}
+				}
+			});
+			await updateGenerateConfig(lst);
+			state.loading = false;
+			closeDialog();
+		};
+
+		const convertDbType = (dbType: number) => {
+			let result = '';
+			switch (dbType) {
+				case 0:
+					result = 'MySql';
+					break;
+				case 1:
+					result = 'SqlServer';
+					break;
+				case 2:
+					result = 'Sqlite';
+					break;
+				case 3:
+					result = 'Oracle';
+					break;
+				case 4:
+					result = 'PostgreSql';
+					break;
+				case 5:
+					result = 'Dm';
+					break;
+				case 6:
+					result = 'Kdbndp';
+					break;
+				case 7:
+					result = 'Oscar';
+					break;
+				case 8:
+					result = 'MySqlConnector';
+					break;
+				case 9:
+					result = 'Access';
+					break;
+				default:
+					result = 'Custom';
+					break;
+			}
+			return result;
+		};
+
+		const isOrNotSelect = () => {
+			return [
+				{
+					label: '是',
+					value: 1,
+				},
+				{
+					label: '否',
+					value: 0,
+				},
+			];
+		};
+
+		return {
+			fkDialogRef,
+			treeDialogRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			convertDbType,
+			isOrNotSelect,
+			handleQuery,
+			judgeColumns,
+			effectTypeEnable,
+			openFkDialog,
+			openTreeDialog,
+			effectTypeChange,
+		};
+	},
+});
+</script>

+ 155 - 0
Web/src/views/system/codeGen/component/treeDialog.vue

@@ -0,0 +1,155 @@
+<template>
+	<div class="tree-container">
+		<el-dialog v-model="isShowDialog" title="树选择配置" draggable width="600px">
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="库定位器" prop="configId">
+							<el-select clearable v-model="ruleForm.configId" placeholder="库名" filterable @change="DbChanged()">
+								<el-option v-for="item in dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="数据库表" prop="tableName">
+							<el-select v-model="ruleForm.tableName" class="m-2" filterable clearable @change="TableChanged()">
+								<el-option v-for="item in tableData" :key="item.entityName" :label="item.tableName" :value="item.tableName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="显示字段" prop="displayColumn">
+							<el-select v-model="ruleForm.displayColumn">
+								<el-option v-for="item in columnData" :key="item.columnName" :label="item.columnName" :value="item.columnName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="选择值字段" prop="valueColumn">
+							<el-select v-model="ruleForm.valueColumn">
+								<el-option v-for="item in columnData" :key="item.columnName" :label="item.columnName" :value="item.columnName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="父级字段" prop="pidColumn">
+							<el-select v-model="ruleForm.pidColumn">
+								<el-option v-for="item in columnData" :key="item.columnName" :label="item.columnName" :value="item.columnName" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref, onMounted } from 'vue';
+
+import { getDatabaseList, getTableList, getColumnList } from '/@/api/system/admin';
+import { AddDbColumnInput } from '/@/api/system/interface';
+
+export default defineComponent({
+	name: 'tree',
+	components: {},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		var rowdata = {} as any;
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as any,
+			dbData: [] as any,
+			tableData: [] as any,
+			columnData: [] as any,
+		});
+
+		onMounted(async () => {
+			var res = await getDatabaseList();
+			state.dbData = res.data.result;
+		});
+
+		const DbChanged = async () => {
+			state.tableData = [];
+			state.columnData = [];
+			await getTableInfoList();
+		};
+
+		const TableChanged = async () => {
+			state.columnData = [];
+			await getColumnInfoList();
+		};
+
+		const getDbList = async () => {
+			var res = await getDatabaseList();
+			state.dbData = res.data.result;
+		};
+
+		const getTableInfoList = async () => {
+			if (state.ruleForm.configId == '') return;
+			var res = await getTableList(state.ruleForm.configId);
+			state.tableData = res.data.result;
+		};
+
+		const getColumnInfoList = async () => {
+			if (state.ruleForm.configId == '' || state.ruleForm.tableName == '') return;
+			console.log(state.ruleForm.configId, state.ruleForm.tableName);
+			var res = await getColumnList(state.ruleForm.configId, state.ruleForm.tableName);
+			state.columnData = res.data.result;
+		};
+
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			rowdata = row;
+			state.isShowDialog = true;
+		};
+
+		// 关闭弹窗
+		const closeDialog = () => {
+			rowdata.fkTableName = state.ruleForm.tableName;
+			// rowdata.fkEntityName = state.ruleForm.entityName;
+			// rowdata.fkColumnName = state.ruleForm.columnName;
+			// rowdata.fkColumnNetType = state.ruleForm.columnNetType;
+			rowdata.displayColumn = state.ruleForm.displayColumn;
+			rowdata.valueColumn = state.ruleForm.valueColumn;
+			rowdata.pidColumn = state.ruleForm.pidColumn;
+			proxy.mittBus.emit('submitRefreshFk', rowdata);
+			state.isShowDialog = false;
+		};
+
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+
+				closeDialog();
+			});
+		};
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			DbChanged,
+			TableChanged,
+			getDbList,
+			getTableInfoList,
+			getColumnInfoList,
+		};
+	},
+});
+</script>

+ 196 - 0
Web/src/views/system/codeGen/index.vue

@@ -0,0 +1,196 @@
+<template>
+	<div class="sys-codegenerate-container">
+		<el-card shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-form :model="queryParams" ref="queryForm" :inline="true" v-loading="loading">
+				<el-form-item>
+					<el-button type="primary" icon="ele-Plus" @click="openAddDialog">增加</el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+
+		<el-card shadow="hover" style="margin-top: 8px">
+			<el-table :data="tableData" style="width: 100%" v-loading="loading" border>
+				<el-table-column type="index" label="序号" width="55" align="center" />
+				<el-table-column prop="configId" label="库定位器" show-overflow-tooltip />
+				<el-table-column prop="tableName" label="表名称" show-overflow-tooltip />
+				<el-table-column prop="busName" label="业务名" show-overflow-tooltip />
+				<el-table-column prop="nameSpace" label="命名空间" show-overflow-tooltip />
+				<el-table-column prop="authorName" label="作者姓名" show-overflow-tooltip />
+				<el-table-column prop="generateType" label="生成方式" show-overflow-tooltip>
+					<template #default="scope">
+						<span>{{ getGenerateTypeString(scope.row.generateType) }}</span>
+					</template>
+				</el-table-column>
+				<el-table-column label="操作" width="200" fixed="right" align="center" show-overflow-tooltip>
+					<template #default="scope">
+						<el-button size="small" text type="primary" @click="handleGenerate(scope.row)">开始生成</el-button>
+						<el-button size="small" text type="primary" @click="openConfigDialog(scope.row)">配置</el-button>
+						<el-button size="small" text type="primary" @click="openEditDialog(scope.row)">编辑</el-button>
+						<el-button size="small" text type="primary" @click="deleConfig(scope.row)">删除</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<el-pagination
+				v-model:currentPage="tableParams.page"
+				v-model:page-size="tableParams.pageSize"
+				:total="tableParams.total"
+				:page-sizes="[10, 20, 50, 100]"
+				small
+				background
+				@size-change="handleSizeChange"
+				@current-change="handleCurrentChange"
+				layout="total, sizes, prev, pager, next, jumper"
+			/>
+		</el-card>
+		<CodeGenerateDialog :code-generate-type-list="codeGenerateTypeList" :menu-data="menudata" :title="editMenuTitle" ref="CodeGenerateRef" />
+		<CodeConfigDialog ref="CodeConfigRef" />
+	</div>
+</template>
+
+<script lang="ts">
+import { toRefs, reactive, onMounted, ref, defineComponent, onUnmounted, getCurrentInstance, toRaw } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+import CodeGenerateDialog from '/@/views/system/codeGen/component/codeGenerateDialog.vue';
+import CodeConfigDialog from '/@/views/system/codeGen/component/generateConfigDialog.vue';
+
+import { AddCodeGenInput, SysCodeGen, SysMenu } from '/@/api/system/interface';
+import { getGeneratePage, getMenuList, getDictDataDropdown, deleGenerate, generateRunLocal } from '/@/api/system/admin';
+
+export default defineComponent({
+	name: 'codeGen',
+	components: { CodeGenerateDialog, CodeConfigDialog },
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const CodeGenerateRef = ref();
+		const CodeConfigRef = ref();
+		const state = reactive({
+			loading: false,
+			loading1: false,
+			dbData: [] as any,
+			configId: '',
+			tableData: [] as Array<SysCodeGen>,
+			tableName: '',
+			queryParams: {
+				name: undefined,
+				code: undefined,
+			},
+			tableParams: {
+				page: 1,
+				pageSize: 10,
+				total: 0 as any,
+			},
+			editMenuTitle: '',
+			menudata: [] as Array<SysMenu>,
+			codeGenerateTypeList: [] as any,
+		});
+
+		onMounted(async () => {
+			handleQuery();
+			let res = await getMenuList();
+			state.menudata = res.data.result;
+
+			let list = await getDictDataDropdown('code_gen_create_type');
+			state.codeGenerateTypeList = list.data.result;
+			proxy.mittBus.on('submitRefresh', () => {
+				handleQuery();
+			});
+			proxy.mittBus.on('submitRefreshFk', (res: any) => {
+				state.tableData;
+			});
+		});
+
+		onUnmounted(() => {
+			proxy.mittBus.off('submitRefresh');
+			proxy.mittBus.off('submitRefreshFk');
+		});
+
+		const openConfigDialog = (row: any) => {
+			CodeConfigRef.value.openDialog(row);
+		};
+		// 表查询操作
+		const handleQuery = async () => {
+			state.loading = true;
+			let params = Object.assign(state.queryParams, state.tableParams);
+			let res = await getGeneratePage(params);
+			state.tableData = res.data.result?.items ?? [];
+			state.tableParams.total = res.data.result?.total;
+			state.loading = false;
+		};
+
+		// 获取生成方式
+		const getGenerateTypeString = (val: string) => {
+			let lst = state.codeGenerateTypeList.filter((u: any) => u.value == val);
+			return lst[0]?.label;
+		};
+
+		// 改变页面容量
+		const handleSizeChange = (val: number) => {
+			state.tableParams.pageSize = val;
+			handleQuery();
+		};
+
+		// 改变页码序号
+		const handleCurrentChange = (val: number) => {
+			state.tableParams.page = val;
+			handleQuery();
+		};
+
+		// 打开表增加页面
+		const openAddDialog = () => {
+			state.editMenuTitle = '新增';
+			CodeGenerateRef.value.openDialog({ type: '1' });
+		};
+		// 打开列编辑页面
+		const openEditDialog = (row: any) => {
+			state.editMenuTitle = '编辑';
+			row.type = '2';
+			CodeGenerateRef.value.openDialog(row);
+		};
+
+		// 删除表
+		const deleConfig = (row: any) => {
+			ElMessageBox.confirm(`确定删除吗?`, '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning',
+			})
+				.then(async () => {
+					await deleGenerate([{ id: row.id }]);
+					handleQuery();
+					ElMessage.success('操作成功');
+				})
+				.catch(() => {});
+		};
+
+		// 开始生成代码
+		const handleGenerate = (row: any) => {
+			ElMessageBox.confirm(`确定要生成吗?`, '提示', {
+				confirmButtonText: '确定',
+				cancelButtonText: '取消',
+				type: 'warning',
+			})
+				.then(async () => {
+					await generateRunLocal(row);
+					handleQuery();
+					ElMessage.success('操作成功');
+				})
+				.catch(() => {});
+		};
+
+		return {
+			handleQuery,
+			openAddDialog,
+			openEditDialog,
+			deleConfig,
+			CodeGenerateRef,
+			handleSizeChange,
+			handleCurrentChange,
+			getGenerateTypeString,
+			...toRefs(state),
+			CodeConfigRef,
+			openConfigDialog,
+			handleGenerate,
+		};
+	},
+});
+</script>

+ 201 - 0
Web/src/views/system/database/component/addColumn.vue

@@ -0,0 +1,201 @@
+<template>
+	<div class="sys-dbColumn-container">
+		<el-dialog v-model="isShowDialog" title="列编辑" draggable width="600px">
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="列名称" prop="dbColumnName" :rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.dbColumnName" placeholder="列名称" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="描述" prop="columnDescription" :rules="[{ required: true, message: '描述不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.columnDescription" placeholder="描述" clearable type="textarea" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="主键" prop="isPrimarykey">
+							<el-select v-model="ruleForm.isPrimarykey">
+								<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="自增" prop="isIdentity">
+							<el-select v-model="ruleForm.isIdentity" class="m-2">
+								<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="类型" prop="dataType">
+							<el-select v-model="ruleForm.dataType">
+								<el-option v-for="item in apiTypeSelect()" :key="item.value" :label="item.value" :value="item.value" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="可空" prop="isNullable">
+							<el-select v-model="ruleForm.isNullable">
+								<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="长度" prop="length">
+							<el-input-number v-model="ruleForm.length" size="default" />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+						<el-form-item label="保留几位小数" prop="decimalDigits">
+							<el-input-number v-model="ruleForm.decimalDigits" size="default" />
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref } from 'vue';
+
+import { addColumn } from '/@/api/system/admin';
+import { AddDbColumnInput } from '/@/api/system/interface';
+
+export default defineComponent({
+	name: 'sysAddColumn',
+	components: {},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as AddDbColumnInput,
+		});
+		// 打开弹窗
+		const openDialog = (addRow: AddDbColumnInput) => {
+			state.ruleForm = addRow;
+			state.isShowDialog = true;
+		};
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('submitRefreshColumn');
+			state.isShowDialog = false;
+		};
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+
+				await addColumn(state.ruleForm);
+				closeDialog();
+			});
+		};
+
+		const apiTypeSelect = () => {
+			return [
+				{
+					value: 'text',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'varchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'nvarchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'char',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'nchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'timestamp',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'int',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'smallint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'tinyint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'bigint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'bit',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'decimal',
+					hasLength: true,
+					hasDecimalDigits: true,
+				},
+				{
+					value: 'datetime',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+			];
+		};
+
+		const isOrNotSelect = () => {
+			return [
+				{
+					label: '是',
+					value: 1,
+				},
+				{
+					label: '否',
+					value: 0,
+				},
+			];
+		};
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			apiTypeSelect,
+			isOrNotSelect,
+		};
+	},
+});
+</script>

+ 380 - 0
Web/src/views/system/database/component/addTable.vue

@@ -0,0 +1,380 @@
+<template>
+	<div class="sys-dbTable-container">
+		<el-dialog v-model="isShowDialog" title="表新增" draggable width="1400px">
+			<el-divider content-position="left">数据表信息</el-divider>
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="80px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="表名称" prop="tableName" :rules="[{ required: true, message: '名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.tableName" placeholder="表名称" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="描述" prop="description" :rules="[{ required: true, message: '描述不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.description" placeholder="描述" clearable type="textarea" />
+						</el-form-item>
+					</el-col>
+				</el-row>
+			</el-form>
+			<el-divider content-position="left">数据列信息</el-divider>
+			<el-table :data="tableData" style="width: 100%" max-height="400">
+				<el-table-column fixed prop="dbColumnName" label="字段名" width="150">
+					<template #default="scope">
+						<el-input v-model="scope.row.dbColumnName" autocomplete="off" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="columnDescription" label="描述" width="200">
+					<template #default="scope">
+						<el-input v-model="scope.row.columnDescription" autocomplete="off" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="isPrimarykey" label="主键">
+					<template #default="scope">
+						<el-select v-model="scope.row.isPrimarykey" class="m-2" placeholder="Select">
+							<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+				<el-table-column prop="isIdentity" label="自增">
+					<template #default="scope">
+						<el-select v-model="scope.row.isIdentity" class="m-2" placeholder="Select">
+							<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+				<el-table-column prop="dataType" label="类型">
+					<template #default="scope">
+						<el-select v-model="scope.row.dataType" class="m-2" placeholder="Select">
+							<el-option v-for="item in apiTypeSelect()" :key="item.value" :label="item.value" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+				<el-table-column prop="isNullable" label="可空">
+					<template #default="scope">
+						<el-select v-model="scope.row.isNullable" class="m-2" placeholder="Select">
+							<el-option v-for="item in isOrNotSelect()" :key="item.value" :label="item.label" :value="item.value" />
+						</el-select>
+					</template>
+				</el-table-column>
+				<el-table-column prop="length" label="长度">
+					<template #default="scope">
+						<el-input-number v-model="scope.row.length" size="small" />
+					</template>
+				</el-table-column>
+				<el-table-column prop="decimalDigits" label="保留几位小数">
+					<template #default="scope">
+						<el-input-number v-model="scope.row.decimalDigits" size="small" />
+					</template>
+				</el-table-column>
+				<el-table-column fixed="right" label="操作" width="220">
+					<template #default="scope">
+						<el-button link type="primary" icon="el-icon-delete" size="small" @click.prevent="handleColDelete(scope.$index)">删除</el-button>
+						<el-button v-if="tableData.length > 1" link type="primary" icon="ele-Top" size="small" @click.prevent="handleColTop(scope.row, scope.$index)">上移</el-button>
+						<el-button v-if="tableData.length > 1" link type="primary" icon="ele-Bottom" size="small" @click.prevent="handleColDown(scope.row, scope.$index)">下移</el-button>
+					</template>
+				</el-table-column>
+			</el-table>
+			<div style="text-align: left; margin-top: 10px">
+				<el-button icon="ele-Plus" @click="addPrimaryColumn">新增主键字段</el-button>
+				<el-button icon="ele-Plus" @click="addColumn">新增普通字段</el-button>
+				<el-button icon="ele-Plus" @click="addTenantColumn">新增租户字段</el-button>
+				<el-button icon="ele-Plus" @click="addBaseColumn">新增基础字段</el-button>
+			</div>
+
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref, toRaw } from 'vue';
+import { EditRecordRow, UpdateDbTableInput } from '/@/api/system/interface';
+import { ElMessage } from 'element-plus';
+
+import { addTable } from '/@/api/system/admin';
+
+export default defineComponent({
+	name: 'sysAddTable',
+	components: {},
+	setup() {
+		var colIndex = 0;
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as UpdateDbTableInput,
+			tableData: [] as Array<EditRecordRow>,
+		});
+
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			state.ruleForm = row;
+			state.isShowDialog = true;
+		};
+
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('addTableSubmitted', state.ruleForm.tableName);
+			state.tableData = [];
+			state.isShowDialog = false;
+		};
+
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+				if (state.tableData.length === 0) {
+					ElMessage({
+						type: 'error',
+						message: `请选择库名!`,
+					});
+					return;
+				}
+				const params: any = {
+					dbColumnInfoList: state.tableData,
+					...state.ruleForm,
+				};
+				await addTable(params);
+				closeDialog();
+			});
+		};
+
+		const apiTypeSelect = () => {
+			return [
+				{
+					value: 'text',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'varchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'nvarchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'char',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'nchar',
+					hasLength: true,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'timestamp',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'int',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'smallint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'tinyint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'bigint',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'bit',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+				{
+					value: 'decimal',
+					hasLength: true,
+					hasDecimalDigits: true,
+				},
+				{
+					value: 'datetime',
+					hasLength: false,
+					hasDecimalDigits: false,
+				},
+			];
+		};
+
+		const isOrNotSelect = () => {
+			return [
+				{
+					label: '是',
+					value: 1,
+				},
+				{
+					label: '否',
+					value: 0,
+				},
+			];
+		};
+
+		function addPrimaryColumn() {
+			const addRow: EditRecordRow = {
+				columnDescription: '主键Id',
+				dataType: 'bigint',
+				dbColumnName: 'Id',
+				decimalDigits: 0,
+				isIdentity: 0,
+				isNullable: 0,
+				isPrimarykey: 1,
+				length: 0,
+				key: colIndex,
+				editable: true,
+				isNew: true,
+			};
+			state.tableData.push(addRow);
+			colIndex++;
+		}
+
+		function addColumn() {
+			const addRow: EditRecordRow = {
+				columnDescription: '',
+				dataType: '',
+				dbColumnName: '',
+				decimalDigits: 0,
+				isIdentity: 0,
+				isNullable: 1,
+				isPrimarykey: 0,
+				length: 0,
+				key: colIndex,
+				editable: true,
+				isNew: true,
+			};
+			state.tableData.push(addRow);
+			colIndex++;
+		}
+
+		function addTenantColumn() {
+			const addRow: EditRecordRow = {
+				columnDescription: '租户Id',
+				dataType: 'bigint',
+				dbColumnName: 'TenantId',
+				decimalDigits: 0,
+				isIdentity: 0,
+				isNullable: 1,
+				isPrimarykey: 0,
+				length: 0,
+				key: colIndex,
+				editable: true,
+				isNew: true,
+			};
+			state.tableData.push(addRow);
+			colIndex++;
+		}
+
+		function addBaseColumn() {
+			const fileds = [
+				{
+					dataType: 'datetime',
+					name: 'CreateTime',
+					desc: '创建时间',
+				},
+				{
+					dataType: 'datetime',
+					name: 'UpdateTime',
+					desc: '更新时间',
+				},
+				{
+					dataType: 'bigint',
+					name: 'CreateUserId',
+					desc: '创建者Id',
+				},
+				{
+					dataType: 'bigint',
+					name: 'UpdateUserId',
+					desc: '修改者Id',
+				},
+				{
+					dataType: 'bit',
+					name: 'IsDelete',
+					desc: '软删除',
+					isNullable: 0,
+				},
+			];
+
+			fileds.forEach((m: any) => {
+				state.tableData.push({
+					columnDescription: m.desc,
+					dataType: m.dataType,
+					dbColumnName: m.name,
+					decimalDigits: 0,
+					isIdentity: 0,
+					isNullable: m.isNullable === 0 ? 0 : 1,
+					isPrimarykey: 0,
+					length: m.length || 0,
+					key: colIndex,
+					editable: true,
+					isNew: true,
+				});
+				colIndex++;
+			});
+		}
+
+		function handleColDelete(index: number) {
+			state.tableData.splice(index, 1);
+		}
+
+		function handleColTop(record: EditRecordRow, index: number) {
+			if (record.isNew) {
+				var data1 = ChangeExForArray(index, index - 1, state.tableData);
+				return data1;
+			}
+		}
+
+		function handleColDown(record: EditRecordRow, index: number) {
+			if (record.isNew) {
+				return ChangeExForArray(index, index + 1, state.tableData);
+			}
+		}
+
+		function ChangeExForArray(index1: number, index2: number, array: Array<EditRecordRow>) {
+			let temp = array[index1];
+			array[index1] = array[index2];
+			array[index2] = temp;
+			return array;
+		}
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+			apiTypeSelect,
+			addPrimaryColumn,
+			addColumn,
+			addTenantColumn,
+			addBaseColumn,
+			isOrNotSelect,
+			handleColTop,
+			handleColDown,
+			handleColDelete,
+		};
+	},
+});
+</script>

+ 1 - 1
Web/src/views/system/database/component/editTable.vue

@@ -1,6 +1,6 @@
 <template>
 	<div class="sys-dbTable-container">
-		<el-dialog v-model="isShowDialog" title="表编辑" draggable width="600px">
+		<el-dialog v-model="isShowDialog" title="表编辑" draggable width="1000px">
 			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="80px">
 				<el-row :gutter="35">
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">

+ 98 - 0
Web/src/views/system/database/component/generateEntity.vue

@@ -0,0 +1,98 @@
+<template>
+	<div class="sys-dbColumn-container">
+		<el-dialog v-model="isShowDialog" title="配置实体" draggable width="600px">
+			<el-form :model="ruleForm" ref="ruleFormRef" size="default" label-width="100px">
+				<el-row :gutter="35">
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="表名" prop="tableName" :rules="[{ required: true, message: '表名不能为空', trigger: 'blur' }]">
+							<el-input disabled v-model="ruleForm.tableName" placeholder="表名" clearable />
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="实体名称" prop="entityName" :rules="[{ required: true, message: '实体名称不能为空', trigger: 'blur' }]">
+							<el-input v-model="ruleForm.entityName" placeholder="实体名称" clearable/>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="基类" prop="baseClassName">
+							<el-select v-model="ruleForm.baseClassName" clearable>
+								<el-option label="EntityBaseId" value="EntityBaseId" />
+								<el-option label="EntityBase" value="EntityBase" />
+								<el-option label="EntityTenant" value="EntityTenant" />
+							</el-select>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="存放位置" prop="position" clearable>
+							<el-select v-model="ruleForm.position">
+								<el-option label="Admin.NET.Application" value="Admin.NET.Application" />
+								<el-option label="Admin.NET.Core" value="Admin.NET.Core" />
+							</el-select>
+						</el-form-item>
+					</el-col>				
+				</el-row>
+			</el-form>
+			<template #footer>
+				<span class="dialog-footer">
+					<el-button @click="cancel" size="default">取 消</el-button>
+					<el-button type="primary" @click="submit" size="default">确 定</el-button>
+				</span>
+			</template>
+		</el-dialog>
+	</div>
+</template>
+
+<script lang="ts">
+import { reactive, toRefs, defineComponent, getCurrentInstance, ref } from 'vue';
+
+import { createEntity } from '/@/api/system/admin';
+
+export default defineComponent({
+	name: 'generateEntity',
+	components: {},
+	setup() {
+		const { proxy } = getCurrentInstance() as any;
+		const ruleFormRef = ref();
+		const state = reactive({
+			isShowDialog: false,
+			ruleForm: {} as any,
+		});
+
+		// 打开弹窗
+		const openDialog = (row: any) => {
+			state.ruleForm.configId = row.configId;
+			state.ruleForm.tableName = row.tableName;
+			state.ruleForm.baseClassName = 'EntityBase';
+			state.ruleForm.position = 'Admin.NET.Application';
+			state.isShowDialog = true;
+		};
+		// 关闭弹窗
+		const closeDialog = () => {
+			proxy.mittBus.emit('submitRefreshColumn');
+			state.isShowDialog = false;
+		};
+		// 取消
+		const cancel = () => {
+			state.isShowDialog = false;
+		};
+		// 提交
+		const submit = () => {
+			ruleFormRef.value.validate(async (valid: boolean) => {
+				if (!valid) return;
+
+				await createEntity(state.ruleForm);
+				closeDialog();
+			});
+		};
+
+		return {
+			ruleFormRef,
+			openDialog,
+			closeDialog,
+			cancel,
+			submit,
+			...toRefs(state),
+		};
+	},
+});
+</script>

+ 74 - 11
Web/src/views/system/database/index.vue

@@ -18,6 +18,7 @@
 					<el-button icon="ele-Delete" type="danger" @click="delTable"> 删除表 </el-button>
 					<el-button icon="ele-Plus" @click="openAddTable"> 增加表 </el-button>
 					<el-button icon="ele-Plus" @click="openAddColumn"> 增加列 </el-button>
+					<el-button icon="ele-Plus" type="primary" @click="openGenerateDialog"> 生成实体 </el-button>
 				</el-form-item>
 			</el-form>
 		</el-card>
@@ -59,26 +60,36 @@
 		</el-card>
 		<EditTable ref="editTableRef" />
 		<EditColumn ref="editColumnRef" />
+		<AddTable ref="addTableRef" />
+		<AddColumn ref="addColumnRef" />
+		<GenerateEntity ref="generateEntityRef" />
 	</div>
 </template>
 
 <script lang="ts">
-import { toRefs, reactive, onMounted, ref, defineComponent, onUnmounted, getCurrentInstance } from 'vue';
+import { toRefs, reactive, onMounted, ref, defineComponent, onUnmounted, getCurrentInstance, toRaw } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import EditTable from '/@/views/system/database/component/editTable.vue';
 import EditColumn from '/@/views/system/database/component/editColumn.vue';
+import AddTable from '/@/views/system/database/component/addTable.vue';
+import AddColumn from '/@/views/system/database/component/addColumn.vue';
+import GenerateEntity from '/@/views/system/database/component/generateEntity.vue';
 
 import { getAPI } from '/@/utils/axios-utils';
 import { SysDatabaseApi } from '/@/api-services/api';
 import { DbColumnOutput, DbTableInfo } from '/@/api-services/models';
+import { AddDbColumnInput } from '/@/api/system/interface';
 
 export default defineComponent({
 	name: 'sysDatabase',
-	components: { EditTable, EditColumn },
+	components: { EditTable, EditColumn, AddTable,AddColumn,GenerateEntity },
 	setup() {
 		const { proxy } = getCurrentInstance() as any;
 		const editTableRef = ref();
 		const editColumnRef = ref();
+		const addTableRef = ref();
+		const addColumnRef = ref();
+		const generateEntityRef = ref();
 		const state = reactive({
 			loading: false,
 			loading1: false,
@@ -105,17 +116,23 @@ export default defineComponent({
 			proxy.mittBus.on('submitRefreshColumn', () => {
 				handleQueryColunm();
 			});
+			proxy.mittBus.on('addTableSubmitted', (res: any) => {
+				handleQueryTable();
+				state.tableName = res;
+				handleQueryColunm();
+			});
 		});
 		onUnmounted(() => {
 			proxy.mittBus.off('submitRefreshTable');
 			proxy.mittBus.off('submitRefreshColumn');
+			proxy.mittBus.off('addTableSubmitted');
 		});
 		// 表查询操作
 		const handleQueryTable = async () => {
 			state.tableName = '';
 			state.columnData = [];
-
 			state.loading = true;
+
 			var res = await getAPI(SysDatabaseApi).sysDatabaseTableListGet(state.configId);
 			state.tableData = res.data.result ?? [];
 			state.loading = false;
@@ -140,12 +157,35 @@ export default defineComponent({
 			};
 			editTableRef.value.openDialog(table);
 		};
+
+		// 打开实体生成页面
+		const openGenerateDialog = () => {
+			if (state.configId == '' || state.tableName == '') return;
+
+			var res = state.tableData.filter((u: any) => u.name == state.tableName);
+			var table: any = {
+				configId: state.configId,
+				tableName: state.tableName
+			};
+			generateEntityRef.value.openDialog(table);
+		};
 		// 打开表增加页面
 		const openAddTable = () => {
-			ElMessage({
-				type: 'success',
-				message: `期待您的PR! ${state.configId}`,
-			});
+			if (state.configId == '') {
+				ElMessage({
+					type: 'error',
+					message: `请选择库名!`,
+				});
+				return;
+			}
+
+			var table: any = {
+				configId: state.configId,
+				tableName: '',
+				oldTableName: '',
+				description: '',
+			};
+			addTableRef.value.openDialog(table);
 		};
 		// 打开列编辑页面
 		const openEditColumn = (row: any) => {
@@ -160,10 +200,29 @@ export default defineComponent({
 		};
 		// 打开列增加页面
 		const openAddColumn = () => {
-			ElMessage({
-				type: 'success',
-				message: `期待您的PR! ${state.configId}`,
-			});
+			if (state.configId == '' || state.tableName == '') {
+				ElMessage({
+					type: 'error',
+					message: `请选择库名和表名!`,
+				});
+				return;
+			}
+			const addRow: AddDbColumnInput = {
+				configId: state.configId,
+				tableName: state.tableName,
+				columnDescription: '',
+				dataType: '',
+				dbColumnName: '',
+				decimalDigits: 0,
+				isIdentity: 0,
+				isNullable: 0,
+				isPrimarykey: 0,
+				length: 0,
+				key: 0,
+				editable: true,
+				isNew: true,
+			};
+			addColumnRef.value.openDialog(addRow);
 		};
 		// 删除表
 		const delTable = () => {
@@ -202,8 +261,12 @@ export default defineComponent({
 			openAddColumn,
 			delTable,
 			delColumn,
+			openGenerateDialog,
 			editTableRef,
 			editColumnRef,
+			addTableRef,
+			addColumnRef,
+			generateEntityRef,
 			...toRefs(state),
 		};
 	},

+ 6 - 0
vue-next-admin/.vscode/settings.json

@@ -0,0 +1,6 @@
+{
+    "i18n-ally.localesPaths": [
+        "src/i18n",
+        "src/i18n/lang"
+    ]
+}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.