添加模板管理模块,添加README文档

This commit is contained in:
zhangjiabao 2024-12-16 17:35:40 +08:00
parent 557dc932fe
commit 08c989d17d
16 changed files with 2277 additions and 221 deletions

417
README.md Normal file
View File

@ -0,0 +1,417 @@
<p align="center">
<img alt="logo" src="https://vue.youshengyun.com/files/img/qrCodeLogo.png">
</p>
<p align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</p>
<p align="center">
<a href='https://gitee.com/risesoft-y9/y9-core/stargazers'><img src='https://gitee.com/risesoft-y9/y9-core/badge/star.svg?theme=dark' alt='star'></img></a>
<img src="https://img.shields.io/badge/version-v9.6.6-yellow.svg">
<img src="https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg">
<img alt="logo" src="https://img.shields.io/badge/Vue-3.3-red.svg">
<img alt="" src="https://img.shields.io/badge/JDK-11-green.svg">
<a href="https://gitee.com/risesoft-y9/y9-core/blob/master/LICENSE">
<img src="https://img.shields.io/badge/license-GPL3-blue.svg"></a>
<img src="https://img.shields.io/badge/total%20lines-810.2k-blue.svg">
</p>
## 简介
代码生成器是基于数字底座的配置模式延伸出来的开源工具其中内含一套完整的基于vue3+element-plus的定制化组件界面风格与数字底座保持统一。代码生成器的目标为帮助开发者和运维者快速生成一套跟数字底座相符的业务后台管理代码同时利用相同的前端设计标准指导界面开发。代码生成器是一个完全开源的项目无商业版但是需要依赖开源的数字底座进行相关人员权限的管控。
[系统在线体验----->>>>>](#在线体验)
## 开源地址
源码地址:<https://github.com/risesoft-y9/Digital-Infrastructure>
源码目录
```
risenet-y9boot-webapp-code -- 代码生成器后端工程
vue -- 前端工程
├── y9vue-code-generator -- 代码生成器前端工程
```
## 内置功能
系统三员是系统默认生成的三个账号,包含系统管理员、安全保密员、安全审计员。
系统管理员:主要负责系统的配置和组织人员的管理
安全保密员:主要负责权限管理和子域三员管理(部门三员管理)以及查看安全审计员的日志和普通用户的日志
安全审计员:主要负责审查系统管理员的日志和安全保密员的日志
<table>
<tr>
<td colspan="2" align="center">系统管理员</td>
</tr>
<tr>
<td>控制台</td>
<td>显示系统的监控统计信息,主要面向用户、应用和日志信息,可根据业务的实际需要进行增改。</td>
</tr>
<tr>
<td>组织架构</td>
<td>包括组织机构、部门、人员、部门领导的构建和管理,其中对组织、部门、人员进行树结构展现。</td>
</tr>
<tr>
<td>组织岗位</td>
<td>包括组织机构、部门、岗位、部门领导的构建和管理,其中对组织、部门、岗位进行树结构展现。</td>
</tr>
<tr>
<td>应用系统管理</td>
<td>对需授权的系统和应用进行构建和管理,支持在系统目录下面添加多级应用。</td>
</tr>
<tr>
<td>应用角色管理</td>
<td>对系统下属的应用角色进行构建和管理。</td>
</tr>
<tr>
<td>公共角色管理</td>
<td>对独立于所有系统之外的公共角色进行构建和管理。</td>
</tr>
<tr>
<td>应用资源管理</td>
<td>对系统下属的应用资源进行构建和管理。应用资源主要包含菜单、按钮等,支持对于内部资源的自由定义。</td>
</tr>
<tr>
<td>字典表管理</td>
<td>对系统中经常使用的较为固定的数据进行维护和管理。</td>
</tr>
<tr>
<td>图标管理</td>
<td>对系统中的图标进行构建和管理,系统创建应用的时候可以从该图标库中选择。</td>
</tr>
<tr>
<td>权限树</td>
<td>内含资源权限树和角色权限树,支持用户以列表和树的形式对全局的人员所持有的资源和角色进行详细查看。</td>
</tr>
<tr>
<td>数据目录管理</td>
<td>采用组织部门、数据分类、时间周期模板的树形结构方式对数据进行编目设定,从而满足后续数据授权的要求。</td>
</tr>
<tr>
<td>子域三员管理</td>
<td>支持对于子组织、下属组织、二级组织的三员的构建与管理。</td>
</tr>
</table>
<table>
<tr>
<td colspan="2" align="center">安全保密员</td>
</tr>
<tr>
<td>应用角色关联</td>
<td>展示已经构建的角色,将角色与资源进行绑定授权。</td>
</tr>
<tr>
<td>公共角色关联</td>
<td>展示已经构建的公共角色,将公共角色与资源进行绑定授权。</td>
</tr>
<tr>
<td>应用资源授权</td>
<td>展示已经构建的资源,将资源与角色、组织、岗位进行绑定授权。</td>
</tr>
<tr>
<td>子域三员管理</td>
<td>对下级部门、下级单位的三员授权管理。</td>
</tr>
<tr>
<td>用户日志</td>
<td>支持审查普通用户的登录日志和操作日志。支持增加针对应用相关的日志审查。</td>
</tr>
<tr>
<td>安全审计员日志</td>
<td>支持审查安全审计员的登录日志和操作日志。</td>
</tr>
<tr>
<td>数据目录授权</td>
<td>展示已经构建的数据目录,将数据目录与组织、岗位、角色进行绑定授权。</td>
</tr>
<tr>
<td>子域三员授权</td>
<td>对已经构建的子域三员进行绑定授权。</td>
</tr>
</table>
<table>
<tr>
<td colspan="2" align="center">安全审计员</td>
</tr>
<tr>
<td>系统管理员日志</td>
<td>可以审查系统管理员的登录日志和操作日志。</td>
</tr>
<tr>
<td>安全保密员日志</td>
<td>可以审查安全保密员的登录日志和操作日志。</td>
</tr>
</table>
## 产品特点
### 内置前端框架
内置一套以vue+element-plus为基础的适应国产场景的前端框架提供各类说明、经典布局和组件代码。方便开发者直接拷贝负责、引用从而快速生成统一的界面。同时支持基于此框架和风格的定制化组件。
### 支持模板套用
将常用且核心的系统、实体、字段等信息进行模板化管理方便大量CRUD系统的快速添加和生成减少配置人员的重复工作量。
### 代码生成标准
依赖数字底座和单点登录,遵循统一的格式和方法生成代码,可以更好地支持信创数据库、中间件的适配。
### 可选择是否实现多租户
可以在创建实体的时候选择是否实现多租户,如果需要实现,则默认帮助实现多租户的功能。
### 预览功能
预览创建的实体会生成哪些文件,以及文件里面的内容。
### 索引功能
可以选择允许用户在创建实体时添加索引,包括聚合索引和唯一索引,并且在建表的时候自动添加索引。
### 生成单个实体相关代码
不生成全部代码,只生成选择的实体类的相关代码。
## 功能架构图
<div><img src="https://vue.youshengyun.com/files/img/code-generator-architecture.png"><div/>
## 部署架构图
<div><img src="https://vue.youshengyun.com/files/img/code-generator-deploy.png"><div/>
## 功能描述
| 序号 | 特点名称 | 特点描述 |
| ---- | -------------------- | ------------------------------------------------------------ |
| 1 | 前端框架说明 | 针对框架功能、目录结构、初始化、单点登录、配置文件、渲染过程、路由配置、路由过程进行图解和文字说明 |
| 2 | 框架路由说明 | 针对静态路由、动态路由和异步路由进行详细说明 |
| 3 | 经典布局 | 提供组织架构、应用系统、职位管理、登录日志等多个经典美观的布局展示 |
| 4 | 组件更新说明 | 每个版本中组件变化的说明 |
| 5 | 组件使用指南 | 针对组件的安装、依赖和国际化方式进行步骤指导 |
| 6 | 通用组件 | 主要包含卡片、弹窗、表单、过滤器、分页、表格、列表、树、图片预览、上传下载等组件(含多种样式)进行展示和代码展示 |
| 7 | 系统、实体、字段管理 | 针对系统基本信息、实体表基本信息、字段信息和配置进行增删改查 |
| 8 | 索引管理 | 支持对已经建立完成的表提前进行索引生成 |
| 9 | 代码生成、预览、下载 | 支持对代码进行生成、预览和下载的功能,支持整体下载,也支持单体下载。 |
| 10 | 模版套用 | 将已经建立的模板一键生成,方便用户在模板之上进行更多的内容增加 |
| 11 | 系统、实体、字段模板 | 针对系统、实体表和字段详细信息进行模板化记录和管理。 |
## 后端技术选型
| 序号 | 依赖 | 版本 | 官网 |
| ---- | --------------- | ------- | ------------------------------------------------------------ |
| 1 | Spring Boot | 2.7.10 | <a href="https://spring.io/projects/spring-boot" target="_blank">官网</a> |
| 2 | SpringDataJPA | 2.7.10 | <a href="https://spring.io/projects/spring-data-jpa" target="_blank">官网</a> |
| 3 | SpringDataRedis | 2.7.10 | <a href="https://spring.io/projects/spring-data-redis" target="_blank">官网</a> |
| 4 | SpringKafka | 2.8.11 | <a href="https://spring.io/projects/spring-kafka" target="_blank">官网</a> |
| 5 | nacos | 2.2.1 | <a href="https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html" target="_blank">官网</a> |
| 6 | druid | 1.2.16 | <a href="https://github.com/alibaba/druid/wiki/%E9%A6%96%E9%A1%B5" target="_blank">官网</a> |
| 7 | Jackson | 2.13.5 | <a href="https://github.com/FasterXML/jackson-core" target="_blank">官网</a> |
| 8 | javers | 6.13.0 | <a href="https://github.com/javers/javers" target="_blank">官网</a> |
| 9 | lombok | 1.18.26 | <a href="https://projectlombok.org/" target="_blank">官网</a> |
| 10 | logback | 1.2.11 | <a href="https://www.docs4dev.com/docs/zh/logback/1.3.0-alpha4/reference/introduction.html" target="_blank">官网</a> |
| 11 | freemarker | 2.3.32 | [官网](https://freemarker.apache.org/) |
## 前端技术选型
| 序号 | 依赖 | 版本 | 官网 |
| ---- | ------------ | ------- | ------------------------------------------------------------ |
| 1 | vue | 3.3.2 | <a href="https://cn.vuejs.org/" target="_blank">官网</a> |
| 2 | vite4 | 4.4.9 | <a href="https://vitejs.cn/" target="_blank">官网</a> |
| 3 | vue-router | 4.0.13 | <a href="https://router.vuejs.org/zh/" target="_blank">官网</a> |
| 4 | pinia | 2.0.11 | <a href="https://pinia.vuejs.org/zh/" target="_blank">官网</a> |
| 5 | axios | 0.24.0 | <a href="https://www.axios-http.cn/" target="_blank">官网</a> |
| 6 | typescript | 4.5.4 | <a href="https://www.typescriptlang.org/" target="_blank">官网</a> |
| 7 | core-js | 3.20.1 | <a href="https://www.npmjs.com/package/core-js" target="_blank">官网</a> |
| 8 | element-plus | 2.2.29 | <a href="https://element-plus.org/zh-CN/" target="_blank">官网</a> |
| 9 | sass | 1.58.0 | <a href="https://www.sass.hk/" target="_blank">官网</a> |
| 10 | animate.css | 4.1.1 | <a href="https://animate.style/" target="_blank">官网</a> |
| 11 | vxe-table | 4.3.5 | <a href="https://vxetable.cn" target="_blank">官网</a> |
| 12 | echarts | 5.3.2 | <a href="https://echarts.apache.org/zh/" target="_blank">官网</a> |
| 13 | svgo | 1.3.2 | <a href="https://github.com/svg/svgo" target="_blank">官网</a> |
| 14 | lodash | 4.17.21 | <a href="https://lodash.com/" target="_blank">官网</a> |
## 中间件选型
| 序号 | 工具 | 版本 | 官网 |
| ---- | ---------------- | ---- | ------------------------------------------------------------ |
| 1 | JDK | 11 | <a href="https://openjdk.org/" target="_blank">官网</a> |
| 2 | Tomcat | 9.0+ | <a href="https://tomcat.apache.org/" target="_blank">官网</a> |
| 3 | Kafka | 2.6+ | <a href="https://kafka.apache.org/" target="_blank">官网</a> |
| 4 | filezilla server | 1.7+ | <a href="https://www.filezilla.cn/download/server" target="_blank">官网</a> |
## 数据库选型
| 序号 | 工具 | 版本 | 官网 |
| ---- | ------------- | ---------- | ------------------------------------------------------------ |
| 1 | Mysql | 5.7 / 8.0+ | <a href="https://www.mysql.com/cn/" target="_blank">官网</a> |
| 2 | Redis | 6.2+ | <a href="https://redis.io/" target="_blank">官网</a> |
| 3 | elasticsearch | 7.9+ | <a href="https://www.elastic.co/cn/elasticsearch/" target="_blank">官网</a> |
## 数字底座专利
| 序&nbsp;号 | 专利号 | 专利名称 |
| ---------- | ---------------- | -------------------------------------------------- |
| 1 | ZL202111207338.0 | 《基于集合运算的资源授权方法及资源授权系统》 |
| 2 | ZL202210702228.X | 《一种静默化数据处理方法及处理系统》 |
| 3 | ZL202310030893.3 | 《基于多租户模式下的权限调度方法及调度系统》 |
| 4 | ZL202310238451.8 | 《一种基于前后端分离架构的前端双随机多态混淆方法》 |
| 5 | ZL202310238534.7 | 《多租户模式下数字底座子域三员架构模型的实现方法》 |
## 信创兼容适配
| **序号** | 类型 | 对象 |
| :------- | -------- | -------------------------- |
| 1 | 浏览器 | 奇安信、火狐、谷歌、360等 |
| 2 | 插件 | 金山、永中、数科、福昕等 |
| 3 | 中间件 | 东方通、金蝶、宝兰德等 |
| 4 | 数据库 | 人大金仓、达梦、高斯等 |
| 5 | 操作系统 | 统信、麒麟、中科方德等 |
| 6 | 芯片 | ARM体系、MIPS体系、X86体系 |
## 在线体验
## 模板代码生成
地址:<https://demo.youshengyun.com/y9vue-code/>
> 快速生成使用了数字底座相关组件的前后端工程
>
> 演示账号
>
> 系统管理员systemManager 密码Risesoft@2024
>
## 文档专区-TODO
| 序号 | 名称 |
| :--- | ------------------------------------------------------------ |
| 1 | <a href="https://vue.youshengyun.com/files/单点登录对接文档.pdf" target="_blank">单点登录对接文档</a> |
| 2 | <a href="https://vue.youshengyun.com/files/数字底座接口文档.pdf" target="_blank">数字底座接口文档</a> |
| 3 | |
| 4 | |
| 5 | <a href="https://vue.youshengyun.com/files/数字底座war包部署文档.pdf" target="_blank">数字底座war包部署文档</a> |
| 6 | <a href="https://vue.youshengyun.com/files/数字底座源码部署文档.pdf" target="_blank">数字底座源码部署文档</a> |
| 7 | <a href="https://vue.youshengyun.com/files/操作使用文档(技术白皮书).pdf" target="_blank">操作使用文档(技术白皮书)</a> |
| 8 | <a href="https://vue.youshengyun.com/files/数字底座数据库设计文档.pdf" target="_blank">数字底座数据库设计文档</a> |
| 9 | <a href="https://vue.youshengyun.com/files/内部Java开发规范手册.pdf" target="_blank">内部Java开发规范手册</a> |
| 10 | <a href="https://vue.youshengyun.com/files/日志组件使用文档.pdf" target="_blank">日志组件使用文档</a> |
| 11 | <a href="https://vue.youshengyun.com/files/文件组件使用文档.pdf" target="_blank">文件组件使用文档</a> |
| 12 | <a href="https://vue.youshengyun.com/files/代码生成器使用文档.pdf" target="_blank">代码生成器使用文档</a> |
| 13 | <a href="https://vue.youshengyun.com/files/配置文件说明文档.pdf" target="_blank">配置文件说明文档</a> |
| 14 | <a href="https://vue.youshengyun.com/files/常用工具类使用示例文档.pdf" target="_blank">常用工具类使用示例文档</a> |
| 15 | <a href="https://vue.youshengyun.com/files/有生博大Vue开发手册v1.0.pdf" target="_blank">前端开发手册</a> |
| 16 | <a href="https://vue.youshengyun.com/files/开发规范.pdf" target="_blank">前端开发规范</a> |
| 17 | <a href="https://vue.youshengyun.com/files/代码格式化.pdf" target="_blank">前端代码格式化</a> |
| 18 | <a href="https://vue.youshengyun.com/files/系统组件.pdf" target="_blank">前端系统组件</a> |
| 19 | <a href="https://vue.youshengyun.com/files/通用方法.pdf" target="_blank">前端通用方法</a> |
| 20 | <a href="https://vue.youshengyun.com/files/国际化.pdf" target="_blank">前端国际化</a> |
| 21 | <a href="https://vue.youshengyun.com/files/Icon图标.pdf" target="_blank">前端Icon图标</a> |
| 22 | <a href="https://vue.youshengyun.com/files/Oracle数据库适配文档.pdf" target="_blank">Oracle数据库适配文档</a> |
| 23 | <a href="https://vue.youshengyun.com/files/Dameng数据库适配文档.pdf" target="_blank">Dameng数据库适配文档</a> |
| 24 | <a href="https://vue.youshengyun.com/files/PostgreSQL数据库适配文档.pdf" target="_blank">PostgreSQL数据库适配文档</a> |
| 25 | <a href="https://vue.youshengyun.com/files/Kingbase数据库适配文档.pdf" target="_blank">Kingbase数据库适配文档</a> |
| 26 | <a href="https://vue.youshengyun.com/files/Mariadb数据库适配文档.pdf" target="_blank">Mariadb数据库适配文档</a> |
| 27 | <a href="https://vue.youshengyun.com/files/OceanBase数据库适配文档.pdf" target="_blank">OceanBase数据库适配文档</a> |
## 代码生成器截图
### 界面截图
<table>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-1.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-2.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-3.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-4.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-5.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-6.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-7.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-8.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-9.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-10.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-11.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-12.png"></td>
</tr>
<tr>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-13.png"></td>
<td><img src="https://vue.youshengyun.com/files/img/code-generator-14.png"></td>
</tr>
</table>
## 依赖开源项目
| 序 号 | 项 目 名 称 | 项目介绍 | 地 址 |
| ----- | ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | 数字底座 | 数字底座是一款面向大型政府、企业数字化转型,基于身份认证、组织架构、岗位职务、应用系统、资源角色等功能构建的统一且安全的管理支撑平台。数字底座基于三员管理模式,具备微服务、多租户、容器化和国产化,支持用户利用代码生成器快速构建自己的业务应用,同时可关联诸多成熟且好用的内部生态应用 | <a href="https://github.com/risesoft-y9/Digital-Infrastructure" target="_blank">码云GitHub</a> |
## 生态开源项目
| 序&nbsp;号 | 项&nbsp;&nbsp;&nbsp;&nbsp; | 项目介绍 | 地&nbsp;址 |
| :--------- | -------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 1 | 工作流引擎 | 工作流引擎对内提供单位/机关流程管理规则和内部业务流程的数字化落地实践;对外提供自动化地第三方业务驱动、接口接入和算法单元驱动能力;工作流引擎在提供底层驱动引擎的同时对全局透明监控、安全防御和国产化特色功能进行充分考虑,是内部流程管理和业务算法驱动的不二之选。 | [码云](https://gitee.com/risesoft-y9/y9-flowable) [GitHub](https://github.com/risesoft-y9/WorkFlow-Engine) |
| 2 | 数据流引擎 | 数据流引擎是一款面向数据集成、数据同步、数据交换、数据共享、任务配置、任务调度的底层数据驱动引擎。数据流引擎采用管执分离、多流层、插件库等体系应对大规模数据任务、数据高频上报、数据高频采集、异构数据兼容的实际数据问题。 | [码云](https://gitee.com/risesoft-y9/y9-dataflow) [GitHub](https://github.com/risesoft-y9/DataFlow-Engine) |
| 3 | 网络硬盘 | 网络硬盘是通过存储、分类、检索、分享、协作、下发、回收等方式管理文档、文件、图片、音频、视频等资料的工具。网络硬盘擅长在国产的私有化环境中,管控文档权限、分配存储空间、安全加密、分享共享,同时可以完成一定轻量级的文件任务收发。网络硬盘是一个完全开源的项目,无商业版,但是需要依赖开源的数字底座进行人员岗位管控。 | [码云](https://gitee.com/risesoft-y9/y9-storage) [GitHub](https://github.com/risesoft-y9/Network-Drive) |
| 4 | 电子邮件 | 电子邮件是一款简化的具备邮件服务器的企业邮箱,支持在将其他主流邮箱的邮件进行导入后自主控制邮件数据安全。电子邮件以其简洁精确的功能和小巧安全的架构方便根据企业和政府机构的业务要求进行二次开发。电子邮件是一个完全开源的项目,无商业版,但是需要依赖开源的数字底座进行人员岗位管控。 | [码云](https://gitee.com/risesoft-y9/y9-email) [GitHub](https://github.com/risesoft-y9/Email) |
| 5 | 数据标注 | 数据标注是一款专门对文本数据进行处理和标注的工具,通过简化快捷的文本标注流程和动态的算法反馈,支持用户快速标注关键词并能通过算法持续减少人工标注的成本和时间。数据标注的过程先由人工标注构筑基础,再由自动标注反哺人工标注,最后由人工标注进行纠偏,从而大幅度提高标注的精准度和高效性。数据标注是一个完全开源的项目,无商业版,但是需要依赖开源的数字底座进行人员岗位管控。数据标注的各类词库结果会定期在本平台中公开。 | [码云](https://gitee.com/risesoft-y9/y9-label) [GitHub](https://github.com/risesoft-y9/Data-Labeling) |
| 6 | 接口管理 | 接口管理通过接口的注册、审批、集市和日志等方式对接口共享进行全生命周期的管理。接口管理注重流程化的接口共享模式和支持大规模接口转发的部署模式,从而面向多接口来源、高流量交互和复杂组织结构的场景。接口管理同时是一个轻量化的内核,支持各种面向特定场景的定制化业务改造。接口管理是一个完全开源的项目,无商业版,但是需要依赖开源的数字底座进行相关目录权限的管控。 | [码云](https://gitee.com/risesoft-y9/y9-interface-platform) [GitHub](https://github.com/risesoft-y9/Interface-Platform) |
## 赞助与支持
### 中关村软件和信息服务产业创新联盟
官网:<a href="https://www.zgcsa.net" target="_blank">https://www.zgcsa.net</a>
### 北京有生博大软件股份有限公司
官网:<a href="https://www.risesoft.net/" target="_blank">https://www.risesoft.net/</a>
### 统一标识代码注册管理中心
官网:<a href="https://www.idcode.org.cn/" target="_blank">https://www.idcode.org.cn/</a>
>数字底座已经全面接入统一标识码MA码具体使用说明请查看<a href="https://gitee.com/risesoft-y9/y9-core/tree/main/y9-digitalbase-idcode" target="_blank">https://gitee.com/risesoft-y9/y9-core/tree/main/y9-digitalbase-idcode</a>
### 中国城市发展研究会
官网:<a href="https://www.china-cfh.com/" target="_blank">https://www.china-cfh.com/</a>
### 北京超维创想信息技术有限公司
官网:<a href="http://www.creatar.com/" target="_blank">http://www.creatar.com/</a>
### 深圳市北斗云信息技术有限公司
官网:<a href="https://www.northdoo.com/" target="_blank">https://www.northdoo.com/</a>
## 咨询与合作
联系人:曲经理
微信号qq349416828
备注:开源咨询-姓名
<div><img style="width: 40%" src="https://vue.youshengyun.com/files/img/曲经理统一二维码咨询.png"><div/>
联系人:有生博大-咨询热线
座机号010-86393151
<div><img style="width: 45%" src="https://vue.youshengyun.com/files/img/有生博大-咨询热线.png"><div/>

View File

@ -54,6 +54,7 @@ public interface Y9CodeSystemService {
*/
Page<Y9CodeSystem> page(int page, int rows);
/**
* @description 分页获取
*

View File

@ -49,7 +49,7 @@ spring:
druid:
y9-public:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/y9_public?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false&allowPublicKeyRetrieval=true
url: jdbc:mysql://192.168.3.31:3306/y9_public?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false&allowPublicKeyRetrieval=true
username: root
#driver-class-name: oracle.jdbc.OracleDriver
#url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
@ -122,25 +122,25 @@ y9:
systemName: code
service:
org:
directUrl: http://localhost:8080/org
directUrl: http://test-api-internal.youshengyun.com
common:
cacheEnabled: true
kafkaEnabled: true
orgBaseUrl: http://localhost:8080/platform
y9DigitalBaseUrl: http://localhost:8080/y9DigitalBase
userOnlineBaseUrl: http://localhost:8080/userOnline
logBaseUrl: http://localhost:8080/log
orgBaseUrl: http://test-api-internal.youshengyun.com/platform
y9DigitalBaseUrl: http://test-api-internal.youshengyun.com/y9DigitalBase
userOnlineBaseUrl: http://test-api-internal.youshengyun.com/userOnline
logBaseUrl: http://test-api-internal.youshengyun.com/log
feature:
file:
rest:
fileManagerUrl: http://localhost:8080/fileManager
fileManagerUrl: http://test-api-internal.youshengyun.com/fileManager
base64FileName: false
encryptionFileContent: false
ftp:
host: localhost
host: 192.168.3.31
port: 21
username: user
password: password
username: y9admin
password: '83204585'
blockWhenExhausted: true
bufferSize: 10240
connectTimeOut: 50000
@ -205,6 +205,6 @@ y9:
#- 客户端密钥,由认证服务提供商分配
client-secret: secret
#- 认证服务器验证访问令牌有效性的路径
introspection-uri: http://localhost:7055/sso/oauth2.0/introspect
introspection-uri: https://test.youshengyun.com/sso/oauth2.0/introspect
#- 认证服务器获取用户信息路径
profile-uri: http://localhost:7055/sso/oauth2.0/profile
profile-uri: https://test.youshengyun.com/sso/oauth2.0/profile

View File

@ -119,7 +119,7 @@ export const routerBeforeEach = async (to, from) => {
}
let path = to.path;
let CHECK;
if (path == '/system' || path == '/localSystem') {
if (path == '/system' || path == '/localSystem' || path == '/localTemplate') {
CHECK = await check();
} else {
CHECK = (await checkRole(['systemAdmin'])) ? true : false;

View File

@ -10,7 +10,7 @@
import { routerBeforeEach } from '@/router/checkRouter';
import NProgress from 'nprogress';
import { createRouter, createWebHistory } from 'vue-router';
import systemRouter from '@/router/modules/systemRouter';
import localTemplateRouter from '@/router/modules/localTemplateRouter';
import localSystemRouter from '@/router/modules/localSystemRouter';
import frontFrameRouter from '@/router/modules/frontFrameRouter';
//constantRoutes为不需要动态判断权限的路由如登录、404、500等
@ -42,7 +42,8 @@ export const constantRoutes: Array<any> = [
//asyncRoutes需求动态判断权限并动态添加的页面 这里的路由模块顺序也是菜单显示的顺序位置src->router->modules
export const asyncRoutes = [
frontFrameRouter,
localSystemRouter
localSystemRouter,
localTemplateRouter
];
// 引入其他模块路由

View File

@ -22,7 +22,7 @@ const frontFrameRouter = {
component: () => import('@/views/frontFrame/frameDes/index.vue'),
name: 'frameDes',
meta: {
title: '前端框架模版',
title: '前端框架说明',
icon: 'ri-file-cloud-line',
environment: 2
}
@ -42,7 +42,7 @@ const frontFrameRouter = {
redirect: '/frontFrame/classicLayout/org',
name: 'classicLayout',
meta: {
title: '数字底座经典布局',
title: '经典布局',
icon: 'ri-layout-2-line',
environment: 2
},
@ -141,153 +141,166 @@ const frontFrameRouter = {
]
},
{
path: '/frontFrame/y9Card',
component: () => import('@/views/frontFrame/y9Card/index.vue'),
name: 'y9Card',
path: '/frontFrame/universalComponent',
redirect: '/frontFrame/y9Card',
name: 'universalComponent',
meta: {
title: 'Card 卡片',
icon: 'ri-hard-drive-2-line',
environment: 2
}
},
{
path: '/frontFrame/y9Dialog',
component: () => import('@/views/frontFrame/y9Dialog/index.vue'),
name: 'y9Dialog',
meta: {
title: 'Dialog 弹窗',
icon: 'ri-window-line',
environment: 2
}
},
{
path: '/frontFrame/y9Form',
component: () => import('@/views/frontFrame/y9Form/index.vue'),
name: 'y9Form',
meta: {
title: 'Form 表单',
icon: 'ri-profile-line',
environment: 2
}
},
{
path: '/frontFrame/y9Filter',
component: () => import('@/views/frontFrame/y9Filter/index.vue'),
name: 'y9Filter',
meta: {
title: 'Filter 过滤',
icon: 'ri-filter-line',
environment: 2
}
},
{
path: '/frontFrame/y9Pagination',
component: () => import('@/views/frontFrame/y9Pagination/index.vue'),
name: 'y9Pagination',
meta: {
title: 'Pagination 分页',
icon: 'ri-page-separator',
environment: 2
}
},
{
path: '/frontFrame/y9Table',
redirect: '/frontFrame/y9Table/install',
name: 'y9Table',
meta: {
title: '表格',
icon: 'ri-table-2',
title: '通用组件',
icon: 'ri-compass-line',
environment: 2
},
children: [
{
path: '/frontFrame/y9Table/y9Table',
component: () => import('@/views/frontFrame/y9Table/eltable.vue'),
name: 'y9Table1',
path: '/frontFrame/y9Card',
component: () => import('@/views/frontFrame/y9Card/index.vue'),
name: 'y9Card',
meta: {
title: 'y9Table 表格',
icon: 'ri-table-2'
title: 'Card 卡片',
icon: 'ri-hard-drive-2-line',
environment: 2
}
},
{
path: '/frontFrame/y9Table/y9VxeTable',
component: () => import('@/views/frontFrame/y9Table/vxetable.vue'),
name: 'y9VxeTable',
path: '/frontFrame/y9Dialog',
component: () => import('@/views/frontFrame/y9Dialog/index.vue'),
name: 'y9Dialog',
meta: {
title: 'y9VxeTable 表格',
icon: 'ri-table-2'
title: 'Dialog 弹窗',
icon: 'ri-window-line',
environment: 2
}
},
{
path: '/frontFrame/y9Form',
component: () => import('@/views/frontFrame/y9Form/index.vue'),
name: 'y9Form',
meta: {
title: 'Form 表单',
icon: 'ri-profile-line',
environment: 2
}
},
{
path: '/frontFrame/y9Filter',
component: () => import('@/views/frontFrame/y9Filter/index.vue'),
name: 'y9Filter',
meta: {
title: 'Filter 过滤',
icon: 'ri-filter-line',
environment: 2
}
},
{
path: '/frontFrame/y9Pagination',
component: () => import('@/views/frontFrame/y9Pagination/index.vue'),
name: 'y9Pagination',
meta: {
title: 'Pagination 分页',
icon: 'ri-page-separator',
environment: 2
}
},
{
path: '/frontFrame/y9Table',
redirect: '/frontFrame/y9Table/install',
name: 'y9Table',
meta: {
title: '表格',
icon: 'ri-table-2',
environment: 2
},
children: [
{
path: '/frontFrame/y9Table/y9Table',
component: () => import('@/views/frontFrame/y9Table/eltable.vue'),
name: 'y9Table1',
meta: {
title: 'y9Table 表格',
icon: 'ri-table-2'
}
},
{
path: '/frontFrame/y9Table/y9VxeTable',
component: () => import('@/views/frontFrame/y9Table/vxetable.vue'),
name: 'y9VxeTable',
meta: {
title: 'y9VxeTable 表格',
icon: 'ri-table-2'
}
}
]
},
{
path: '/frontFrame/y9List',
component: () => import('@/views/frontFrame/y9List/index.vue'),
name: 'y9List',
meta: {
title: 'List 列表',
icon: 'ri-list-unordered',
environment: 2
}
},
{
path: '/frontFrame/y9Tree',
component: () => import('@/views/frontFrame/y9Tree/index.vue'),
name: 'y9Tree',
meta: {
title: 'y9Tree 树',
icon: 'ri-node-tree',
environment: 2
}
},
{
path: '/frontFrame/viewer',
component: () => import('@/views/frontFrame/v-viewer/index.vue'),
name: 'viewer',
meta: {
title: 'v-viewer 图片预览插件',
icon: 'ri-image-line',
environment: 2
}
},
{
path: '/frontFrame/y9Upload',
redirect: '/frontFrame/y9Upload/install',
meta: {
title: 'y9Upload 上传',
icon: 'ri-folder-upload-line'
},
children: [
{
path: '/frontFrame/y9UploadOne',
component: () => import('@/views/frontFrame/y9Upload/uploadOne.vue'),
name: 'y9UploadOne',
meta: {
title: 'y9Upload 上传样式一',
icon: 'ri-node-tree'
}
},
{
path: '/frontFrame/y9UploadTwo',
component: () => import('@/views/frontFrame/y9Upload/uploadTwo.vue'),
name: 'y9UploadTwo',
meta: {
title: 'y9Upload 上传样式二',
icon: 'ri-node-tree'
}
},
{
path: '/frontFrame/y9Uploader',
component: () => import('@/views/frontFrame/y9Upload/uploadThree.vue'),
name: 'uploadThree',
meta: {
title: 'y9Upload 上传样式三',
icon: 'ri-node-tree'
}
}
]
}
]
},
{
path: '/frontFrame/y9List',
component: () => import('@/views/frontFrame/y9List/index.vue'),
name: 'y9List',
meta: {
title: 'List 列表',
icon: 'ri-list-unordered',
environment: 2
}
},
{
path: '/frontFrame/y9Tree',
component: () => import('@/views/frontFrame/y9Tree/index.vue'),
name: 'y9Tree',
meta: {
title: 'y9Tree 树',
icon: 'ri-node-tree',
environment: 2
}
},
{
path: '/frontFrame/viewer',
component: () => import('@/views/frontFrame/v-viewer/index.vue'),
name: 'viewer',
meta: {
title: 'v-viewer 图片预览插件',
icon: 'ri-image-line',
environment: 2
}
},
{
path: '/frontFrame/y9Upload',
redirect: '/frontFrame/y9Upload/install',
meta: {
title: 'y9Upload 上传',
icon: 'ri-folder-upload-line'
},
children: [
{
path: '/frontFrame/y9UploadOne',
component: () => import('@/views/frontFrame/y9Upload/uploadOne.vue'),
name: 'y9UploadOne',
meta: {
title: 'y9Upload 上传样式一',
icon: 'ri-node-tree'
}
},
{
path: '/frontFrame/y9UploadTwo',
component: () => import('@/views/frontFrame/y9Upload/uploadTwo.vue'),
name: 'y9UploadTwo',
meta: {
title: 'y9Upload 上传样式二',
icon: 'ri-node-tree'
}
},
{
path: '/frontFrame/y9Uploader',
component: () => import('@/views/frontFrame/y9Upload/uploadThree.vue'),
name: 'uploadThree',
meta: {
title: 'y9Upload 上传样式三',
icon: 'ri-node-tree'
}
}
]
}
]
};
export default frontFrameRouter;

View File

@ -1,31 +1,24 @@
/*
* @Author: lizhiwen
* @Date: 2022-05-19 14:01:58
* @LastEditors: lizhiwen
* @LastEditTime: 2022-05-19 14:04:42
* @Description:
*/
const systemRouter = {
path: '/localSystem',
component: () => import('@/layouts/index.vue'),
redirect: '/localSystem',
name: 'localSystemIndex',
meta: {
title: '应用生成',
environment: 1
},
children: [
{
path: '/localSystem',
component: () => import('@/views/system/index.vue'),
name: 'localSystemIndex1',
meta: {
title: '应用生成',
icon: 'ri-function-line',
environment: 1
path: '/localSystem',
component: () => import('@/layouts/index.vue'),
redirect: '/localSystem',
name: 'localSystemIndex',
meta: {
title: '应用生成',
environment: 1
},
children: [
{
path: '/localSystem',
component: () => import('@/views/system/index.vue'),
name: 'localSystemIndex1',
meta: {
title: '应用生成',
icon: 'ri-function-line',
environment: 1
}
}
}
]
],
};
export default systemRouter;

View File

@ -0,0 +1,23 @@
const localTemplateRouter = {
path: '/localTemplate',
component: () => import('@/layouts/index.vue'),
redirect: '/localTemplate',
name: 'localTemplateIndex',
meta: {
title: '模板管理',
environment: 1
},
children: [
{
path: '/localTemplate',
component: () => import('@/views/template/index.vue'),
name: 'localTemplate',
meta: {
title: '模板管理',
icon: 'ri-align-item-left-line',
environment: 1
}
}
],
};
export default localTemplateRouter;

View File

@ -1,31 +0,0 @@
/*
* @Author: lizhiwen
* @Date: 2022-05-17 18:01:58
* @LastEditors: lizhiwen
* @LastEditTime: 2022-05-17 18:04:42
* @Description:
*/
const systemRouter = {
path: '/system',
component: () => import('@/layouts/index.vue'),
redirect: '/system',
name: 'systemIndex',
meta: {
title: '应用生成(云服务)',
environment: 0
},
children: [
{
path: '/system',
component: () => import('@/views/system/index.vue'),
name: 'systemIndex1',
meta: {
title: '应用生成(云服务)',
icon: 'ri-apps-line',
environment: 0
}
}
]
};
export default systemRouter;

View File

@ -149,7 +149,7 @@
options: [],
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.environment == '0' ? t('云服务') : t('本地化'));
return h('span', t('本地化'));
}
}
},
@ -205,13 +205,8 @@
//根据environment值改变选项
if (isEdit && item.prop == 'environment') {
item.props.options = [];
if (systemInfo.value?.environment == '1') {
item.props.options.push({ label: '本地化', value: 1 });
item.props.options.push({ label: '云服务', value: 0 });
} else {
item.props.options.push({ label: '云服务', value: 0 });
item.props.options.push({ label: '本地化', value: 1 });
}
item.props.options.push({ label: '本地化', value: 1 });
}
});
}

View File

@ -6,6 +6,7 @@
@on-curr-page-change="onEntityCurrPageChange"
@on-page-size-change="onEntityPageSizeChange"
@on-change="handlerGetData"
v-model:selectedVal="selectedVal"
>
<template v-slot:bnts>
<el-button
@ -549,10 +550,11 @@ let entityTableConfig = ref({
pageSize: 20, //每页显示条目个数支持 v-model 双向绑定
total: 0, //总条目数
},
selectedVal: '',
loading: false,
});
let selectedVal = ref('');
const copyText = (val) =>{
clipboard.copy(val);
clipboardSuccess();
@ -570,9 +572,9 @@ const data = reactive({
},
itemList: [
{
type: 'slot',
slotName: 'bnts',
span: 6,
type: 'slot',
slotName: 'bnts',
span: 13,
},
{
type: 'input',
@ -584,7 +586,7 @@ const data = reactive({
props: {
placeholder: '请输入实体名称',
},
span: 6,
span: 7,
},
{

View File

@ -27,7 +27,7 @@
</el-button>
<el-button
class="global-btn-main"
class="global-btn-second"
:size="fontSizeObj.buttonSize"
:style="{ fontSize: fontSizeObj.baseFontSize }"
type="primary"

View File

@ -0,0 +1,228 @@
<!--
* @Author: lizhiwen
* @Date: 2022-05-17 17:43:02
* @LastEditors: yihong yihong@risesoft.net
* @LastEditTime: 2024-06-24 15:14:43
* @Description:
-->
<template>
<y9Form ref="y9FormRef" :config="y9FormConfig"></y9Form>
</template>
<script lang="ts" setup>
import { computed, h, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { getSystemInfo } from '@/api/system';
import { useSettingStore } from '@/store/modules/settingStore';
import { nameValidator, tablePrefixValidator } from '@/utils/validate';
const settingStore = useSettingStore();
const { t } = useI18n();
// 传过来的 系统 id
const props = defineProps({
id: String, // 系统id
editFlag: Boolean, // 编辑 查看 的对应显示变量
saveClickFlag: Boolean // 是否点击保存 的变量
});
const emits = defineEmits(['getInfoData']);
// 基本信息
let systemInfo = ref({
name: '',
cnName: '',
war: '',
tablePrefix: '',
updateTime: '',
description: '',
environment: ''
});
// 请求详情 函数
async function getInfo() {
if (props.id != null) {
const responseInfo = await getSystemInfo(props.id);
systemInfo.value = responseInfo.data;
}
}
onMounted(() => {
getInfo();
});
// 监听系统id 当发生改变时重新请求数据 并赋值
watch(
() => props.id,
(new_, old_) => {
if (new_ && new_ !== old_) {
getInfo();
}
}
);
watch(
() => props.editFlag,
(new_, old_) => {
y9FormConfig.value.model = systemInfo.value;
changeY9FormType(!new_);
}
);
let y9FormRef = ref();
//表单配置
let y9FormConfig = ref({
descriptionsFormConfig: {
//描述表单配置
column: settingStore.device === 'mobile' ? 1 : 2,
labelAlign: 'center',
labelWidth: '150px',
contentWidth: '200px'
},
model: {},
rules: {}, //表单验证规则
itemList: [
//表单显示列表
{
type: 'text',
type1: 'input', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'name',
label: computed(() => t('系统名称')),
props: {
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.name);
}
}
},
{
type: 'text',
type1: 'input', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'cnName',
label: computed(() => t('系统中文名称')),
props: {
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.cnName);
}
}
},
{
type: 'text',
type1: 'radio', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'war',
label: computed(() => t('包种类')),
props: {
options: [
{ label: computed(() => t('war')), value: true },
{ label: computed(() => t('jar')), value: false }
],
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.war ? t('war') : t('jar'));
}
}
},
{
type: 'text',
type1: 'input', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'tablePrefix',
label: computed(() => t('表前缀')),
props: {
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.tablePrefix);
}
}
},
{
type: 'text',
type1: 'select', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'environment',
label: computed(() => t('系统环境')),
props: {
options: [],
render: () => {
//text类型渲染的内容
return h('span', t('本地化'));
}
}
},
{
type: 'text',
type1: 'text', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'updateTime',
label: computed(() => t('更新时间')),
props: {
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.updateTime);
}
}
},
{
type: 'text',
type1: 'textarea', //自定义字段-编辑时显示的类型
type2: 'text', //自定义字段-非编辑状态显示文本类型
prop: 'description',
label: computed(() => t('系统概述')),
props: {
render: () => {
//text类型渲染的内容
return h('span', systemInfo.value?.description);
},
resize: 'none',
autosize: {
minRows: 3
}
}
}
]
});
//改变y9Form显示类型
function changeY9FormType(isEdit) {
if (isEdit) {
//编辑状态设置表单校验规则
y9FormConfig.value.rules = {
name: [{ required: true, validator: nameValidator, trigger: 'blur' }],
cnName: [{ required: true, message: '请输入中文名', trigger: 'blur' }],
tablePrefix: [{ required: true, validator: tablePrefixValidator, trigger: 'blur' }]
};
} else {
y9FormConfig.value.rules = {};
}
//编辑模式显示type1类型 非编辑模式显示type2类型
y9FormConfig.value.itemList.forEach((item) => {
item.type = isEdit ? item.type1 : item.type2;
//根据environment值改变选项
if (isEdit && item.prop == 'environment') {
item.props.options = [];
item.props.options.push({ label: '本地化', value: 1 });
}
});
}
// 监听 saveClicFlag 当为true 将对象传给 index
watch(
async () => props.saveClickFlag,
async (new_, old_) => {
if (new_) {
let valid = await y9FormRef?.value.elFormRef?.validate((valid) => valid); //获取表单验证结果;
if (props.saveClickFlag) {
systemInfo.value = y9FormRef.value?.model;
emits('getInfoData', systemInfo.value);
return;
}
}
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,700 @@
<template>
<y9Table
ref="tableConfig"
:config="entityTableConfig"
:filterConfig="filterConfig"
@on-curr-page-change="onEntityCurrPageChange"
@on-page-size-change="onEntityPageSizeChange"
@on-change="handlerGetData"
>
<template v-slot:bnts>
<el-button
class="global-btn-main"
type="primary"
@click="addEntityEntity()"
:style="{ fontSize: fontSizeObj.baseFontSize }"
:size="fontSizeObj.buttonSize"
>
<i class="ri-add-circle-line"></i> {{ $t('新增') }}
</el-button>
<el-button
class="global-btn-main"
type="primary"
@click="editEntity()"
:style="{ fontSize: fontSizeObj.baseFontSize }"
:size="fontSizeObj.buttonSize"
>
<i class="ri-edit-line"></i> {{ $t('编辑') }}
</el-button>
</template>
<template v-slot:slotEntitySearch>
<el-button
class="global-btn-main"
type="primary"
@click="search()"
:style="{ fontSize: fontSizeObj.baseFontSize }"
:size="fontSizeObj.buttonSize"
><i class="ri-search-2-line"></i>{{ $t('查询') }}
</el-button>
</template>
</y9Table>
<y9Dialog v-model:config="dialogConfig">
<y9Form
v-if="dialogConfig.type === 'addEntity' || dialogConfig.type === 'editEntity'"
ref="ruleRef"
:config="y9FormConfig"
></y9Form>
</y9Dialog>
<y9Dialog v-model:config="dialogConfig2">
<fieldForm ref="formDialogRef" :v-if="isFormDialogOpen" @close="closeFormDialog" :entityId="entityId"/>
</y9Dialog>
<y9Dialog v-model:config="dialogConfigIndex">
<indexForm ref="indexDialogRef" :v-if="isIndexDialogOpen" @close="()=>{isIndexDialogOpen=false}" :entityId="entityId"/>
</y9Dialog>
<y9Dialog v-model:config="dialogConfigPreview">
<el-tabs v-model="Object.keys(previewEntities)[0]">
<el-tab-pane
v-for="(value, key) in previewEntities"
:label="key"
:name="key"
:key="key"
>
<el-scrollbar height="450px">
<el-link @click="copyText(value)" style="float: right;margin-right: 15px">
<template #icon>
<el-icon><DocumentCopy /></el-icon>
复制
</template>
</el-link>
<pre><p v-text="value"></p></pre>
</el-scrollbar>
</el-tab-pane>
</el-tabs>
</y9Dialog>
</template>
<script lang="ts" setup>
import {computed, h, inject, onMounted, reactive, ref, toRefs, watch} from 'vue';
import {useSettingStore} from '@/store/modules/settingStore';
import {useI18n} from 'vue-i18n';
import {ElNotification} from "element-plus";
import {deleteEntity, getEntityInfo, getEntityList, saveEntity,previewEntity} from "@/api/entity";
import {downloadEntity, generateEntity} from "@/api/export";
import FieldForm from '@/components/dialog/fieldForm.vue';
import {entityNameValidator} from '@/utils/validate';
import clipboard from "clipboard";
const {t} = useI18n();
const settingStore = useSettingStore();
const fontSizeObj: any = inject('sizeObjInfo');
const ruleRef = ref();
const isFormDialogOpen = ref(false);
const isIndexDialogOpen = ref(false);
const formDialogRef = ref(null);
const indexDialogRef = ref(null);
const props = defineProps({
systemId: {
//当前tree节点信息
type: String,
default: '',
},
treeNodeName: {
type: String,
default: '',
},
});
// form 组件的config
const y9FormConfig = ref({
model: {
id: '',
name: '',
mobile: '',
codeSystemId: '',
cnName: '',
tenanted: false,
},
rules: {
name: [{required: true, validator: entityNameValidator, trigger: 'blur'}],
cnName: [{required: true, message: '请输入中文名', trigger: 'blur'}],
tenanted: [{required: true, message: '请选择', trigger: 'blur'}],
},
labelWidth: '120px',
itemList: [
{
type: 'input',
props: {
type: 'text',
placeholder: '请以大写字母开头,只能包含英文字母'
},
label: t('名称'),
prop: 'name',
required: true,
},
{
type: 'input',
props: {
type: 'text',
placeholder: '请输入中文名称'
},
label: t('中文名称'),
prop: 'cnName',
required: true,
},
{
type: 'radio',
props: {
radioType: 'radio',
options: [
{label: t('是'), value: true},
{label: t('否'), value: false},
],
},
label: t('是否多租户'),
prop: 'tenanted',
required: true,
},
],
descriptionsFormConfig: {
labelWidth: '200px',
labelAlign: 'center',
},
});
let dialogConfig = ref({
show: false,
title: '',
type: '',
width: '40%',
onOkLoading: true,
onOk: (newConfig) => {
return new Promise(async (resolve, reject) => {
const ruleFormRef = ruleRef.value.elFormRef;
if (!ruleFormRef) return;
await ruleFormRef.validate((valid, fields) => {
if (valid) {
// 通过验证
// 请求 新增实体 接口
if (dialogConfig.value.type == 'addEntity' || dialogConfig.value.type == 'editEntity') {
ruleRef.value.model.codeSystemId = props.systemId;
saveEntity(ruleRef.value.model).then(async (res) => {
ElNotification({
title: res.success ? t('成功') : t('失败'),
message: res.success ? t('保存成功') : t('保存失败'),
type: res.success ? 'success' : 'error',
duration: 2000,
offset: 80,
});
// 清空表单 数据
clearFormData();
// 重新刷新树 数据
loadEntityList();
resolve();
});
}
} else {
reject();
}
});
});
},
onCancel: (newConfig) => {
clearFormData();
dialogConfig.value.show = false;
}
});
const entityId = ref('');
//字段弹窗
let dialogConfigPreview = ref({
show: false,
title: '预览',
type: '',
width: '60%',
onOkLoading: true,
margin: '50px auto',
});
let dialogConfig2 = ref({
show: false,
title: '',
type: '',
width: '70%',
onOkLoading: true,
onOk: (newConfig) => {
return new Promise(async (resolve, reject) => {
// 调用子组件的方法获取保存字段
try {
let res = await formDialogRef.value.saveFieldList(entityId.value);
// 重新刷新树 数据
if (res) {
loadEntityList();
resolve();
} else {
reject();
}
} catch (error) {
ElNotification({
title: '失败',
message: error.message,
type: 'error',
duration: 2000,
offset: 80,
});
}
});
},
});
let dialogConfigIndex = ref({
show: false,
title: '',
type: '',
width: '70%',
onOkLoading: true,
onOk: (newConfig) => {
return new Promise(async (resolve, reject) => {
// 调用子组件的方法获取保存字段
try {
let res = await indexDialogRef.value.saveIndexListMethod(entityId.value);
// 重新刷新树 数据
if (res) {
loadEntityList();
resolve();
} else {
reject();
}
} catch (error) {
ElNotification({
title: '失败',
message: error.message,
type: 'error',
duration: 2000,
offset: 80,
});
}
});
},
});
watch(
() => props.systemId,
(newVal, oldVal) => {
if (newVal != '') {
currentId.value = '';
loadEntityList();
}
},
{
deep: true,
}
);
const tableHeight = ref(document.documentElement.clientHeight - 60 - 80 - 35 - 62 - 54 - 32 - 54 - 330);
onMounted(() => {
if (props.systemId != '') {
loadEntityList();
}
});
window.onresize = () => {
return (() => {
tableHeight.value = useSettingStore().getWindowHeight - 60 - 80 - 35 - 62 - 54 - 32 - 54 - 330;
})();
};
const clipboardSuccess = () => {
ElNotification({
title: '成功',
type: 'success',
message: '复制成功'
})
}
let previewEntities = ref({});
let entityTableConfig = ref({
columns: [
{title: '', type: 'radio', fixed: 'left', width: 70},
{title: computed(() => t('序号')), showOverflowTooltip: false, key: 'index', width: 80},
{title: computed(() => t('实体名称')), key: 'name'},
{title: computed(() => t('实体中文名称')), key: 'cnName'},
{
title: computed(() => t('是否多租户')), key: 'tenanted',
render: (row) => {//text类型渲染的内容
return h('a', row?.tenanted == true ? t('是') : t('否'))
}
},
{
title: computed(() => t("操作")),
width: '200',
fixed: 'right',
render: (row, params) => {
let editActions = [
h(
'span',
{
style: {
marginLeft: '10px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
const res = await previewEntity(row.id);
if (res.success) {
// let i = 0;
// for (const item in res.data) {
// previewEntities.value[tabsTitle[i]] = res.data[item];
// i++;
// }
// i = 0;
// console.log("previewentities:{}",previewEntities.value)
previewEntities.value = res.data;
dialogConfigPreview.value.show = true;
} else {
ElNotification({
title: '失败',
type: 'error',
message: '预览失败'
})
}
},
},
[
h('i', {
class: 'ri-eye-line',
style: {
marginRight: '2px',
},
}),
//删除
h('span', t('')),
]
),
h(
'span',
{
style: {
marginLeft: '10px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
const res = await deleteEntity(row.id);
if (res.success) {
ElNotification({
title: '成功',
type: 'success',
message: '删除成功'
})
} else {
ElNotification({
title: '失败',
type: 'error',
message: '删除失败'
})
}
loadEntityList();
},
},
[
h('i', {
class: 'ri-delete-bin-line',
style: {
marginRight: '2px',
},
}),
//删除
h('span', t('')),
]
),
h(
'span',
{
style: {
marginLeft: '12px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
const res = await generateEntity(row.id);
if (res.success) {
ElNotification({
title: '成功',
type: 'success',
message: res.msg
})
} else {
ElNotification({
title: '失败',
type: 'error',
message: res.msg
})
}
},
},
[
h('i', {
class: 'ri-file-upload-line',
style: {
marginRight: '2px',
},
}),
// 生成代码
h('span', t('')),
]
),
h(
'span',
{
style: {
marginLeft: '12px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
// 实体下载
try {
const file = await downloadEntity(row.id);
const blob = new Blob([file], {type: 'application/zip'});
const url = URL.createObjectURL(blob);
// 创建下载链接并模拟点击下载
const link = document.createElement('a');
link.href = url;
link.download = row.name + '.zip';
link.click();
// 释放URL对象
window.URL.revokeObjectURL(url);
} catch (e) {
console.log(e)
}
},
},
[
h('i', {
class: 'ri-download-2-line',
style: {
marginRight: '2px',
},
}),
//查看属性
h('span', t('')),
]
),
h(
'span',
{
style: {
marginLeft: '12px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
entityId.value = row.id;
dialogConfig2.value.type = "editEntity";
dialogConfig2.value.show = true;
// const res = await getEntity(row.id);
// y9FormConfig.value.model = res.data;
},
},
[
h('i', {
class: 'ri-menu-line',
style: {
marginRight: '2px',
},
}),
h('span', t('')),
]
),
h(
'span',
{
style: {
marginLeft: '12px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
entityId.value = row.id;
// dialogConfigIndex.value.type = "editEntity";
dialogConfigIndex.value.show = true;
},
},
[
h('i', {
class: 'ri-git-merge-line',
style: {
marginRight: '2px',
},
}),
h('span', t('')),
]
),
];
return h('span', editActions);
},
},
],
tableData: [],
pageConfig: {
currentPage: 1, //当前页数支持 v-model 双向绑定
pageSize: 20, //每页显示条目个数支持 v-model 双向绑定
total: 0, //总条目数
},
selectedVal: '',
loading: false,
});
const copyText = (val) =>{
clipboard.copy(val);
clipboardSuccess();
}
const data = reactive({
loading: false, // 全局loading
params: {
name: '',
},
editId: -1,
filterConfig: {
filtersValueCallBack: (filter) => {
params.value.name = filter;
},
itemList: [
{
type: 'slot',
slotName: 'bnts',
span: 13,
},
{
type: 'input',
value: '',
key: 'name',
label: t('实体名称'),
labelWith: '82px',
ref: 'entityName',
props: {
placeholder: '请输入实体名称',
},
span: 7,
},
{
type: 'slot',
slotName: 'slotEntitySearch',
span: 4,
},
],
showBorder: true,
},
});
var FormData = ref({});
let {loading, filterConfig, params} = toRefs(data);
function clearFormData(){
y9FormConfig.value.model = {
id: '',
name: '',
mobile: '',
codeSystemId: '',
cnName: '',
tenanted: false,
};
}
//当前页改变时触发
function onEntityCurrPageChange(currPage) {
entityTableConfig.value.pageConfig.currentPage = currPage;
loadEntityList();
}
//每页条数改变时触发
function onEntityPageSizeChange(pageSize) {
entityTableConfig.value.pageConfig.pageSize = pageSize;
loadEntityList();
}
function loadEntityList() {
entityTableConfig.value.loading = true;
let page = entityTableConfig.value.pageConfig.currentPage;
let rows = entityTableConfig.value.pageConfig.pageSize;
let query = {systemId: props.systemId, name: params.value.name.name, page: page, size: rows};
getEntityList(query).then((res) => {
if (res.success) {
let tableData = res.rows;
tableData.forEach((row, index) => {
row.index = (page - 1) * rows + index + 1;
});
entityTableConfig.value.tableData = tableData;
entityTableConfig.value.pageConfig.total = res.total;
entityTableConfig.value.loading = false;
}
});
}
async function search() {
entityTableConfig.value.pageConfig.currentPage = 1;
loadEntityList();
}
const currentId = ref('');
// 表格 选择框 选择后获取数据
function handlerGetData(id, data) {
currentId.value = id;
console.log(currentId.value)
}
function addEntityEntity() {
dialogConfig.value.type = 'addEntity';
clearFormData();
dialogConfig.value.show = true;
}
async function editEntity() {
if (currentId.value == '') {
ElNotification({
title: "未选中",
type: "warning",
message: "请选择实体",
})
return;
}
dialogConfig.value.type = 'editEntity';
dialogConfig.value.show = true;
let res = await getEntityInfo(currentId.value);
y9FormConfig.value.model = res.data;
}
const closeFormDialog = () => {
isFormDialogOpen.value = false;
};
</script>
<style>
.list-tabs > .el-tabs__content {
padding: 10px;
color: #6b778c;
}
</style>
<style lang="scss" scoped>
:deep(.is-plain) {
border: 1px solid var(--el-color-primary);
margin-right: 10px;
border-radius: 5px;
i {
margin-right: 5px;
}
}
</style>

View File

@ -0,0 +1,38 @@
<template>
<y9Card :title="`${currInfo.name ? currInfo.name : ''}`">
<div style="height: 213px">
<el-alert
:style="{ fontSize: fontSizeObj.baseFontSize }"
:title="$t('请选择左侧树,选择系统再进行操作。')"
type="warning"
/>
</div>
</y9Card>
</template>
<script lang="ts" setup>
import { $deepAssignObject } from '@/utils/object';
import { inject, ref, watch } from 'vue';
// 注入 字体对象
const fontSizeObj: any = inject('sizeObjInfo');
const props = defineProps({
currTreeNodeInfo: {
//当前tree节点信息
type: Object,
default: () => {
return {};
}
}
});
let currInfo = ref(props.currTreeNodeInfo);
watch(
() => props.currTreeNodeInfo,
(newVal) => {
currInfo.value = $deepAssignObject(currInfo.value, newVal);
}
);
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,676 @@
<template>
<fixedTreeModule
ref="fixedTreeRef"
:treeApiObj="treeApiObj"
nodeLabel="cnName"
@onTreeClick="onTreeClick"
:showNodeDelete="true"
@onDeleteTree="systemRemove"
:hiddenSearch="true"
>
<template v-slot:treeHeaderRight>
<el-button
:size="fontSizeObj.buttonSize"
:style="{ fontSize: fontSizeObj.baseFontSize }"
class="global-btn-main"
type="primary"
@click="addSystem()"
v-if="userInfo.globalManager"
>
<i class="ri-add-line"></i>
<span> {{ $t('添加模板') }}</span>
</el-button>
</template>
<template #rightContainer>
<template v-if="isShow">
<y9Card :title="`${$t('基本信息')} - ${currTreeNodeInfo.cnName ? currTreeNodeInfo.cnName : ''}`">
<template v-slot>
<div class="basic-btns">
<span class="btn-top">
<el-button class="global-btn-main" type="primary"
:size="fontSizeObj.buttonSize"
:style="{ fontSize: fontSizeObj.baseFontSize }"
v-if="editBtnFlag" @click="editBtnFlag = false">
<i class="ri-edit-line"></i>
{{ $t('编辑') }}
</el-button>
<span v-else>
<el-button class="global-btn-main" type="primary"
:size="fontSizeObj.buttonSize"
:style="{ fontSize: fontSizeObj.baseFontSize }"
:loading="saveBtnLoading" @click="saveBtnClick = true">
<i class="ri-save-line"></i>
{{ $t('保存') }}
</el-button>
<el-button class="global-btn-second"
:size="fontSizeObj.buttonSize"
:style="{ fontSize: fontSizeObj.baseFontSize }"
@click="editBtnFlag = true">
<i class="ri-close-line"></i>
{{ $t('取消') }}
</el-button>
</span>
</span>
</div>
<BaseInfo :id="currTreeNodeInfo.id" :editFlag="editBtnFlag" :saveClickFlag="saveBtnClick"
@getInfoData="handlerEditSave"/>
</template>
</y9Card>
<y9Card :title="`${$t('实体列表')}${currTreeNodeInfo.name ? ' - ' + currTreeNodeInfo.name : ''}`">
<div style="display: flex; justify-content: space-between; text-align: right; margin-top: -10px" class="expand-btns">
</div>
<entityList
:systemId="currTreeNodeInfo.id"
:treeNodeName="currTreeNodeInfo.name">
</entityList>
</y9Card>
</template>
<template v-else>
<reminder :currTreeNodeInfo="currTreeNodeInfo"></reminder>
</template>
</template>
</fixedTreeModule>
<!-- 添加模板 -->
<y9Dialog v-model:config="dialogConfig">
<y9Form v-if="dialogConfig.type === 'addSystem'" ref="ruleRef" :config="formSystem"></y9Form>
<y9Table v-if="dialogConfig.type === 'addTemplate'"
v-model:selectedVal="selectedVal"
:config="y9TableConfig"
@on-curr-page-change="onSystemCurrPageChange"
@on-page-size-change="onSystemPageSizeChange">
</y9Table>
</y9Dialog>
<y9Dialog v-model:config="dialogConfig2">
<y9Table
:config="y9TableExpandConfig"
@on-curr-page-change="onSystemCurrPageChange"
@on-page-size-change="onSystemPageSizeChange">
<template #childContent="props">
<div>
<el-table :data="props.row.y9CodeFields" style="width: 100%">
<el-table-column prop="name" label="字段名称" width="180"/>
<el-table-column prop="cnName" label="中文名称" width="180"/>
<el-table-column prop="fieldType" label="字段类型" width="150"/>
<el-table-column prop="fieldLength" label="字段长度" width="130"/>
<el-table-column prop="nullable" label="可否为空" width="130"/>
<el-table-column prop="defaultValue" label="默认值" width="130"/>
<el-table-column prop="isLarge" label="是否长对象" width="130"/>
</el-table>
</div>
</template>
</y9Table>
</y9Dialog>
<el-button style="display: none" v-loading.fullscreen.lock="loading"></el-button>
</template>
<script lang="ts" setup>
import {useI18n} from 'vue-i18n';
import EntityList from './comps/entityList.vue';
import {useSettingStore} from '@/store/modules/settingStore';
import {computed, h, inject, reactive, ref, toRefs, watch} from 'vue';
import {ElNotification} from "element-plus";
import {deleteSystem, getSystemList, saveSystem, saveSystemList} from "@/api/system";
import {download, generateCode} from "@/api/export";
import BaseInfo from "@/views/template/comps/baseInfo.vue";
import Reminder from "@/views/template/comps/reminder.vue";
import {nameValidator, tablePrefixValidator} from "@/utils/validate";
import {getEntityAndField} from "@/api/entity";
import y9_storage from '@/utils/storage';
let userInfo = ref({});
userInfo.value = y9_storage.getObjectItem('ssoUserInfo');
const route = useRoute();
const settingStore = useSettingStore();
const {t} = useI18n();
// 注入 字体对象
const fontSizeObj: any = inject('sizeObjInfo');
// 点击保存按钮 flag
let saveBtnClick = ref(false);
// 控制 基本信息 编辑按钮 保存取消按钮的显示与隐藏
let editBtnFlag = ref(true);
// 保存 按钮 loading
let saveBtnLoading = ref(false);
// 系统环境 0-有生云1-本地
const environment = ref('')
const isShow = ref(false)
//数据
const data = reactive({
fixedTreeRef: '', //tree实例
loading: false,
treeApiObj: {
//tree接口对象
topLevel: '',
},
currTreeNodeInfo: '', //当前tree节点的信息
//气泡操作列表配置
actionListConfig: {
padding: "0px",
listData: [
{
id: "addSystem",
name: computed(() => t("新增模板"))
},
{
id: "addTemplate",
name: computed(() => t("选择模板"))
},
],
},
y9ListRef: "",
});
//操作列表点击事件
async function addTemplate() {
let params = {
template: 1,
page: y9TableConfig.value.pageConfig.currentPage,
size: y9TableConfig.value.pageConfig.pageSize
}
const res = await getSystemList(params);
y9TableConfig.value.pageConfig.total = res.total;
y9TableConfig.value.pageConfig.currentPage = 1;
y9TableConfig.value.tableData = res.rows;
selectedVal.value = [];
Object.assign(dialogConfig.value, {
show: true,
title: computed(() => t(`选择模板`)),
type: 'addTemplate',
showFooter: true,
width: '60%',
})
}
const treeApiObj = ref({
topLevel: async () => {
let data = []
environment.value = route.meta.environment;
let params = {
environment: environment.value,
template: 1
}
const res = await getSystemList(params);
data = res.rows;
data.forEach(item => {
if (item.template == '1') {
item.cnName = item.cnName + ' (模板)'
}
item.isLeaf = true;
})
if (data.length > 0) {
isShow.value = true;
} else {
isShow.value = false;
}
return data
},
});
let y9TableConfig = ref({
headerBackground: true,
height: "450px",
pageConfig: {
background: false, //是否显示背景色
layout: "prev, pager, next,sizes", //布局
currentPage: 1, //当前页数支持 v-model 双向绑定
pageSize: 5, //每页显示条目个数支持 v-model 双向绑定
pageSizeOpts: [5, 10, 20, 30, 40], //每页显示个数选择器的选项设置
},
columns: [{
type: "selection",
width: 60,
},
{
type: "index",
title: "序号",
width: 60,
},
{
title: "系统名称",
key: "name",
width: 130,
},
{
title: "系统中文名称",
key: "cnName",
width: 130,
},
{
title: "打包方式",
key: "war",
width: 100,
render: (row) => {//text类型渲染的内容
return h('a', row?.war == true ? 'war' : 'jar')
}
},
{
title: "系统概述",
key: "description",
width: 420,
},
{
title: "操作",
render: (row, params) => {
let openDetail = [
h(
'span',
{
style: {
marginLeft: '10px',
display: 'inline-flex',
alignItems: 'center',
},
onClick: async () => {
debugger
let data = await getEntityAndField({systemId: row.id});
y9TableExpandConfig.value.tableData = data.data;
Object.assign(dialogConfig2.value, {
show: true,
title: computed(() => t(`${row.cnName}`)),
type: row.id,
showFooter: true,
width: '60%',
})
},
},
[
h('i', {
class: 'ri-menu-line',
style: {
marginRight: '2px',
},
}),
//删除
h('span', t('')),
]
),
];
return h('span', openDetail);
},
},
],
tableData: []
})
// 模板列表表格
let y9TableExpandConfig = ref({
border: false,
headerBackground: true,
height: "500px",
columns: [
{
type: "expand",
slot: "childContent",
width: 60,
},
{title: computed(() => t('实体名称')), key: 'name'},
{title: computed(() => t('实体中文名称')), key: 'cnName'},
{
title: computed(() => t('是否多租户')), key: 'tenanted',
render: (row) => {//text类型渲染的内容
return h('a', row?.tenanted == true ? '是' : '否')
}
},
],
tableData: [],
pageConfig: false,//不分页
})
let selectedVal = ref([1]);
async function handlerEditSave(data) {
saveBtnLoading.value = true;
saveSystem(data).then((res) => {
//1.更新当前节点的信息
const treeData = fixedTreeRef.value.getTreeData();//获取tree数据
//2.手动设置点击当前节点
const currNode = fixedTreeRef.value.findNode(treeData, res.data.id); //找到树节点对应的节点信息
fixedTreeRef.value.handClickNode(currNode);
Object.assign(currNode, data)//合并节点信息
ElNotification({
title: res.success ? t('成功') : t('失败'),
message: res.success ? t('保存成功') : t('保存失败'),
type: res.success ? 'success' : 'error',
duration: 2000,
offset: 80,
});
// loading为false 编辑 按钮出现 保存按钮未点击状态
saveBtnLoading.value = false;
editBtnFlag.value = true;
saveBtnClick.value = false;
// 清空表单 数据
formSystem.value.model = {name: ''};
// 重新刷新树 数据
fixedTreeRef.value.onRefreshTree();
});
}
const {fixedTreeRef, currTreeNodeInfo, loading, y9ListRef, actionListConfig} = toRefs(data);
// form 组件的config
const formSystem = ref({
model: {
name: '',
cnName: '',
tablePrefix: '',
description: '',
war: true,
environment: '',
},
rules: {
name: [{required: true, validator: nameValidator, trigger: 'blur'}],
cnName: [{required: true, message: '请输入中文名', trigger: 'blur'}],
tablePrefix: [{required: true, validator: tablePrefixValidator, trigger: 'blur'}],
war: [{required: true, message: '请选择包类型', trigger: 'blur'}],
},
labelWidth: '120px',
itemList: [
{
type: 'input',
props: {
type: 'text',
placeholder: '请遵循驼峰命名原则'
},
label: t('系统名称'),
prop: 'name',
required: true,
},
{
type: 'input',
props: {
type: 'text',
placeholder: '请输入中文名'
},
label: t('系统中文名称'),
prop: 'cnName',
required: true,
},
{
type: 'input',
props: {
type: 'text',
placeholder: '请以字母开头,下划线结尾'
},
label: t('表前缀'),
prop: 'tablePrefix',
required: true,
},
{
type: 'radio',
props: {
radioType: 'radio',
options: [
{label: t('war'), value: true},
{label: t('jar'), value: false},
],
},
label: t('包种类'),
prop: 'war',
required: true,
},
{
type: 'input',
props: {
type: 'text',
},
label: t('系统概述'),
prop: 'description',
required: false,
},
],
descriptionsFormConfig: {
labelWidth: '200px',
labelAlign: 'center',
},
});
let dialogConfig = ref({
show: false,
title: '',
type: '',
width: '40%',
onOkLoading: true,
onOk: (newConfig) => {
return new Promise(async (resolve, reject) => {
if (newConfig.value.type == 'addSystem') {
const ruleFormRef = ruleRef.value.elFormRef;
if (!ruleFormRef) return;
await ruleFormRef.validate((valid, fields) => {
if (valid) {
// 通过验证
ruleRef.value.model.environment = environment.value;
// 请求 新增系统 接口
saveSystem(ruleRef.value.model).then(async (res) => {
/**
* 对树进行操作
*/
//1.更新一级节点数据
const treeData = await postNode({$level: 0}); //重新请求一级节点
await fixedTreeRef.value.setTreeData(treeData);
//2.手动设置点击当前节点
const currNode = fixedTreeRef.value.findNode(treeData, res.data.id); //找到树节点对应的节点信息
fixedTreeRef.value.handClickNode(currNode);
ElNotification({
title: res.success ? t('成功') : t('失败'),
message: res.success ? t('保存成功') : t('保存失败'),
type: res.success ? 'success' : 'error',
duration: 2000,
offset: 80,
});
// 清空表单 数据
formSystem.value.model = {name: ''};
// 重新刷新树 数据
fixedTreeRef.value.onRefreshTree();
resolve();
});
} else {
reject();
}
});
}
if (newConfig.value.type == 'addTemplate') {
selectedVal.value.forEach((item) => {
item.environment = environment.value;
})
saveSystemList(selectedVal.value).then(async (res) => {
//1.更新一级节点数据
const treeData = await postNode({$level: 0}); //重新请求一级节点
await fixedTreeRef.value.setTreeData(treeData);
//2.手动设置点击当前节点
const currNode = fixedTreeRef.value.findNode(treeData, res.data.id); //找到树节点对应的节点信息
fixedTreeRef.value.handClickNode(currNode);
ElNotification({
title: res.success ? t('成功') : t('失败'),
message: res.success ? t('保存成功') : t('保存失败'),
type: res.success ? 'success' : 'error',
duration: 2000,
offset: 80,
});
// 清空表单 数据
formSystem.value.model = {name: ''};
// 重新刷新树 数据
fixedTreeRef.value.onRefreshTree();
resolve();
});
}
});
},
});
let dialogConfig2 = ref({
show: false,
title: '',
type: '',
width: '40%',
onOkLoading: true,
okText: false,
cancelText: '关闭'
});
//点击tree的回调
async function onTreeClick(currTreeNode) {
currTreeNodeInfo.value = currTreeNode;
}
// 删除系统
function systemRemove(data) {
ElMessageBox.confirm(`${t('是否删除')}${data.cnName}?`, t('提示'), {
confirmButtonText: t('确定'),
cancelButtonText: t('取消'),
type: 'info',
})
.then(async () => {
loading.value = true;
// 删除系统
const result = await deleteSystem(data.id);
loading.value = false;
if (result.success) {
/**
* 对树进行操作
*/
//1.需要手动点击的节点信息如果有父节点则默认点击父节点没有则点击tree数据的第一个节点
const treeData = fixedTreeRef.value.getTreeData();//获取tree数据
let clickNode = null;
if (data.parentId) {
clickNode = fixedTreeRef.value.findNode(treeData, data.parentId);//找到父节点的信息
fixedTreeRef.value?.y9TreeRef?.remove(data);//删除此节点
} else if (treeData.length > 0) {
fixedTreeRef.value?.y9TreeRef?.remove(data);//删除此节点
clickNode = treeData[0]
}
if (clickNode) {
fixedTreeRef.value?.handClickNode(clickNode)//手动设置点击当前节点
}
ElNotification({
title: t('成功'),
message: t('删除成功'),
type: 'success',
duration: 2000,
offset: 80,
});
}
})
.catch(() => {
ElMessage({
type: 'info',
message: t('已取消删除'),
offset: 65,
});
});
}
function postNode(node) {
return new Promise((resolve, reject) => {
fixedTreeRef.value.onTreeLazyLoad(node, data => {
resolve(data)
})
})
}
const ruleRef = ref();
function addSystem() {
formSystem.value.model = {
name: '',
cnName: '',
tablePrefix: '',
description: '',
war: true,
environment: '',
}
Object.assign(dialogConfig.value, {
show: true,
title: computed(() => t(`新增系统`)),
type: 'addSystem',
showFooter: true,
width: '60%',
})
}
//当前页改变时触发
async function onSystemCurrPageChange(currPage) {
y9TableConfig.value.pageConfig.currentPage = currPage;
let params = {
template: 1,
page: y9TableConfig.value.pageConfig.currentPage,
size: y9TableConfig.value.pageConfig.pageSize
}
const res = await getSystemList(params);
y9TableConfig.value.tableData = res.rows;
y9TableConfig.value.pageConfig.total = res.total;
selectedVal.value = [];
}
//每页条数改变时触发
async function onSystemPageSizeChange(pageSize) {
y9TableConfig.value.pageConfig.pageSize = pageSize;
let params = {
template: 1,
page: y9TableConfig.value.pageConfig.currentPage,
size: y9TableConfig.value.pageConfig.pageSize
}
const res = await getSystemList(params);
y9TableConfig.value.tableData = res.rows;
y9TableConfig.value.pageConfig.total = res.total;
selectedVal.value = [];
}
watch(route, async (to, from) => {
if (to.meta != null) {
environment.value = to.meta.environment;
}
console.log("watch:" + environment.value);
if (to.path == '/system' || to.path == '/localSystem') {
//1.更新一级节点数据
const treeData = await postNode({$level: 0}); //重新请求一级节点
await fixedTreeRef.value.setTreeData(treeData);
if (treeData.length > 0) {
isShow.value = true;
fixedTreeRef.value.onRefreshTree();
} else {
isShow.value = false;
}
}
});
</script>
<style lang="scss" scoped>
.basic-btns {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-bottom: 20px;
.btn-top {
margin-bottom: 10px;
}
}
</style>