Compare commits
No commits in common. "master" and "main" have entirely different histories.
|
|
@ -1,13 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
insert_final_newline = false
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# ---> Actionscript
|
||||||
|
# Build and Release Folders
|
||||||
|
bin-debug/
|
||||||
|
bin-release/
|
||||||
|
[Oo]bj/
|
||||||
|
[Bb]in/
|
||||||
|
|
||||||
# dependencies
|
# Other files and folders
|
||||||
/node_modules
|
.settings/
|
||||||
|
|
||||||
# production
|
# Executables
|
||||||
/dist
|
*.swf
|
||||||
/demo
|
*.air
|
||||||
|
*.ipa
|
||||||
|
*.apk
|
||||||
|
|
||||||
|
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
|
||||||
|
# should NOT be excluded as they contain compiler settings and other important
|
||||||
|
# information for Eclipse / Flash Builder.
|
||||||
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
.idea
|
|
||||||
yarn.lock
|
|
||||||
/openspec/
|
|
||||||
/.codebuddy/
|
|
||||||
/.idea/
|
|
||||||
/.playwright-cli/
|
|
||||||
/.vscode/
|
|
||||||
/.workbuddy/
|
|
||||||
|
|
|
||||||
76
README.md
76
README.md
|
|
@ -1,75 +1,3 @@
|
||||||
# 微应用模板说明文档
|
# safety-eval-service-frontend
|
||||||
|
|
||||||
## 在线文档
|
重庆安全评价前端项目
|
||||||
|
|
||||||
https://www.yuque.com/buhangjiecheshen-ymbtb/qc0093/gxdun1dphetcurko
|
|
||||||
|
|
||||||
|
|
||||||
## 安装依赖
|
|
||||||
项目依赖可通过 **yarn** 或 **npm** 进行安装:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 使用 yarn
|
|
||||||
yarn
|
|
||||||
|
|
||||||
# 或使用 npm
|
|
||||||
npm i
|
|
||||||
```
|
|
||||||
|
|
||||||
## 开发服务&打包应用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 启动开发服务
|
|
||||||
yarn serve:<env>
|
|
||||||
# 或
|
|
||||||
npm run serve:<env>
|
|
||||||
|
|
||||||
# 开发环境打包
|
|
||||||
yarn build:<env>
|
|
||||||
# 或
|
|
||||||
npm run build:<env>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 路由配置&路由访问&自动化路由
|
|
||||||
所有页面必须放在`src/pages/container`目录下,启动访问页面请在浏览器地址栏输入`/<appIdentifier>/container/<你的路由页面文件名称>`
|
|
||||||
解释:
|
|
||||||
1. 所有页面组件命名为`index.js`或`index.jsx`,必须放在一个首字母大写的文件中。
|
|
||||||
2. `container`为固定路径访问格式
|
|
||||||
3. `<appIdentifier>`为应用的唯一标识符,也是应用路由的`basename`,在底座中用于区分其他应用。可在根目录 `jjb.config.js` 文件的 `appIdentifier` 节点中进行修改。
|
|
||||||
4. 自动化路由将根据`pages/container`中的路由页面文件自动生成路由树。
|
|
||||||
5. `id`匹配路由,文件夹命名`_id`
|
|
||||||
|
|
||||||
## 应用接口环境配置
|
|
||||||
应用接口环境相关配置在根目录 `jjb.config.js` 文件的 `environment` 节点中进行定义。
|
|
||||||
|
|
||||||
## 应用开发服务配置
|
|
||||||
应用开发服务相关配置在根目录 `jjb.config.js` 文件的 `server` 节点中进行定义。
|
|
||||||
|
|
||||||
## Babel 配置
|
|
||||||
应用的 `Babel` 配置在根目录 `jjb.babel.js` 文件中进行管理。
|
|
||||||
|
|
||||||
## 目录说明
|
|
||||||
|
|
||||||
1. `src/api/` 配置各个 store 模块的接口数据。
|
|
||||||
2. `src/components/` 全局公共组件。
|
|
||||||
3. `src/enumerate/` 全局各种枚举配置。
|
|
||||||
4. `src/pages/` 页面文件目录。
|
|
||||||
5. `src/main.js` 应用的入口文件。
|
|
||||||
|
|
||||||
## 核心依赖
|
|
||||||
1. `@cqsjjb/jjb-common-decorator`
|
|
||||||
1. 公共装饰器库,内部包含:
|
|
||||||
1. 按钮权限处理
|
|
||||||
2. antd/Table 控制
|
|
||||||
3. 文本重命名处理
|
|
||||||
4. 具体使用方式可参考各个模块的 `d.ts`。
|
|
||||||
2. `@cqsjjb/jjb-common-lib`
|
|
||||||
1. 公共工具库,具体 API 使用请查看 `d.ts`
|
|
||||||
3. `@cqsjjb/jjb-dva-runtime`
|
|
||||||
1. 核心运行时,基于 `dvajs` 实现。
|
|
||||||
1. 应用核心依赖模块
|
|
||||||
2. 应用的自动化路由
|
|
||||||
3. `store` 模块接口数据处理
|
|
||||||
4. 均基于此依赖实现,具体使用方式请查看 `d.ts`。
|
|
||||||
4. `@cqsjjb/jjb-react-admin-component`
|
|
||||||
1. 公共组件库,具体组件使用方式请查看 `d.ts`。
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
_ooOoo_
|
|
||||||
o8888888o
|
|
||||||
88" . "88
|
|
||||||
(| -_- |)
|
|
||||||
O\ = /O
|
|
||||||
____/`---'\____
|
|
||||||
. ' \\| |// `.
|
|
||||||
/ \\||| : |||// \
|
|
||||||
/ _||||| -:- |||||- \
|
|
||||||
| | \\\ - /// | |
|
|
||||||
| \_| ''\---/'' | |
|
|
||||||
\ .-\__ `-` ___/-. /
|
|
||||||
___`. .' /--.--\ `. . __
|
|
||||||
."" '< `.___\_<|>_/___.' >'"".
|
|
||||||
| | : `- \`.;`\ _ /`;.`/ - ` : | |
|
|
||||||
\ \ `-. \_ __\ /__ _/ .-` / /
|
|
||||||
======`-.____`-.___\_____/___.-`____.-'======
|
|
||||||
`=---='
|
|
||||||
|
|
||||||
.............................................
|
|
||||||
佛祖保佑 永无BUG
|
|
||||||
佛曰:
|
|
||||||
写字楼里写字间,写字间里程序员;
|
|
||||||
程序人员写程序,又拿程序换酒钱。
|
|
||||||
酒醒只在网上坐,酒醉还来网下眠;
|
|
||||||
酒醉酒醒日复日,网上网下年复年。
|
|
||||||
但愿老死电脑间,不愿鞠躬老板前;
|
|
||||||
奔驰宝马贵者趣,公交自行程序员。
|
|
||||||
别人笑我忒疯癫,我笑自己命太贱;
|
|
||||||
不见满街漂亮妹,哪个归得程序员?
|
|
||||||
*/
|
|
||||||
|
|
||||||
const blessedByBuddha
|
|
||||||
= "%c _ooOoo_\n"
|
|
||||||
+ " o8888888o\n"
|
|
||||||
+ " 88\" . \"88\n"
|
|
||||||
+ " (| -_- |)\n"
|
|
||||||
+ " O\\ = /O\n"
|
|
||||||
+ " ____/`---'\\____\n"
|
|
||||||
+ " . ' \\\\| |// `.\n"
|
|
||||||
+ " / \\\\||| : |||// \\\n"
|
|
||||||
+ " / _||||| -:- |||||- \\\n"
|
|
||||||
+ " | | \\\\\\ - /// | |\n"
|
|
||||||
+ " | \\_| ''\\---/'' | |\n"
|
|
||||||
+ " \\ .-\\__ `-` ___/-. /\n"
|
|
||||||
+ " ___`. .' /--.--\\ `. . __\n"
|
|
||||||
+ " .\"\" '< `.___\\_<|>_/___.' >'\"\".\n"
|
|
||||||
+ " | | : `- \\`.;`\\ _ /`;.`/ - ` : | |\n"
|
|
||||||
+ " \\ \\ `-. \\_ __\\ /__ _/ .-` / /\n"
|
|
||||||
+ " ======`-.____`-.___\\_____/___.-`____.-'======\n"
|
|
||||||
+ " `=---='\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "%c .............................................\n"
|
|
||||||
+ " 佛祖保佑 永无BUG\n"
|
|
||||||
+ "\n"
|
|
||||||
+ "%c 佛曰:\n"
|
|
||||||
+ " 写字楼里写字间,写字间里程序员;\n"
|
|
||||||
+ " 程序人员写程序,又拿程序换酒钱。\n"
|
|
||||||
+ " 酒醒只在网上坐,酒醉还来网下眠;\n"
|
|
||||||
+ " 酒醉酒醒日复日,网上网下年复年。\n"
|
|
||||||
+ " 但愿老死电脑间,不愿鞠躬老板前;\n"
|
|
||||||
+ " 奔驰宝马贵者趣,公交自行程序员。\n"
|
|
||||||
+ " 别人笑我忒疯癫,我笑自己命太贱;\n"
|
|
||||||
+ " 不见满街漂亮妹,哪个归得程序员?";
|
|
||||||
console.log(blessedByBuddha, "color:#ffd700", "color:red", "color:#1e80ff");
|
|
||||||
|
|
@ -1,572 +0,0 @@
|
||||||
# 证照管理子应用 — 本地开发指南
|
|
||||||
|
|
||||||
## 目录
|
|
||||||
|
|
||||||
- [1. 项目概述](#1-项目概述)
|
|
||||||
- [2. 环境准备与启动](#2-环境准备与启动)
|
|
||||||
- [3. 路由系统](#3-路由系统)
|
|
||||||
- [4. 菜单配置](#4-菜单配置)
|
|
||||||
- [5. 页面开发流程](#5-页面开发流程)
|
|
||||||
- [6. API 接口声明](#6-api-接口声明)
|
|
||||||
- [7. 状态管理(DVA)](#7-状态管理dva)
|
|
||||||
- [8. 共享组件](#8-共享组件)
|
|
||||||
- [9. 本地模拟布局](#9-本地模拟布局)
|
|
||||||
- [10. 已知问题与注意事项](#10-已知问题与注意事项)
|
|
||||||
- [11. 目录结构参考](#11-目录结构参考)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. 项目概述
|
|
||||||
|
|
||||||
本项目是基于 **qiankun 微前端** 框架的子应用,运行在 **GBS 底座平台** 内。使用以下核心技术栈:
|
|
||||||
|
|
||||||
| 技术 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| React 18 | UI 组件框架 |
|
|
||||||
| Ant Design 5.x | UI 组件库 |
|
|
||||||
| @cqsjjb/jjb-dva-runtime | 底座 DVA 状态管理运行时 |
|
|
||||||
| @cqsjjb/jjb-common-decorator | 装饰器工具(权限、模块加载等) |
|
|
||||||
| rspack | 构建打包工具 |
|
|
||||||
| pnpm | 包管理器 |
|
|
||||||
|
|
||||||
项目通过 `jjb.config.js` 中配置的 `appIdentifier: "certificate"` 注册到底座,所有页面路由前缀为 `/certificate/container/`。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. 环境准备与启动
|
|
||||||
|
|
||||||
### 2.1 安装依赖
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.2 启动命令
|
|
||||||
|
|
||||||
| 命令 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `pnpm run serve:development` | **开发环境启动**(推荐) |
|
|
||||||
| `pnpm run serve:production` | 生产环境配置启动 |
|
|
||||||
| `pnpm run build:development` | 开发环境构建 |
|
|
||||||
| `pnpm run build:production` | 生产环境构建 |
|
|
||||||
|
|
||||||
### 2.3 访问地址
|
|
||||||
|
|
||||||
启动后开发服务器默认监听 `http://127.0.0.1:8081`,访问:
|
|
||||||
|
|
||||||
```
|
|
||||||
http://localhost:8081/certificate/container/
|
|
||||||
http://localhost:8081/certificate/container/Test
|
|
||||||
```
|
|
||||||
|
|
||||||
> **注意**:本地独立启动时,应用处于 qiankun 独立运行模式(`window.__POWERED_BY_QIANKUN__` 为 false),
|
|
||||||
> 会使用内置的 `SimulatedLayout` 模拟侧边栏和标签页布局。
|
|
||||||
|
|
||||||
### 2.4 配置说明
|
|
||||||
|
|
||||||
`jjb.config.js` 中的关键配置项:
|
|
||||||
|
|
||||||
```js
|
|
||||||
module.exports = {
|
|
||||||
appIdentifier: "certificate", // 应用唯一标识,对应路由前缀
|
|
||||||
server: {
|
|
||||||
port: "8081", // 开发服务器端口
|
|
||||||
host: "127.0.0.1", // 服务地址
|
|
||||||
},
|
|
||||||
environment: {
|
|
||||||
development: {
|
|
||||||
API_HOST: "https://gbs-gateway.qhdsafety.com", // 开发环境接口地址
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. 路由系统
|
|
||||||
|
|
||||||
### 3.1 约定式路由
|
|
||||||
|
|
||||||
本项目使用 **文件系统约定式路由**,由 `@cqsjjb/jjb-dva-runtime` 框架自动注册。页面对应的路径由目录结构决定:
|
|
||||||
|
|
||||||
```
|
|
||||||
src/pages/Container/<目录层级>/index.js → /certificate/container/<目录层级>
|
|
||||||
```
|
|
||||||
|
|
||||||
**示例:**
|
|
||||||
|
|
||||||
| 文件路径 | 对应路由 |
|
|
||||||
|----------|----------|
|
|
||||||
| `src/pages/Container/Test/index.js` | `/certificate/container/Test` |
|
|
||||||
| `src/pages/Container/Supervision/index.js` | `/certificate/container/Supervision` |
|
|
||||||
| `src/pages/Container/Supervision/PersonnelLicense/PersonInCharge/List/index.js` | `/certificate/container/Supervision/PersonnelLicense/PersonInCharge/List` |
|
|
||||||
|
|
||||||
### 3.2 页面组件类型
|
|
||||||
|
|
||||||
项目中有两类页面组件:
|
|
||||||
|
|
||||||
1. **容器组件**(中间层级):作为 `{props.children}` 的容器,负责嵌套子页面
|
|
||||||
```js
|
|
||||||
function ContainerPage(props) {
|
|
||||||
return <div>{props.children}</div>;
|
|
||||||
}
|
|
||||||
export default ContainerPage;
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **叶子页面**(终端页面):实际的业务功能页面,通过 `Connect` 连接 DVA 数据
|
|
||||||
```js
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
return <div>业务内容</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(List);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 路由匹配规则
|
|
||||||
|
|
||||||
- 框架自动递归扫描 `src/pages/` 目录,每个 `index.js` 对应一个路由
|
|
||||||
- 路由路径是将目录路径转换为小写并用 `/` 连接
|
|
||||||
- 带参数的路由(如 `/View/:id`)需在目录中创建对应层级
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. 菜单配置
|
|
||||||
|
|
||||||
侧边栏菜单定义在 `src/pages/Container/Layout/menuConfig.js` 中。
|
|
||||||
|
|
||||||
### 4.1 菜单数据结构
|
|
||||||
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
key: "/certificate/container/<实际路由>", // 必须与文件目录对应的路由完全一致
|
|
||||||
label: "菜单显示名称",
|
|
||||||
icon: <SomeIcon />, // Ant Design 图标组件
|
|
||||||
children: [...] // 可选,子菜单项
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.2 当前菜单结构
|
|
||||||
|
|
||||||
```
|
|
||||||
📁 监管端 (Supervision)
|
|
||||||
├── 📄 企业证照 (EnterpriseLicense)
|
|
||||||
│ ├── 企业证照管理
|
|
||||||
│ ├── 分公司统计
|
|
||||||
│ └── 干系人统计
|
|
||||||
└── 📄 人员证照 (PersonnelLicense)
|
|
||||||
├── 负责人
|
|
||||||
├── 安全管理员
|
|
||||||
├── 特种设备
|
|
||||||
├── 特种作业人员
|
|
||||||
├── 分公司人员统计
|
|
||||||
└── 干系人人员统计
|
|
||||||
|
|
||||||
📁 分公司端 (BranchCompany)
|
|
||||||
└── 📄 企业证照 (EnterpriseLicense)
|
|
||||||
├── 企业证照管理
|
|
||||||
└── 📄 人员证照 (PersonnelLicense)
|
|
||||||
├── 负责人
|
|
||||||
├── 安全管理员
|
|
||||||
├── 特种设备
|
|
||||||
└── 特种作业人员
|
|
||||||
|
|
||||||
📁 干系人端 (Stakeholder)
|
|
||||||
└── 📄 企业证照 (EnterpriseLicense)
|
|
||||||
├── 企业证照管理
|
|
||||||
└── 📄 人员证照 (PersonnelLicense)
|
|
||||||
├── 负责人
|
|
||||||
├── 安全管理员
|
|
||||||
├── 特种设备
|
|
||||||
└── 特种作业人员
|
|
||||||
|
|
||||||
📁 测试页面 (Test)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.3 菜单配置注意事项
|
|
||||||
|
|
||||||
> **关键规则**:菜单的 `key` 必须与文件系统的实际目录层级完全一致,否则会出现"页面不存在"。
|
|
||||||
|
|
||||||
以"干系人端 → 负责人"为例:
|
|
||||||
|
|
||||||
- **文件位置**:`Stakeholder/EnterpriseLicense/PersonnelLicense/PersonInCharge/List/index.js`
|
|
||||||
- **正确路径**:`/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense/PersonInCharge/List`
|
|
||||||
- **错误路径**(缺少 `EnterpriseLicense` 层级):`/certificate/container/Stakeholder/PersonnelLicense/PersonInCharge/List`
|
|
||||||
|
|
||||||
### 4.4 工具函数
|
|
||||||
|
|
||||||
`menuConfig.js` 同时导出以下辅助函数:
|
|
||||||
|
|
||||||
| 函数 | 参数 | 返回值 | 说明 |
|
|
||||||
|------|------|--------|------|
|
|
||||||
| `flattenMenu(items)` | 菜单树 | 扁平数组 | 将树形菜单拍平 |
|
|
||||||
| `findMenuPath(path)` | 当前路由 | 菜单项数组 | 从根到叶子节点的面包屑路径 |
|
|
||||||
| `getPageLabel(path)` | 当前路由 | 字符串 | 获取页面标签名 |
|
|
||||||
| `getOpenKeys(path)` | 当前路由 | 路径数组 | 默认展开的菜单项 |
|
|
||||||
| `getSelectedKeys(path)` | 当前路由 | 路径数组 | 默认选中的菜单项 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. 页面开发流程
|
|
||||||
|
|
||||||
### 5.1 新增业务页面
|
|
||||||
|
|
||||||
以新增"监管端 → 人员证照 → 新增功能"为例:
|
|
||||||
|
|
||||||
**步骤 1:创建目录结构**
|
|
||||||
|
|
||||||
```
|
|
||||||
src/pages/Container/Supervision/PersonnelLicense/NewFeature/
|
|
||||||
├── index.js # 容器组件
|
|
||||||
├── List/
|
|
||||||
│ └── index.js # 列表页
|
|
||||||
└── View/
|
|
||||||
└── index.js # 详情页
|
|
||||||
```
|
|
||||||
|
|
||||||
**步骤 2:编写容器组件**
|
|
||||||
|
|
||||||
`src/pages/Container/Supervision/PersonnelLicense/NewFeature/index.js`:
|
|
||||||
```js
|
|
||||||
function NewFeature(props) {
|
|
||||||
return <div>{props.children}</div>;
|
|
||||||
}
|
|
||||||
export default NewFeature;
|
|
||||||
```
|
|
||||||
|
|
||||||
**步骤 3:编写列表页面**
|
|
||||||
|
|
||||||
`src/pages/Container/Supervision/PersonnelLicense/NewFeature/List/index.js`:
|
|
||||||
```js
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>新功能列表</h1>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(List);
|
|
||||||
```
|
|
||||||
|
|
||||||
**步骤 4:添加菜单配置**
|
|
||||||
|
|
||||||
在 `src/pages/Container/Layout/menuConfig.js` 中添加:
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense",
|
|
||||||
label: "人员证照",
|
|
||||||
icon: <TeamOutlined />,
|
|
||||||
children: [
|
|
||||||
// ... 已有菜单项
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/NewFeature/List",
|
|
||||||
label: "新功能",
|
|
||||||
icon: <SomeIcon />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.2 新增测试页面(独立于业务)
|
|
||||||
|
|
||||||
在 `src/pages/Container/` 下创建目录,并在菜单中添加即可:
|
|
||||||
|
|
||||||
```
|
|
||||||
src/pages/Container/MyDebug/
|
|
||||||
└── index.js
|
|
||||||
```
|
|
||||||
|
|
||||||
菜单:
|
|
||||||
```js
|
|
||||||
{
|
|
||||||
key: "/certificate/container/MyDebug",
|
|
||||||
label: "调试页面",
|
|
||||||
icon: <ExperimentOutlined />,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.3 验证路径是否正确
|
|
||||||
|
|
||||||
启动项目后,通过以下方式验证:
|
|
||||||
|
|
||||||
1. 在浏览器直接访问完整 URL
|
|
||||||
2. 从侧边栏菜单点击导航
|
|
||||||
3. 检查开发者工具 Network 面板,404 表示路径不匹配
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. API 接口声明
|
|
||||||
|
|
||||||
### 6.1 接口定义位置
|
|
||||||
|
|
||||||
API 接口声明在 `src/api/` 目录下,按模块划分:
|
|
||||||
|
|
||||||
```
|
|
||||||
src/api/
|
|
||||||
├── userCertificate/index.js # 人员证书接口
|
|
||||||
├── corpCertificate/index.js # 企业证书接口
|
|
||||||
├── courseware/index.js # 课件接口
|
|
||||||
└── global/index.js # 全局接口
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6.2 declareRequest 语法
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
// 格式:declareRequest(loadingKey, "HttpMethod > 接口路径")
|
|
||||||
export const listApi = declareRequest(
|
|
||||||
"namespaceLoading", // loading 状态 key
|
|
||||||
"Post > @/certificate/userCertificate/list", // POST + 相对路径(带 @)
|
|
||||||
);
|
|
||||||
|
|
||||||
export const getApi = declareRequest(
|
|
||||||
"namespaceLoading",
|
|
||||||
"Get > /certificate/userCertificate/getInfoById/{id}", // GET + 绝对路径
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
**语法规则:**
|
|
||||||
|
|
||||||
| 符号 | 说明 | 示例 |
|
|
||||||
|------|------|------|
|
|
||||||
| `@/` | 相对路径,使用 `jjb.config.js` 中配置的 `API_HOST` | `Post > @/certificate/xxx/list` |
|
|
||||||
| `/` | 绝对路径 | `Get > /config/dict-trees/list` |
|
|
||||||
| `{param}` | 路径参数 | `/certificate/xxx/delete/{id}` |
|
|
||||||
| `Post >` | POST 请求 | — |
|
|
||||||
| `Get >` | GET 请求 | — |
|
|
||||||
| `Put >` | PUT 请求 | — |
|
|
||||||
| `Delete >` | DELETE 请求 | — |
|
|
||||||
|
|
||||||
### 6.3 在组件中使用 API
|
|
||||||
|
|
||||||
API 通过 DVA 的 `dispatch` 和 `Connect` 来调用。`declareRequest` 会自动生成对应的 dva effect:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List({ dispatch, userCertificate }) {
|
|
||||||
const fetchData = () => {
|
|
||||||
dispatch({
|
|
||||||
type: `${NS_USER_CERTIFICATE}/userCertificateList`, // namespace/接口名
|
|
||||||
payload: { page: 1, size: 10 },
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return <div>{/* ... */}</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(List);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. 状态管理(DVA)
|
|
||||||
|
|
||||||
### 7.1 Namespace 定义
|
|
||||||
|
|
||||||
`src/enumerate/namespace/index.js` 中定义了所有 DVA namespace:
|
|
||||||
|
|
||||||
```js
|
|
||||||
export const NS_GLOBAL = defineNamespace("global");
|
|
||||||
export const NS_PERSNONEL_CERTFICATE = defineNamespace("personnelCertificate");
|
|
||||||
export const NS_CORP_CERTIFICATE = defineNamespace("corpCertificate");
|
|
||||||
export const NS_USER_CERTIFICATE = defineNamespace("userCertificate");
|
|
||||||
export const NS_COURSEWARE = defineNamespace("courseware");
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.2 Connect 高阶组件
|
|
||||||
|
|
||||||
```js
|
|
||||||
Connect([NS_USER_CERTIFICATE], true)(MyComponent)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 第一个参数:需要连接的 namespace 数组
|
|
||||||
- 第二个参数:是否在组件挂载时自动加载数据(`true` 表示自动触发 `load` effect)
|
|
||||||
|
|
||||||
### 7.3 数据流向
|
|
||||||
|
|
||||||
```
|
|
||||||
dispatch(action) → DVA Effect → declareRequest → HTTP API → reducer → state 更新 → 组件重渲染
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7.4 本地开发时的限制
|
|
||||||
|
|
||||||
本地独立运行时(非底座环境),DVA 状态管理正常可用,但 `declareRequest` 发起的 HTTP 请求会因缺少认证 Token 而返回 **401**。详见 [§10 已知问题](#10-已知问题与注意事项)。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. 共享组件
|
|
||||||
|
|
||||||
业务组件位于 `src/components/` 目录下,目前包括:
|
|
||||||
|
|
||||||
```
|
|
||||||
src/components/
|
|
||||||
├── PersonInChargeInfo/ # 负责人详情组件
|
|
||||||
├── PersonInChargeList/ # 负责人列表组件(含搜索、分页、CRUD)
|
|
||||||
├── SpecialCertificateInfo/ # 特种证书详情组件
|
|
||||||
└── SpecialCertificateList/ # 特种证书列表组件
|
|
||||||
```
|
|
||||||
|
|
||||||
组件通过 `@/components/xxx` 或别名 `~/components/xxx` 引入:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.1 组件参数传递
|
|
||||||
|
|
||||||
列表组件通过 `props` 接收业务参数:
|
|
||||||
|
|
||||||
```js
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props} // dva props 透传
|
|
||||||
certificatePhotoType={161} // 证照照片类型
|
|
||||||
personnelType="zyfzr" // 人员类型标识
|
|
||||||
permissionAdd="gfd-xxx-add" // 新增权限码
|
|
||||||
permissionEdit="gfd-xxx-edit" // 编辑权限码
|
|
||||||
permissionView="gfd-xxx-info" // 查看权限码
|
|
||||||
permissionDel="gfd-xxx-del" // 删除权限码
|
|
||||||
dictionaryType="zyfzrgwmc0000" // 字典类型
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. 本地模拟布局
|
|
||||||
|
|
||||||
### 9.1 工作原理
|
|
||||||
|
|
||||||
`src/pages/Container/index.js` 中的 `AppMiddle` 组件检测运行环境:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function AppMiddle(props) {
|
|
||||||
const content = process.env.NODE_ENV === "development" && !window.__POWERED_BY_QIANKUN__
|
|
||||||
? <SimulatedLayout>{props.children}</SimulatedLayout>
|
|
||||||
: props.children;
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **本地开发**(`development` + 非 qiankun):使用 `SimulatedLayout` 包裹内容,提供模拟的侧边栏、面包屑和标签页
|
|
||||||
- **底座环境**:由底座平台提供真实的布局
|
|
||||||
|
|
||||||
### 9.2 SimulatedLayout 功能
|
|
||||||
|
|
||||||
`src/pages/Container/Layout/index.jsx` 提供:
|
|
||||||
|
|
||||||
| 功能 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| 侧边栏 | 使用 `menuConfig.js` 的菜单数据渲染,支持折叠 |
|
|
||||||
| 面包屑 | 根据当前路径自动计算导航路径 |
|
|
||||||
| 多标签页 | 支持打开多个页面标签,右键关闭操作 |
|
|
||||||
| 标签持久化 | 使用 sessionStorage 保存标签状态 |
|
|
||||||
| 主题适配 | 通过 `window.base?.themeConfig` 支持底座主题切换 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 10. 已知问题与注意事项
|
|
||||||
|
|
||||||
### 10.1 API 401 错误
|
|
||||||
|
|
||||||
**现象**:本地启动后,点击侧边栏菜单(除 Test 页面外),控制台报 401 错误。
|
|
||||||
|
|
||||||
**原因**:本项目是 qiankun 微前端子应用,API 请求需要的认证 Token 由 GBS 底座注入。本地独立运行时没有底座,也就没有 Token,所有 API 调用被拒绝。
|
|
||||||
|
|
||||||
**处理方式**:
|
|
||||||
- **纯前端调试**:使用 Test 页面(`/certificate/container/Test`),该页面不发起任何 API 请求
|
|
||||||
- **完整功能调试**:在 GBS 底座环境中打开应用
|
|
||||||
|
|
||||||
### 10.2 路由路径与菜单 key 必须匹配
|
|
||||||
|
|
||||||
菜单的 `key` 值必须和文件目录层级完全一致。错误示例见 [§4.3 菜单配置注意事项](#43-菜单配置注意事项)。
|
|
||||||
|
|
||||||
### 10.3 重命名项目目录后需重新安装依赖
|
|
||||||
|
|
||||||
由于 pnpm 使用基于绝对路径的符号链接管理 `node_modules`,重命名项目根目录后需要:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Remove-Item -Recurse -Force node_modules
|
|
||||||
pnpm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### 10.4 权限控制
|
|
||||||
|
|
||||||
页面使用 `@cqsjjb/jjb-common-decorator/permission` 的 `Permission` 装饰器控制访问:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
```
|
|
||||||
|
|
||||||
权限码由底座平台管理,本地开发时权限校验可能不生效。
|
|
||||||
|
|
||||||
### 10.5 pnpm overrides
|
|
||||||
|
|
||||||
`package.json` 中通过 `pnpm.overrides` 强制统一 React 等依赖版本,避免多副本冲突:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"pnpm": {
|
|
||||||
"overrides": {
|
|
||||||
"react": "$react",
|
|
||||||
"react-dom": "$react-dom"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 11. 目录结构参考
|
|
||||||
|
|
||||||
```
|
|
||||||
safety-eval-service-frontend/
|
|
||||||
├── public/
|
|
||||||
│ └── index.html # HTML 模板
|
|
||||||
├── src/
|
|
||||||
│ ├── main.js # 应用入口(setup + 生命周期导出)
|
|
||||||
│ ├── api/ # API 接口声明
|
|
||||||
│ │ ├── global/
|
|
||||||
│ │ ├── userCertificate/
|
|
||||||
│ │ ├── corpCertificate/
|
|
||||||
│ │ └── courseware/
|
|
||||||
│ ├── components/ # 共享业务组件
|
|
||||||
│ │ ├── PersonInChargeList/
|
|
||||||
│ │ ├── PersonInChargeInfo/
|
|
||||||
│ │ ├── SpecialCertificateList/
|
|
||||||
│ │ └── SpecialCertificateInfo/
|
|
||||||
│ ├── enumerate/ # 枚举/常量定义
|
|
||||||
│ │ ├── namespace/ # DVA namespace
|
|
||||||
│ │ ├── context/ # React Context
|
|
||||||
│ │ └── constant/ # 常量
|
|
||||||
│ ├── pages/
|
|
||||||
│ │ └── Container/
|
|
||||||
│ │ ├── index.js # 容器入口(Antd 主题 + 布局切换)
|
|
||||||
│ │ ├── Entry/ # 底座入口页
|
|
||||||
│ │ ├── Layout/ # 本地模拟布局
|
|
||||||
│ │ │ ├── index.jsx # SimulatedLayout 组件
|
|
||||||
│ │ │ └── menuConfig.js # ★ 菜单配置
|
|
||||||
│ │ ├── Test/ # 测试页面(无 API 依赖)
|
|
||||||
│ │ ├── Supervision/ # 监管端
|
|
||||||
│ │ │ ├── EnterpriseLicense/
|
|
||||||
│ │ │ └── PersonnelLicense/
|
|
||||||
│ │ ├── BranchCompany/ # 分公司端
|
|
||||||
│ │ │ └── EnterpriseLicense/
|
|
||||||
│ │ └── Stakeholder/ # 干系人端
|
|
||||||
│ │ └── EnterpriseLicense/
|
|
||||||
│ ├── assets/ # 静态资源
|
|
||||||
│ └── utils/ # 工具函数
|
|
||||||
├── jjb.config.js # 项目配置(端口、API_HOST、主题等)
|
|
||||||
├── package.json
|
|
||||||
├── pnpm-lock.yaml
|
|
||||||
└── pnpm-workspace.yaml
|
|
||||||
```
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# 证照管理子应用 — 快速启动
|
|
||||||
|
|
||||||
## 环境要求
|
|
||||||
|
|
||||||
- Node.js >= 18
|
|
||||||
- pnpm >= 8
|
|
||||||
|
|
||||||
## 启动
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 安装依赖(首次或重命名项目目录后)
|
|
||||||
pnpm install
|
|
||||||
|
|
||||||
# 启动开发服务器
|
|
||||||
pnpm run serve:development
|
|
||||||
```
|
|
||||||
|
|
||||||
## 访问
|
|
||||||
|
|
||||||
| 地址 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `http://localhost:8081/certificate/container/` | 应用首页 |
|
|
||||||
| `http://localhost:8081/certificate/container/Test` | 测试页面(无 API 依赖,纯前端调试可用) |
|
|
||||||
|
|
||||||
## 常用命令
|
|
||||||
|
|
||||||
| 命令 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| `pnpm run serve:development` | 开发环境启动(推荐) |
|
|
||||||
| `pnpm run serve:production` | 生产环境配置启动 |
|
|
||||||
| `pnpm run build:development` | 开发环境构建 |
|
|
||||||
| `pnpm run build:production` | 生产环境构建 |
|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
- React 18 + Ant Design 5.x
|
|
||||||
- @cqsjjb/jjb-dva-runtime(GBS 底座 DVA 运行时)
|
|
||||||
- rspack 构建 / pnpm 包管理
|
|
||||||
- qiankun 微前端子应用
|
|
||||||
|
|
||||||
## 重要提示
|
|
||||||
|
|
||||||
- 本项目为 GBS 底座微前端子应用,独立启动时有内置模拟布局
|
|
||||||
- 本地独立运行时 API 调用会返回 401(缺少底座注入的认证 Token)
|
|
||||||
- 仅 Test 页面可在本地无底座环境下正常访问
|
|
||||||
- 重命名项目目录后需 `pnpm install` 重建 node_modules 符号链接
|
|
||||||
- 完整开发指南请参考 [dev-guide.md](./dev-guide.md)
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
import antfu from "@antfu/eslint-config";
|
|
||||||
|
|
||||||
export default antfu({
|
|
||||||
formatters: {
|
|
||||||
html: false,
|
|
||||||
css: true,
|
|
||||||
},
|
|
||||||
test: false,
|
|
||||||
typescript: true,
|
|
||||||
react: true,
|
|
||||||
vue: false,
|
|
||||||
markdown: false,
|
|
||||||
stylistic: {
|
|
||||||
semi: true,
|
|
||||||
quotes: "double",
|
|
||||||
},
|
|
||||||
overrides: {
|
|
||||||
react: {
|
|
||||||
"react/no-comment-textnodes": "off",
|
|
||||||
"react-hooks-extra/no-unnecessary-use-prefix": "off",
|
|
||||||
"react-hooks-extra/prefer-use-state-lazy-initialization": "off",
|
|
||||||
"react-hooks/exhaustive-deps": "off",
|
|
||||||
},
|
|
||||||
javascript: {
|
|
||||||
"no-console": process.env.NODE_ENV === "production" ? "error" : "warn",
|
|
||||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "warn",
|
|
||||||
"no-alert": process.env.NODE_ENV === "production" ? "error" : "warn",
|
|
||||||
"no-restricted-syntax": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
selector: "VariableDeclarator[id.name='pd']",
|
|
||||||
message: "不允许使用 pd,请改用有语义化的变量名",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
selector: "ObjectExpression > Property[key.name='pd']",
|
|
||||||
message: "不允许使用 pd,请改用有语义化的变量名",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-unused-vars": ["error", { varsIgnorePattern: "^React$" }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
"antfu/top-level-function": "off",
|
|
||||||
"node/prefer-global/process": "off",
|
|
||||||
"dot-notation": "off",
|
|
||||||
"linebreak-style": ["off", "windows"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
23
jjb.babel.js
23
jjb.babel.js
|
|
@ -1,23 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
compact: false,
|
|
||||||
// 插件
|
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
"@babel/plugin-proposal-decorators",
|
|
||||||
{
|
|
||||||
legacy: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
// 预设
|
|
||||||
presets: [
|
|
||||||
["@babel/preset-env", {
|
|
||||||
targets: {
|
|
||||||
browsers: ["ie >= 10"],
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
["@babel/preset-react", {
|
|
||||||
runtime: "automatic",
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
// 应用后端git地址,部署上线需要
|
|
||||||
javaGit: "<git-url>",
|
|
||||||
// 应用后端仓库名称,部署上线需要
|
|
||||||
javaGitName: "<git-name>",
|
|
||||||
// 环境配置
|
|
||||||
environment: {
|
|
||||||
development: {
|
|
||||||
// 应用后端分支名称,部署上线需要
|
|
||||||
javaGitBranch: "<branch-name>",
|
|
||||||
// 接口服务地址
|
|
||||||
// API_HOST: "http://192.168.20.100:30140",
|
|
||||||
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
|
||||||
},
|
|
||||||
production: {
|
|
||||||
// 应用后端分支名称,部署上线需要
|
|
||||||
javaGitBranch: "<branch-name>",
|
|
||||||
// 接口服务地址
|
|
||||||
API_HOST: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 应用唯一标识符
|
|
||||||
appIdentifier: "certificate",
|
|
||||||
// 应用上下文注入全局变量
|
|
||||||
contextInject: {
|
|
||||||
// 应用Key
|
|
||||||
appKey: "",
|
|
||||||
// fileUrl: "http://192.168.20.240:9787/mnt",
|
|
||||||
// fileUrl: "https://jpfz.qhdsafety.com/gbsFileTest/",
|
|
||||||
fileUrl: "https://skqhdg.porthebei.com:9004/file/uploadFiles2/",
|
|
||||||
},
|
|
||||||
// public/index.html注入全局变量
|
|
||||||
windowInject: {
|
|
||||||
// 应用标题
|
|
||||||
title: "微应用模板",
|
|
||||||
// 注入css链接集合
|
|
||||||
links: [],
|
|
||||||
element: {
|
|
||||||
root: {
|
|
||||||
// 挂载DOM元素ID
|
|
||||||
id: "root",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 注入js链接集合
|
|
||||||
scripts: [],
|
|
||||||
},
|
|
||||||
// 开发服务
|
|
||||||
server: {
|
|
||||||
// 监听端口号
|
|
||||||
port: "8081",
|
|
||||||
// 服务地址
|
|
||||||
host: "127.0.0.1",
|
|
||||||
// 是否自动打开浏览器
|
|
||||||
open: true,
|
|
||||||
},
|
|
||||||
// 框架
|
|
||||||
framework: {
|
|
||||||
// ant-design
|
|
||||||
antd: {
|
|
||||||
// 全局antd-class-name前缀
|
|
||||||
"ant-prefix": "micro-temp",
|
|
||||||
// 全局字体
|
|
||||||
"fontFamily": "PingFangSC-Regular",
|
|
||||||
// 全局主题色
|
|
||||||
"colorPrimary": "#1677ff",
|
|
||||||
// 全局圆角
|
|
||||||
"borderRadius": 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// webpack
|
|
||||||
webpackConfig: {
|
|
||||||
// 单页面插件
|
|
||||||
htmlWebpackPluginOption: {
|
|
||||||
// 自动注入编译后的文件到public/index.html中
|
|
||||||
inject: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": "src",
|
|
||||||
"paths": {
|
|
||||||
"~/*": ["*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
||||||
63
package.json
63
package.json
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"name": "micro-app",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"description": "建教帮微应用模板",
|
|
||||||
"author": "JJB",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"serve": "node node_modules/@cqsjjb/scripts/rspack.dev.server.js",
|
|
||||||
"build": "node node_modules/@cqsjjb/scripts/rspack.build.js",
|
|
||||||
"push": "jjb-cmd push java production",
|
|
||||||
"clean-cache": "rimraf node_modules/.cache/webpack",
|
|
||||||
"serve:development": "cross-env NODE_ENV=development npm run serve",
|
|
||||||
"serve:production": "cross-env NODE_ENV=production npm run serve",
|
|
||||||
"build:development": "cross-env NODE_ENV=development npm run build",
|
|
||||||
"build:production": "cross-env NODE_ENV=production npm run build",
|
|
||||||
"code-optimization": "node node_modules/@cqsjjb/scripts/code-optimization.js",
|
|
||||||
"lint": "eslint --ext .js,.jsx,.tsx --fix src"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@ant-design/icons": "^5.0.0",
|
|
||||||
"@ant-design/pro-components": "^2.8.10",
|
|
||||||
"@cqsjjb/jjb-common-decorator": "latest",
|
|
||||||
"@cqsjjb/jjb-common-lib": "latest",
|
|
||||||
"@cqsjjb/jjb-dva-runtime": "latest",
|
|
||||||
"@cqsjjb/jjb-react-admin-component": "latest",
|
|
||||||
"@rc-component/motion": "^1.0.0",
|
|
||||||
"@rc-component/util": "^1.11.1",
|
|
||||||
"ahooks": "^3.9.5",
|
|
||||||
"antd": "^5.11.2",
|
|
||||||
"dayjs": "^1.11.7",
|
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"qrcode.react": "^4.2.0",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"zy-react-library": "^1.2.3"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@antfu/eslint-config": "^5.4.1",
|
|
||||||
"@babel/plugin-proposal-decorators": "^7.19.3",
|
|
||||||
"@cqsjjb/scripts": "latest",
|
|
||||||
"@eslint-react/eslint-plugin": "^2.2.2",
|
|
||||||
"babel-loader": "^9.1.3",
|
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"css-loader": "^6.8.1",
|
|
||||||
"eslint": "^9.37.0",
|
|
||||||
"eslint-plugin-format": "^1.0.2",
|
|
||||||
"eslint-plugin-react-hooks": "^7.0.0",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.23",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"less-loader": "^11.1.3",
|
|
||||||
"style-loader": "^3.3.3",
|
|
||||||
"typescript": "^5.9.3"
|
|
||||||
},
|
|
||||||
"pnpm": {
|
|
||||||
"overrides": {
|
|
||||||
"history": "^4.10.1",
|
|
||||||
"path-to-regexp": "^1.9.0",
|
|
||||||
"react": "$react",
|
|
||||||
"react-dom": "$react-dom"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11822
pnpm-lock.yaml
11822
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1,3 +0,0 @@
|
||||||
allowBuilds:
|
|
||||||
es5-ext: false
|
|
||||||
zy-react-library: false
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<!--BEGIN-->
|
|
||||||
<!--<% var { env: $env, process: $process, mode: $mode, builtInfo: $builtInfo, links: $links, redirectLogin: $redirectLogin, framework: $framework, scripts: $scripts, element: $element } = htmlWebpackPlugin.options %>-->
|
|
||||||
<!--<% var { appKey: $appKey, antd: $antd, basename: $basename, API_HOST: $API_HOST } = $process %>-->
|
|
||||||
<!--<% var { ['ant-prefix']: $antPrefix, fontFamily: $fontFamily, colorPrimary: $colorPrimary, borderRadius: $borderRadius } = $antd %>-->
|
|
||||||
<!--NED-->
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh">
|
|
||||||
<head data-built-info="<%= $builtInfo %>">
|
|
||||||
<meta charset="UTF-8"/>
|
|
||||||
<meta name="renderer" content="webkit"/>
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1"/>
|
|
||||||
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,viewport-fit=cover">
|
|
||||||
<% for (const item of $links) { %>
|
|
||||||
<link type="text/css" rel="stylesheet" href="<%= item %>"></link>
|
|
||||||
<% } %>
|
|
||||||
<title>--</title>
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
const APP_ENV = {
|
|
||||||
antd: {
|
|
||||||
'ant-prefix': '<%= $antPrefix %>',
|
|
||||||
fontFamily: '<%= $fontFamily %>',
|
|
||||||
colorPrimary: '<%= $colorPrimary %>',
|
|
||||||
borderRadius: parseInt('<%= $borderRadius %>')
|
|
||||||
},
|
|
||||||
appKey: '<%= $appKey %>',
|
|
||||||
basename: '<%= $basename %>',
|
|
||||||
API_HOST: '<%= $API_HOST %>'
|
|
||||||
};
|
|
||||||
APP_ENV.API_HOST = sessionStorage.API_HOST || APP_ENV.API_HOST || window.location.origin;
|
|
||||||
window.process = {
|
|
||||||
env: { app: APP_ENV },
|
|
||||||
NODE_ENV: '<%= $mode %>'
|
|
||||||
};
|
|
||||||
window.__JJB_ENVIRONMENT__ = {
|
|
||||||
API_HOST: APP_ENV.API_HOST,
|
|
||||||
redirect: '<%= $redirectLogin %>',
|
|
||||||
FRAMEWORK: APP_ENV.antd
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
<!-- SCRIPTS -->
|
|
||||||
<% for (const item of $scripts) { %>
|
|
||||||
<script src="<%= item %>" type="text/javascript"></script>
|
|
||||||
<% } %>
|
|
||||||
</head>
|
|
||||||
<body >
|
|
||||||
<!-- NOSCRIPT -->
|
|
||||||
<noscript>此网页需要开启JavaScript功能。</noscript>
|
|
||||||
<!-- MAIN -->
|
|
||||||
<% const { root } = $element; %>
|
|
||||||
<div id="<%= root.id %>" style="width: 100%; height: 100%; position: relative;overflow-y: auto"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
export const corpCertificateList = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Post > @/certificate/corpCertificate/list",
|
|
||||||
);
|
|
||||||
|
|
||||||
export const corpCertificateInfo = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Get > /certificate/corpCertificate/getInfoById?id={id}",
|
|
||||||
);
|
|
||||||
export const corpCertificateAdd = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Post > @/certificate/corpCertificate/save",
|
|
||||||
);
|
|
||||||
export const corpCertificateEdit = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Put > @/certificate/corpCertificate/edit",
|
|
||||||
);
|
|
||||||
// 股份端查看分公司-相关方证照统计信息分页
|
|
||||||
export const corpCertificateStatPage = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Post > @/certificate/corpCertificate/statPage",
|
|
||||||
);
|
|
||||||
export const corpCertificateRemove = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Put > @/certificate/corpCertificate/remove?id={id}",
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取字典
|
|
||||||
export const dictValuesData = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Get > /config/dict-trees/list/by/dictValues",
|
|
||||||
);
|
|
||||||
|
|
||||||
export const corpCertificateIsExistCertNo = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Get > /certificate/corpCertificate/isExistCertNo",
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
export const identifyPartList = declareRequest(
|
|
||||||
"coursewareLoading",
|
|
||||||
"Post > @/risk/busIdentifyPart/list",
|
|
||||||
);
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
export {};
|
|
||||||
|
|
||||||
// export const riskList = declareRequest(
|
|
||||||
// "loading",
|
|
||||||
// "Post > @/xxx",
|
|
||||||
// "dataSource: [] | res.data || [] & total: 0 | res.totalCount || 0 & pageIndex: 1 | res.pageIndex || 1 & pageSize: 10 | res.pageSize || 10",
|
|
||||||
// );
|
|
||||||
// export const riskDelete = declareRequest(
|
|
||||||
// "loading",
|
|
||||||
// "Delete > @/xxx/{id}",
|
|
||||||
// );
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
export const userCertificateList = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Post > @/certificate/userCertificate/list",
|
|
||||||
);
|
|
||||||
|
|
||||||
export const userCertificateInfo = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Get > /certificate/userCertificate/getInfoById/{id}",
|
|
||||||
);
|
|
||||||
export const userCertificateAdd = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Post > @/certificate/userCertificate/save",
|
|
||||||
);
|
|
||||||
export const userCertificateEdit = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Put > @/certificate/userCertificate/edit",
|
|
||||||
);
|
|
||||||
// 股份端查看分公司-相关方证照统计信息分页
|
|
||||||
export const userCertificateStatPage = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Post > @/certificate/userCertificate/corpCertificateStatPage",
|
|
||||||
);
|
|
||||||
export const userCertificateRemove = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Delete > @/certificate/userCertificate/delete/{id}",
|
|
||||||
);
|
|
||||||
|
|
||||||
// 获取字典
|
|
||||||
export const dictValuesData = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Get > /config/dict-trees/list/by/dictValues",
|
|
||||||
);
|
|
||||||
|
|
||||||
export const userCertificateIsExistCertNo = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
"Get > /certificate/userCertificate/isExistCertNo",
|
|
||||||
);
|
|
||||||
export const projectHasUser = declareRequest(
|
|
||||||
"userCertificateLoading",
|
|
||||||
`Get > /xgfManager/project/projectHasUser`,
|
|
||||||
);
|
|
||||||
// 获取人员 (带权限)
|
|
||||||
export const getUserlistAll = declareRequest(
|
|
||||||
"corpCertificateLoading",
|
|
||||||
"Post > @/certificate/user/listAll",
|
|
||||||
);
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/* 打印时:隐藏所有内容 */
|
|
||||||
@media print {
|
|
||||||
body * {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 只显示要打印的 div 及其子元素 */
|
|
||||||
#print-invoice,
|
|
||||||
#print-invoice * {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
#print-invoice {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
padding: 1cm;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 12pt;
|
|
||||||
font-family: 'SimSun', '宋体', serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 隐藏弹窗中的操作按钮(双重保险) */
|
|
||||||
.no-print {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 屏幕上正常显示 */
|
|
||||||
@media screen {
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
width: 80%;
|
|
||||||
max-width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions {
|
|
||||||
margin-top: 20px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions button {
|
|
||||||
margin-left: 10px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Descriptions, Divider } from "antd";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PreviewImg from "zy-react-library/components/PreviewImg";
|
|
||||||
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
|
|
||||||
import useGetFile from "zy-react-library/hooks/useGetFile";
|
|
||||||
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
const JOB_STATUS = {
|
|
||||||
1: "在职",
|
|
||||||
0: "离职",
|
|
||||||
2: "信息变更中",
|
|
||||||
3: "未入职",
|
|
||||||
4: "实习生",
|
|
||||||
5: "实习结束",
|
|
||||||
6: "退休",
|
|
||||||
7: "劳务派遣",
|
|
||||||
8: "劳务派遣结束",
|
|
||||||
11: "入职待审核",
|
|
||||||
10: "离职待审核",
|
|
||||||
};
|
|
||||||
function PersonInChargeInfo({ props, certificatePhotoType }) {
|
|
||||||
const [info, setInfo] = useState({});
|
|
||||||
const queryParams = useGetUrlQuery();
|
|
||||||
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(queryParams);
|
|
||||||
const fetchData = async () => {
|
|
||||||
const res = await props.userCertificateInfo({
|
|
||||||
id: queryParams["id"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const licenseFile = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[certificatePhotoType],
|
|
||||||
eqForeignKey: res.data.userCertificateId,
|
|
||||||
});
|
|
||||||
|
|
||||||
res.data.licenseFile = licenseFile;
|
|
||||||
|
|
||||||
setInfo(res.data || {});
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<Page headerTitle="证书信息查看">
|
|
||||||
<div>
|
|
||||||
<Divider orientation="left">人员信息</Divider>
|
|
||||||
<Descriptions
|
|
||||||
bordered
|
|
||||||
loding={getFileLoading}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: "姓名",
|
|
||||||
children: info.name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "企业名称",
|
|
||||||
children: info.corpinfoName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "部门名称",
|
|
||||||
children: info.departmentName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "岗位名称",
|
|
||||||
children: info.userPostName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "就职状态",
|
|
||||||
children: <div>{JOB_STATUS[info.employmentStatus]}</div>,
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
column={2}
|
|
||||||
labelStyle={{
|
|
||||||
width: 200,
|
|
||||||
}}
|
|
||||||
contentStyle={{
|
|
||||||
width: 500,
|
|
||||||
}}
|
|
||||||
|
|
||||||
/>
|
|
||||||
<Divider orientation="left">证书信息</Divider>
|
|
||||||
<Descriptions
|
|
||||||
bordered
|
|
||||||
loding={getFileLoading}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: "证书名称",
|
|
||||||
children: info.certificateName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证书编号",
|
|
||||||
children: info.certificateCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "岗位名称",
|
|
||||||
children: info.postName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "发证机构",
|
|
||||||
children: info.issuingAuthority,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "发证日期",
|
|
||||||
children: info.dateIssue,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
label: "有效期至",
|
|
||||||
children: <div>{`${info.certificateDateStart ?? ""} - ${info.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证照照片",
|
|
||||||
children: <PreviewImg files={info.licenseFile} />,
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
column={2}
|
|
||||||
labelStyle={{
|
|
||||||
width: 200,
|
|
||||||
}}
|
|
||||||
contentStyle={{
|
|
||||||
width: 500,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Page>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(PersonInChargeInfo);
|
|
||||||
|
|
@ -1,665 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, message, Modal, Space } from "antd";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
|
||||||
import AddIcon from "zy-react-library/components/Icon/AddIcon";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
|
|
||||||
import PersonnelSelect from "zy-react-library/components/Select/Personnel/Gwj";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
import TooltipPreviewImg from "zy-react-library/components/TooltipPreviewImg";
|
|
||||||
import Upload from "zy-react-library/components/Upload";
|
|
||||||
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
|
||||||
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
|
|
||||||
import useDeleteFile from "zy-react-library/hooks/useDeleteFile";
|
|
||||||
import useGetFile from "zy-react-library/hooks/useGetFile";
|
|
||||||
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
|
|
||||||
import useGetUserInfo from "zy-react-library/hooks/useGetUserInfo";
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import useUploadFile from "zy-react-library/hooks/useUploadFile";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
import { useDebounce } from "~/utils";
|
|
||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
|
|
||||||
const JOB_STATUS = {
|
|
||||||
1: "在职",
|
|
||||||
0: "离职",
|
|
||||||
2: "信息变更中",
|
|
||||||
3: "未入职",
|
|
||||||
4: "实习生",
|
|
||||||
5: "实习结束",
|
|
||||||
6: "退休",
|
|
||||||
7: "劳务派遣",
|
|
||||||
8: "劳务派遣结束",
|
|
||||||
11: "入职待审核",
|
|
||||||
10: "离职待审核",
|
|
||||||
};
|
|
||||||
|
|
||||||
function List({ props, certificatePhotoType, displayType, personnelType, permissionAdd, permissionEdit, permissionView, permissionDel, dictionaryType }) {
|
|
||||||
const [addModalOpen, setAddModalOpen] = useState(false);
|
|
||||||
const [currentId, setCurrentId] = useState("");
|
|
||||||
const queryParams = useGetUrlQuery();
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["userCertificateList"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
eqCorpinfoId: queryParams["corpinfoId"],
|
|
||||||
eqType: personnelType,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const onDelete = async (row) => {
|
|
||||||
props["projectHasUser"]({ eqUserId: row.userId }).then((res) => {
|
|
||||||
console.log(res);
|
|
||||||
if (res.data && res.data.length > 0) {
|
|
||||||
const arr = [];
|
|
||||||
const userArr = [];
|
|
||||||
|
|
||||||
res.data.forEach((item) => {
|
|
||||||
arr.push(item.projectName);
|
|
||||||
userArr.push(item.userName);
|
|
||||||
});
|
|
||||||
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
【
|
|
||||||
{[...new Set(userArr)].join(",")}
|
|
||||||
】有正在进行的项目,包含【
|
|
||||||
{
|
|
||||||
[...new Set(arr)].join(",")
|
|
||||||
}
|
|
||||||
】确定删除吗?
|
|
||||||
</div>
|
|
||||||
<div style={{ fontSize: 14, color: "red" }}>删除可能会对正在进行的项目造成异常状态,请谨慎操作。</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
onOk: () => {
|
|
||||||
props["userCertificateRemove"]({
|
|
||||||
id: row.id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: "确定删除吗?",
|
|
||||||
onOk: () => {
|
|
||||||
props["userCertificateRemove"]({
|
|
||||||
id: row.id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const [fileCache, setFileCache] = useState({});
|
|
||||||
const [loadingKeys, setLoadingKeys] = useState(new Set());
|
|
||||||
const pendingLoadIdsRef = useRef(new Set());
|
|
||||||
const requestQueueRef = useRef([]);
|
|
||||||
const activeRequestsRef = useRef(0);
|
|
||||||
const MAX_CONCURRENT_REQUESTS = 3; // 最大并发请求数
|
|
||||||
|
|
||||||
const processQueue = () => {
|
|
||||||
while (
|
|
||||||
requestQueueRef.current.length > 0
|
|
||||||
&& activeRequestsRef.current < MAX_CONCURRENT_REQUESTS
|
|
||||||
) {
|
|
||||||
const { id, resolve, reject } = requestQueueRef.current.shift();
|
|
||||||
activeRequestsRef.current++;
|
|
||||||
|
|
||||||
getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[certificatePhotoType],
|
|
||||||
eqForeignKey: id,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
setFileCache(prev => ({
|
|
||||||
...prev,
|
|
||||||
[id]: res || [],
|
|
||||||
}));
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("图片加载失败:", err);
|
|
||||||
reject(err);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
activeRequestsRef.current--;
|
|
||||||
setLoadingKeys((prev) => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(id);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
processQueue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadFileForRecord = (userQualificationinfoId) => {
|
|
||||||
if (!userQualificationinfoId)
|
|
||||||
return Promise.resolve();
|
|
||||||
if (fileCache[userQualificationinfoId])
|
|
||||||
return Promise.resolve();
|
|
||||||
if (loadingKeys.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
if (pendingLoadIdsRef.current.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
|
|
||||||
pendingLoadIdsRef.current.add(userQualificationinfoId);
|
|
||||||
setLoadingKeys(prev => new Set([...prev, userQualificationinfoId]));
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
requestQueueRef.current.push({ id: userQualificationinfoId, resolve, reject });
|
|
||||||
processQueue();
|
|
||||||
}).finally(() => {
|
|
||||||
pendingLoadIdsRef.current.delete(userQualificationinfoId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 清除伪类
|
|
||||||
useEffect(() => {
|
|
||||||
if (displayType === "View") {
|
|
||||||
const style = document.createElement("style");
|
|
||||||
style.innerHTML = `
|
|
||||||
.search-layout::after {
|
|
||||||
content: none !important;
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
// 清理函数,在组件卸载时移除样式
|
|
||||||
return () => {
|
|
||||||
document.head.removeChild(style);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 缓存数据变化时清空图片缓存
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
const currentIds = new Set(tableProps.dataSource.map(item => item.userCertificateId).filter(Boolean));
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = {};
|
|
||||||
Object.keys(prev).forEach((id) => {
|
|
||||||
if (currentIds.has(id)) {
|
|
||||||
newCache[id] = prev[id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
|
|
||||||
// 记录已经触发过加载的 ID,避免 render 重复触发
|
|
||||||
const triggeredLoadIdsRef = useRef(new Set());
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
tableProps.dataSource.forEach((record) => {
|
|
||||||
const id = record.userCertificateId;
|
|
||||||
if (id && !triggeredLoadIdsRef.current.has(id)) {
|
|
||||||
triggeredLoadIdsRef.current.add(id);
|
|
||||||
loadFileForRecord(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 组件卸载或数据源变化时重置
|
|
||||||
return () => {
|
|
||||||
triggeredLoadIdsRef.current.clear();
|
|
||||||
};
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "likeUserName",
|
|
||||||
label: "姓名",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "likePostName",
|
|
||||||
label: "岗位名称",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
loding={getFileLoading}
|
|
||||||
options={displayType !== "View"}
|
|
||||||
toolBarRender={() => (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
(displayType !== "View" && props.permission(permissionAdd))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<AddIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "姓名",
|
|
||||||
dataIndex: "name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书名称",
|
|
||||||
dataIndex: "certificateName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书编号",
|
|
||||||
dataIndex: "certificateCode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "岗位名称",
|
|
||||||
dataIndex: "postName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "有效期至",
|
|
||||||
dataIndex: "certificateNo",
|
|
||||||
width: 280,
|
|
||||||
render: (_, record) =>
|
|
||||||
<div>{`${record.certificateDateStart ?? ""} - ${record.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "就职状态",
|
|
||||||
dataIndex: "certificateNo",
|
|
||||||
render: (_, record) => (
|
|
||||||
<div>{JOB_STATUS[record.employmentStatus] || "-"}</div>
|
|
||||||
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "图片",
|
|
||||||
dataIndex: "name",
|
|
||||||
render: (_, record) => {
|
|
||||||
const id = record.userCertificateId;
|
|
||||||
const files = fileCache[id] || [];
|
|
||||||
|
|
||||||
if (!files.length)
|
|
||||||
return <span>无</span>;
|
|
||||||
return <TooltipPreviewImg files={files} />;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 200,
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
{
|
|
||||||
props.permission(permissionView)
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./View?id=${record.id}`)}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
(displayType !== "View" && props.permission(permissionEdit))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
setCurrentId(record.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
(displayType !== "View" && props.permission(permissionDel))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
type="link"
|
|
||||||
onClick={() => onDelete(record)}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{addModalOpen && (
|
|
||||||
<AddModal
|
|
||||||
open={addModalOpen}
|
|
||||||
loding={props.userCertificate.userCertificateLoading}
|
|
||||||
getData={getData}
|
|
||||||
currentId={currentId}
|
|
||||||
requestAdd={props["userCertificateAdd"]}
|
|
||||||
requestEdit={props["userCertificateEdit"]}
|
|
||||||
requestDetails={props["userCertificateInfo"]}
|
|
||||||
userCertificateIsExistCertNo={props["userCertificateIsExistCertNo"]}
|
|
||||||
getUserlistAll={props["getUserlistAll"]}
|
|
||||||
certificatePhotoType={certificatePhotoType}
|
|
||||||
personnelType={personnelType}
|
|
||||||
dictionaryType={dictionaryType}
|
|
||||||
onCancel={() => {
|
|
||||||
setAddModalOpen(false);
|
|
||||||
setCurrentId("");
|
|
||||||
}}
|
|
||||||
onSuccess={(userQualificationinfoId) => {
|
|
||||||
// 清除该记录的图片缓存,强制下次 render 时重新加载
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = { ...prev };
|
|
||||||
delete newCache[userQualificationinfoId];
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function AddModalComponent(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const [userQualificationinfoId, setUserQualificationinfoId] = useState("");
|
|
||||||
const [userObj, setUserObj] = useState({});
|
|
||||||
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
|
|
||||||
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
const { getUserInfo } = useGetUserInfo();
|
|
||||||
const [deleteCardImageFiles, setDeleteCardImageFiles] = useState([]);
|
|
||||||
const [CertificateCodeValue, setPertificateCodeValue] = useState(null);
|
|
||||||
const debouncedCertificateCodeValue = useDebounce(CertificateCodeValue, 100);
|
|
||||||
const [personnelData, setPersonnelData] = useState([]);
|
|
||||||
const [isSubmit, setIsSubmit] = useState(true);
|
|
||||||
const location = useLocation();
|
|
||||||
const getUserInfoFun = async () => {
|
|
||||||
const userInfo = await getUserInfo();
|
|
||||||
setUserObj(userInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUserlistFun = async () => {
|
|
||||||
props.getUserlistAll({menuPath:"/certificate"+location.pathname}).then(res => {
|
|
||||||
if(res.data) {
|
|
||||||
res.data.forEach(item => {
|
|
||||||
item.bianma=item.id;
|
|
||||||
})
|
|
||||||
setPersonnelData(res.data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.currentId) {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const { data } = await props.requestDetails({
|
|
||||||
id: props.currentId,
|
|
||||||
});
|
|
||||||
const certificateImgs = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
|
|
||||||
eqForeignKey: data.userCertificateId,
|
|
||||||
});
|
|
||||||
data.certificateDate = [data.certificateDateStart, data.certificateDateEnd];
|
|
||||||
data.certificateImgs = certificateImgs;
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setUserQualificationinfoId(data.userCertificateId);
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
getUserInfoFun();
|
|
||||||
getUserlistFun()
|
|
||||||
}, [props.currentId]);
|
|
||||||
const onCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
props.onCancel();
|
|
||||||
};
|
|
||||||
const onSubmit = async (values) => {
|
|
||||||
if (!isSubmit) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (values.certificateImgs.length !== 2) {
|
|
||||||
message.error("证照照片必须上传正反面两张");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxSizeInBytes = 10 * 1024 * 1024;
|
|
||||||
|
|
||||||
const isOverSize = values.certificateImgs.some(file => file.size > maxSizeInBytes);
|
|
||||||
|
|
||||||
if (isOverSize) {
|
|
||||||
message.error("选择的图片不能大于10MB");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await deleteFile({
|
|
||||||
single: false,
|
|
||||||
files: deleteCardImageFiles,
|
|
||||||
});
|
|
||||||
const { id } = await uploadFile({
|
|
||||||
single: false,
|
|
||||||
files: values.certificateImgs,
|
|
||||||
params: {
|
|
||||||
type: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
|
|
||||||
foreignKey: userQualificationinfoId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
values.certificateDateStart = values.certificateDate[0];
|
|
||||||
values.certificateDateEnd = values.certificateDate[1];
|
|
||||||
values.type = props.personnelType;
|
|
||||||
const personnelTypeMap = {
|
|
||||||
tezhongzuoye: "特种作业人员",
|
|
||||||
tzsbczry: "特种设备操作人员",
|
|
||||||
zyfzr: "主要负责人",
|
|
||||||
aqscglry: "安全生产管理人员",
|
|
||||||
};
|
|
||||||
|
|
||||||
values.typeName = personnelTypeMap[props.personnelType];
|
|
||||||
if (props.currentId) {
|
|
||||||
values.id = props.currentId;
|
|
||||||
values.userCertificateId = userQualificationinfoId;
|
|
||||||
await props.requestEdit(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
props.onSuccess(userQualificationinfoId);
|
|
||||||
message.success("编辑成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
values.userCertificateId = id;
|
|
||||||
await props.requestAdd(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
props.onSuccess(userQualificationinfoId);
|
|
||||||
message.success("新增成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 校验重复
|
|
||||||
useEffect(() => {
|
|
||||||
if (!debouncedCertificateCodeValue) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
props["userCertificateIsExistCertNo"]({
|
|
||||||
certNo: debouncedCertificateCodeValue,
|
|
||||||
id: props.currentId ?? "",
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
setIsSubmit(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setIsSubmit(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [debouncedCertificateCodeValue]);
|
|
||||||
const onValuesChange = (changedValues) => {
|
|
||||||
if ("certificateCode" in changedValues) {
|
|
||||||
setPertificateCodeValue(changedValues.certificateCode ?? "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={props.open}
|
|
||||||
maskClosable={false}
|
|
||||||
title={props.currentId ? "编辑" : "新增"}
|
|
||||||
width={800}
|
|
||||||
|
|
||||||
confirmLoading={
|
|
||||||
deleteFileLoading || uploadFileLoading || getFileLoading || props.loding
|
|
||||||
}
|
|
||||||
onOk={form.submit}
|
|
||||||
onCancel={onCancel}
|
|
||||||
>
|
|
||||||
<FormBuilder
|
|
||||||
form={form}
|
|
||||||
onValuesChange={onValuesChange}
|
|
||||||
span={24}
|
|
||||||
values={{
|
|
||||||
securityFlag: 0,
|
|
||||||
}}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "userId",
|
|
||||||
label: "选择人员",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
|
||||||
items:personnelData
|
|
||||||
},
|
|
||||||
{ name: "userName", label: "人员名称", onlyForLabel: true },
|
|
||||||
{
|
|
||||||
name: "certificateName",
|
|
||||||
label: "证书名称",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
label: "证书编号",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "postId",
|
|
||||||
label: "岗位名称",
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={props.dictionaryType}
|
|
||||||
onGetLabel={label => form.setFieldValue("postName", label)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ name: "postName", label: "岗位名称", onlyForLabel: true },
|
|
||||||
{
|
|
||||||
name: "issuingAuthority",
|
|
||||||
label: "发证机构",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "dateIssue",
|
|
||||||
label: "发证日期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateDate",
|
|
||||||
label: "有效期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
const allEmptyStrings = Array.isArray(value) && value.every(item => item === "");
|
|
||||||
if (allEmptyStrings) {
|
|
||||||
return Promise.reject(new Error("请选择有效期"));
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateImgs",
|
|
||||||
label: "证照照片",
|
|
||||||
render: (
|
|
||||||
<Upload
|
|
||||||
|
|
||||||
maxCount={2}
|
|
||||||
onGetRemoveFile={(file) => {
|
|
||||||
setDeleteCardImageFiles([...deleteCardImageFiles, file]);
|
|
||||||
}}
|
|
||||||
tipContent={(
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
lineHeight: 1.6,
|
|
||||||
color: "red",
|
|
||||||
fontSize: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
温馨提示:用户要上传证照照片正反面(证照照片数量是2张)单张大小不超过10MB,支持jpg、jpeg、png格式。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
labelCol={{
|
|
||||||
span: 10,
|
|
||||||
}}
|
|
||||||
showActionButtons={false}
|
|
||||||
onFinish={onSubmit}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const AddModal = AddModalComponent;
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
import { Descriptions, Divider } from "antd";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PreviewImg from "zy-react-library/components/PreviewImg";
|
|
||||||
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
|
|
||||||
import useGetFile from "zy-react-library/hooks/useGetFile";
|
|
||||||
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
const JOB_STATUS = {
|
|
||||||
1: "在职",
|
|
||||||
0: "离职",
|
|
||||||
2: "信息变更中",
|
|
||||||
3: "未入职",
|
|
||||||
4: "实习生",
|
|
||||||
5: "实习结束",
|
|
||||||
6: "退休",
|
|
||||||
7: "劳务派遣",
|
|
||||||
8: "劳务派遣结束",
|
|
||||||
11: "入职待审核",
|
|
||||||
10: "离职待审核",
|
|
||||||
};
|
|
||||||
function SpecialCertificateInfo({ props, certificatePhotoType }) {
|
|
||||||
const [info, setInfo] = useState({});
|
|
||||||
const queryParams = useGetUrlQuery();
|
|
||||||
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(queryParams["personnelType"]);
|
|
||||||
const fetchData = async () => {
|
|
||||||
const res = await props.userCertificateInfo({
|
|
||||||
id: queryParams["id"],
|
|
||||||
});
|
|
||||||
const licenseFile = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[certificatePhotoType],
|
|
||||||
eqForeignKey: res.data.userCertificateId,
|
|
||||||
});
|
|
||||||
res.data.licenseFile = licenseFile;
|
|
||||||
setInfo(res.data || {});
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<Page headerTitle="证书信息查看">
|
|
||||||
<div>
|
|
||||||
<Divider orientation="left">人员信息</Divider>
|
|
||||||
<Descriptions
|
|
||||||
bordered
|
|
||||||
loding={getFileLoading}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: "姓名",
|
|
||||||
children: info.name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "企业名称",
|
|
||||||
children: info.corpinfoName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "部门名称",
|
|
||||||
children: info.departmentName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "岗位名称",
|
|
||||||
children: info.userPostName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "就职状态",
|
|
||||||
children: <div>{JOB_STATUS[info.employmentStatus]}</div>,
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
column={2}
|
|
||||||
labelStyle={{
|
|
||||||
width: 200,
|
|
||||||
}}
|
|
||||||
contentStyle={{
|
|
||||||
width: 500,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Divider orientation="left">证书信息</Divider>
|
|
||||||
<Descriptions
|
|
||||||
bordered
|
|
||||||
loding={getFileLoading}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: "证书名称",
|
|
||||||
children: info.certificateName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证书编号",
|
|
||||||
children: info.certificateCode,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "发证机构",
|
|
||||||
children: info.issuingAuthority,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: queryParams["personnelType"] === "tzsbczry" ? "操作项目" : "行业类别",
|
|
||||||
|
|
||||||
children: queryParams["personnelType"] === "tzsbczry" ? info.assignmentOperatingItemsName : info.industryCategoryName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: queryParams["personnelType"] === "tzsbczry" ? "作业类别" : "操作项目",
|
|
||||||
children: queryParams["personnelType"] === "tzsbczry" ? info.assignmentCategoryName : info.industryOperatingItemsName,
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
label: "发证日期",
|
|
||||||
children: info.dateIssue,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
label: "复审日期",
|
|
||||||
children: info.reviewDate,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "有效期至",
|
|
||||||
children: <div>{`${info.certificateDateStart ?? ""} - ${info.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证照照片",
|
|
||||||
children: <PreviewImg files={info.licenseFile} />,
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
column={2}
|
|
||||||
labelStyle={{
|
|
||||||
width: 200,
|
|
||||||
}}
|
|
||||||
contentStyle={{
|
|
||||||
width: 500,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Page>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(SpecialCertificateInfo);
|
|
||||||
|
|
@ -1,796 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, message, Modal, Space } from "antd";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import { useLocation } from "react-router-dom";
|
|
||||||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
|
||||||
import AddIcon from "zy-react-library/components/Icon/AddIcon";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
import TooltipPreviewImg from "zy-react-library/components/TooltipPreviewImg";
|
|
||||||
import Upload from "zy-react-library/components/Upload";
|
|
||||||
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
|
||||||
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
|
|
||||||
import useDeleteFile from "zy-react-library/hooks/useDeleteFile";
|
|
||||||
import useGetFile from "zy-react-library/hooks/useGetFile";
|
|
||||||
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
|
|
||||||
import useGetUserInfo from "zy-react-library/hooks/useGetUserInfo";
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import useUploadFile from "zy-react-library/hooks/useUploadFile";
|
|
||||||
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
import { useDebounce } from "~/utils";
|
|
||||||
|
|
||||||
const JOB_STATUS = {
|
|
||||||
1: "在职",
|
|
||||||
0: "离职",
|
|
||||||
2: "信息变更中",
|
|
||||||
3: "未入职",
|
|
||||||
4: "实习生",
|
|
||||||
5: "实习结束",
|
|
||||||
6: "退休",
|
|
||||||
7: "劳务派遣",
|
|
||||||
8: "劳务派遣结束",
|
|
||||||
11: "入职待审核",
|
|
||||||
10: "离职待审核",
|
|
||||||
};
|
|
||||||
|
|
||||||
function SpecialCertificateList({ props, certificatePhotoType, displayType, personnelType, permissionAdd, permissionEdit, permissionView, permissionDel, dictionaryType }) {
|
|
||||||
const [addModalOpen, setAddModalOpen] = useState(false);
|
|
||||||
const [currentId, setCurrentId] = useState("");
|
|
||||||
const [operatingProjectType, setOperatingProjectType] = useState("");
|
|
||||||
const queryParams = useGetUrlQuery();
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const { tableProps, getData } = useTable(props["userCertificateList"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
if (formData.eqIndustryCategoryCode) {
|
|
||||||
setOperatingProjectType(formData.eqIndustryCategoryCode);
|
|
||||||
}
|
|
||||||
if (formData.eqAssignmentOperatingItemsCode) {
|
|
||||||
setOperatingProjectType(formData.eqAssignmentOperatingItemsCode);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
eqCorpinfoId: queryParams["corpinfoId"],
|
|
||||||
eqType: personnelType,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 清除伪类
|
|
||||||
useEffect(() => {
|
|
||||||
if (displayType === "View") {
|
|
||||||
const style = document.createElement("style");
|
|
||||||
style.innerHTML = `
|
|
||||||
.search-layout::after {
|
|
||||||
content: none !important;
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
document.head.appendChild(style);
|
|
||||||
// 清理函数,在组件卸载时移除样式
|
|
||||||
return () => {
|
|
||||||
document.head.removeChild(style);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onDelete = async (row) => {
|
|
||||||
props["projectHasUser"]({ eqUserId: row.userId }).then((res) => {
|
|
||||||
if (res.data && res.data.length > 0) {
|
|
||||||
const arr = [];
|
|
||||||
const userArr = [];
|
|
||||||
|
|
||||||
res.data.forEach((item) => {
|
|
||||||
arr.push(item.projectName);
|
|
||||||
userArr.push(item.userName);
|
|
||||||
});
|
|
||||||
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
【
|
|
||||||
{[...new Set(userArr)].join(",")}
|
|
||||||
】有正在进行的项目,包含【
|
|
||||||
{
|
|
||||||
[...new Set(arr)].join(",")
|
|
||||||
}
|
|
||||||
】确定删除吗?
|
|
||||||
</div>
|
|
||||||
<div style={{ fontSize: 14, color: "red" }}>删除可能会对正在进行的项目造成异常状态,请谨慎操作。</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
onOk: () => {
|
|
||||||
props["userCertificateRemove"]({
|
|
||||||
id: row.id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: "确定删除吗?",
|
|
||||||
onOk: () => {
|
|
||||||
props["userCertificateRemove"]({
|
|
||||||
id: row.id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const [fileCache, setFileCache] = useState({});
|
|
||||||
const [loadingKeys, setLoadingKeys] = useState(new Set());
|
|
||||||
const pendingLoadIdsRef = useRef(new Set());
|
|
||||||
const requestQueueRef = useRef([]);
|
|
||||||
const activeRequestsRef = useRef(0);
|
|
||||||
const MAX_CONCURRENT_REQUESTS = 3; // 最大并发请求数
|
|
||||||
|
|
||||||
const processQueue = () => {
|
|
||||||
while (
|
|
||||||
requestQueueRef.current.length > 0
|
|
||||||
&& activeRequestsRef.current < MAX_CONCURRENT_REQUESTS
|
|
||||||
) {
|
|
||||||
const { id, resolve, reject } = requestQueueRef.current.shift();
|
|
||||||
activeRequestsRef.current++;
|
|
||||||
|
|
||||||
getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[certificatePhotoType],
|
|
||||||
eqForeignKey: id,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
setFileCache(prev => ({
|
|
||||||
...prev,
|
|
||||||
[id]: res || [],
|
|
||||||
}));
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("图片加载失败:", err);
|
|
||||||
reject(err);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
activeRequestsRef.current--;
|
|
||||||
setLoadingKeys((prev) => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(id);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
processQueue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadFileForRecord = (userQualificationinfoId) => {
|
|
||||||
if (!userQualificationinfoId)
|
|
||||||
return Promise.resolve();
|
|
||||||
if (fileCache[userQualificationinfoId])
|
|
||||||
return Promise.resolve();
|
|
||||||
if (loadingKeys.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
if (pendingLoadIdsRef.current.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
|
|
||||||
pendingLoadIdsRef.current.add(userQualificationinfoId);
|
|
||||||
setLoadingKeys(prev => new Set([...prev, userQualificationinfoId]));
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
requestQueueRef.current.push({ id: userQualificationinfoId, resolve, reject });
|
|
||||||
processQueue();
|
|
||||||
}).finally(() => {
|
|
||||||
pendingLoadIdsRef.current.delete(userQualificationinfoId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 缓存数据变化时清空图片缓存
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
const currentIds = new Set(tableProps.dataSource.map(item => item.userCertificateId).filter(Boolean));
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = {};
|
|
||||||
Object.keys(prev).forEach((id) => {
|
|
||||||
if (currentIds.has(id)) {
|
|
||||||
newCache[id] = prev[id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
|
|
||||||
// 记录已经触发过加载的 ID,避免 render 重复触发
|
|
||||||
const triggeredLoadIdsRef = useRef(new Set());
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
tableProps.dataSource.forEach((record) => {
|
|
||||||
const id = record.userCertificateId;
|
|
||||||
if (id && !triggeredLoadIdsRef.current.has(id)) {
|
|
||||||
triggeredLoadIdsRef.current.add(id);
|
|
||||||
loadFileForRecord(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 组件卸载或数据源变化时重置
|
|
||||||
return () => {
|
|
||||||
triggeredLoadIdsRef.current.clear();
|
|
||||||
};
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
|
|
||||||
const onValuesChange = (changedValues) => {
|
|
||||||
if ("eqIndustryCategoryCode" in changedValues) {
|
|
||||||
const newIdCard = changedValues.eqIndustryCategoryCode;
|
|
||||||
if (newIdCard) {
|
|
||||||
setOperatingProjectType(newIdCard);
|
|
||||||
form.setFieldsValue({
|
|
||||||
eqIndustryOperatingItemsCode: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("eqAssignmentOperatingItemsCode" in changedValues) {
|
|
||||||
const newIdCard = changedValues.eqAssignmentOperatingItemsCode;
|
|
||||||
if (newIdCard) {
|
|
||||||
setOperatingProjectType(newIdCard);
|
|
||||||
form.setFieldsValue({
|
|
||||||
eqAssignmentCategoryCode: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
onValuesChange={onValuesChange}
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "likeUserName",
|
|
||||||
label: "姓名",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: personnelType === "tzsbczry" ? "eqAssignmentOperatingItemsCode" : "eqIndustryCategoryCode",
|
|
||||||
label: personnelType === "tzsbczry" ? "操作项目" : "行业类别",
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={dictionaryType}
|
|
||||||
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: personnelType === "tzsbczry" ? "eqAssignmentCategoryCode" : "eqIndustryOperatingItemsCode",
|
|
||||||
label: personnelType === "tzsbczry" ? "作业类别" : "操作项目",
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={operatingProjectType}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
loding={getFileLoading}
|
|
||||||
options={displayType !== "View"}
|
|
||||||
toolBarRender={() => (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
(displayType !== "View" && props.permission(permissionAdd))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<AddIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "姓名",
|
|
||||||
dataIndex: "name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书名称",
|
|
||||||
dataIndex: "certificateName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书编号",
|
|
||||||
dataIndex: "certificateCode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: personnelType === "tzsbczry" ? "操作项目" : "行业类别",
|
|
||||||
dataIndex: personnelType === "tzsbczry" ? "assignmentOperatingItemsName" : "industryCategoryName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: personnelType === "tzsbczry" ? "作业类别" : "操作项目",
|
|
||||||
dataIndex: personnelType === "tzsbczry" ? "assignmentCategoryName" : "industryOperatingItemsName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "有效期至",
|
|
||||||
dataIndex: "certificateDate",
|
|
||||||
width: 280,
|
|
||||||
render: (_, record) =>
|
|
||||||
<div>{`${record.certificateDateStart ?? ""} - ${record.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "就职状态",
|
|
||||||
dataIndex: "employmentStatus",
|
|
||||||
render: (_, record) => (
|
|
||||||
<div>{JOB_STATUS[record.employmentStatus] || "-"}</div>
|
|
||||||
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "图片",
|
|
||||||
dataIndex: "name",
|
|
||||||
render: (_, record) => {
|
|
||||||
const id = record.userCertificateId;
|
|
||||||
const files = fileCache[id] || [];
|
|
||||||
|
|
||||||
if (!files.length)
|
|
||||||
return <span>无</span>;
|
|
||||||
return <TooltipPreviewImg files={files} />;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 200,
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
{
|
|
||||||
props.permission(permissionView)
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./View?id=${record.id}&personnelType=${personnelType}`)}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
(displayType !== "View" && props.permission(permissionEdit))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
setCurrentId(record.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
displayType !== "View" && props.permission(permissionDel)
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
type="link"
|
|
||||||
onClick={() => onDelete(record)}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{addModalOpen && (
|
|
||||||
<AddModal
|
|
||||||
open={addModalOpen}
|
|
||||||
loding={props.userCertificate.userCertificateLoading}
|
|
||||||
getData={getData}
|
|
||||||
currentId={currentId}
|
|
||||||
requestAdd={props["userCertificateAdd"]}
|
|
||||||
requestEdit={props["userCertificateEdit"]}
|
|
||||||
requestDetails={props["userCertificateInfo"]}
|
|
||||||
userCertificateIsExistCertNo={props["userCertificateIsExistCertNo"]}
|
|
||||||
certificatePhotoType={certificatePhotoType}
|
|
||||||
getUserlistAll={props["getUserlistAll"]}
|
|
||||||
personnelType={personnelType}
|
|
||||||
dictionaryType={dictionaryType}
|
|
||||||
onCancel={() => {
|
|
||||||
setAddModalOpen(false);
|
|
||||||
setCurrentId("");
|
|
||||||
}}
|
|
||||||
onSuccess={(userQualificationinfoId) => {
|
|
||||||
// 清除该记录的图片缓存,强制下次 render 时重新加载
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = { ...prev };
|
|
||||||
delete newCache[userQualificationinfoId];
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function AddModalComponent(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const [userQualificationinfoId, setUserQualificationinfoId] = useState("");
|
|
||||||
|
|
||||||
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
|
|
||||||
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
const [operatingProjectType, setOperatingProjectType] = useState("");
|
|
||||||
const [deleteCardImageFiles, setDeleteCardImageFiles] = useState([]);
|
|
||||||
const [CertificateCodeValue, setPertificateCodeValue] = useState(null);
|
|
||||||
const [userObj, setUserObj] = useState({});
|
|
||||||
const debouncedCertificateCodeValue = useDebounce(CertificateCodeValue, 100);
|
|
||||||
const [isSubmit, setIsSubmit] = useState(true);
|
|
||||||
const [personnelData, setPersonnelData] = useState([]);
|
|
||||||
const { getUserInfo } = useGetUserInfo();
|
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const getUserInfoFun = async () => {
|
|
||||||
const userInfo = await getUserInfo();
|
|
||||||
|
|
||||||
setUserObj(userInfo);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 校验重复
|
|
||||||
useEffect(() => {
|
|
||||||
if (!debouncedCertificateCodeValue) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
props["userCertificateIsExistCertNo"]({
|
|
||||||
certNo: debouncedCertificateCodeValue,
|
|
||||||
id: props.currentId ?? "",
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
setIsSubmit(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setIsSubmit(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [debouncedCertificateCodeValue]);
|
|
||||||
const getUserlistFun = async () => {
|
|
||||||
props.getUserlistAll({ menuPath: `/certificate${location.pathname}` }).then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
console.log(res.data);
|
|
||||||
res.data.forEach((item) => {
|
|
||||||
item.bianma = item.id;
|
|
||||||
});
|
|
||||||
setPersonnelData(res.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.currentId) {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const { data } = await props.requestDetails({
|
|
||||||
id: props.currentId,
|
|
||||||
});
|
|
||||||
setOperatingProjectType(data.industryCategoryCode ? data.industryCategoryCode : data.assignmentOperatingItemsCode);
|
|
||||||
data.certificateDate = [data.certificateDateStart, data.certificateDateEnd];
|
|
||||||
|
|
||||||
const certificateImgs = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
|
|
||||||
eqForeignKey: data.userCertificateId,
|
|
||||||
});
|
|
||||||
data.certificateImgs = certificateImgs;
|
|
||||||
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setUserQualificationinfoId(data.userCertificateId);
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
getUserInfoFun();
|
|
||||||
getUserlistFun();
|
|
||||||
}, [props.currentId]);
|
|
||||||
const onCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
props.onCancel();
|
|
||||||
};
|
|
||||||
const onSubmit = async (values) => {
|
|
||||||
if (!isSubmit) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.certificateImgs.length !== 2) {
|
|
||||||
message.error("证照照片必须上传正反面两张");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const maxSizeInBytes = 10 * 1024 * 1024;
|
|
||||||
|
|
||||||
const isOverSize = values.certificateImgs.some(file => file.size > maxSizeInBytes);
|
|
||||||
|
|
||||||
if (isOverSize) {
|
|
||||||
message.error("选择的图片不能大于10MB");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await deleteFile({
|
|
||||||
single: false,
|
|
||||||
files: deleteCardImageFiles,
|
|
||||||
});
|
|
||||||
const { id } = await uploadFile({
|
|
||||||
single: false,
|
|
||||||
files: values.certificateImgs,
|
|
||||||
params: {
|
|
||||||
type: UPLOAD_FILE_TYPE_ENUM[props.certificatePhotoType],
|
|
||||||
foreignKey: userQualificationinfoId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
values.type = props.personnelType;
|
|
||||||
|
|
||||||
const personnelTypeMap = {
|
|
||||||
tezhongzuoye: "特种作业人员",
|
|
||||||
tzsbczry: "特种设备操作人员",
|
|
||||||
zyfzr: "主要负责人",
|
|
||||||
aqscglry: "安全生产管理人员",
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
values.typeName = personnelTypeMap[props.personnelType];
|
|
||||||
|
|
||||||
values.certificateDateStart = values.certificateDate[0];
|
|
||||||
values.certificateDateEnd = values.certificateDate[1];
|
|
||||||
|
|
||||||
if (props.currentId) {
|
|
||||||
values.id = props.currentId;
|
|
||||||
values.userCertificateId = userQualificationinfoId;
|
|
||||||
await props.requestEdit(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
props.onSuccess(userQualificationinfoId);
|
|
||||||
message.success("编辑成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
values.userCertificateId = id;
|
|
||||||
await props.requestAdd(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
props.onSuccess(userQualificationinfoId);
|
|
||||||
message.success("新增成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onValuesChange = (changedValues) => {
|
|
||||||
if ("industryCategoryCode" in changedValues) {
|
|
||||||
const industryCategoryCode = changedValues.industryCategoryCode;
|
|
||||||
|
|
||||||
if (industryCategoryCode) {
|
|
||||||
setOperatingProjectType(industryCategoryCode);
|
|
||||||
|
|
||||||
form.setFieldsValue({
|
|
||||||
industryOperatingItemsCode: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("assignmentOperatingItemsCode" in changedValues) {
|
|
||||||
const assignmentOperatingItemsCode = changedValues.assignmentOperatingItemsCode;
|
|
||||||
|
|
||||||
if (assignmentOperatingItemsCode) {
|
|
||||||
setOperatingProjectType(assignmentOperatingItemsCode);
|
|
||||||
|
|
||||||
form.setFieldsValue({
|
|
||||||
assignmentCategoryCode: undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ("certificateCode" in changedValues) {
|
|
||||||
setPertificateCodeValue(changedValues.certificateCode ?? "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={props.open}
|
|
||||||
maskClosable={false}
|
|
||||||
title={props.currentId ? "编辑" : "新增"}
|
|
||||||
width={800}
|
|
||||||
confirmLoading={
|
|
||||||
deleteFileLoading || uploadFileLoading || getFileLoading || props.loding
|
|
||||||
}
|
|
||||||
onOk={form.submit}
|
|
||||||
onCancel={onCancel}
|
|
||||||
|
|
||||||
>
|
|
||||||
<FormBuilder
|
|
||||||
form={form}
|
|
||||||
onValuesChange={onValuesChange}
|
|
||||||
span={24}
|
|
||||||
values={{
|
|
||||||
securityFlag: 0,
|
|
||||||
}}
|
|
||||||
options={[
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "userId",
|
|
||||||
label: "选择人员",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
|
||||||
items: personnelData,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateName",
|
|
||||||
label: "证书名称",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
label: "证书编号",
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "issuingAuthority",
|
|
||||||
label: "发证机构",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "industryCategoryCode",
|
|
||||||
label: "行业类别",
|
|
||||||
hidden: !(props.personnelType === "tezhongzuoye"),
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={props.dictionaryType}
|
|
||||||
onGetLabel={label => form.setFieldValue("industryCategoryName", label)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ name: "industryCategoryName", label: "行业类别名称", onlyForLabel: true },
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "industryOperatingItemsCode",
|
|
||||||
label: "操作项目",
|
|
||||||
hidden: !(props.personnelType === "tezhongzuoye"),
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={operatingProjectType}
|
|
||||||
onGetLabel={label => form.setFieldValue("industryOperatingItemsName", label)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ name: "industryOperatingItemsName", label: "操作项目名称", onlyForLabel: true },
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "assignmentOperatingItemsCode",
|
|
||||||
label: "操作项目",
|
|
||||||
hidden: !(props.personnelType === "tzsbczry"),
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={props.dictionaryType}
|
|
||||||
onGetLabel={label => form.setFieldValue("assignmentOperatingItemsName", label)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ name: "assignmentOperatingItemsName", label: "操作项目名称", onlyForLabel: true },
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "assignmentCategoryCode",
|
|
||||||
label: "作业类别",
|
|
||||||
hidden: !(props.personnelType === "tzsbczry"),
|
|
||||||
render: (
|
|
||||||
<DictionarySelect
|
|
||||||
dictValue={operatingProjectType}
|
|
||||||
onGetLabel={label => form.setFieldValue("assignmentCategoryName", label)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{ name: "assignmentCategoryName", label: "作业类别名称", onlyForLabel: true },
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "dateIssue",
|
|
||||||
label: "发证日期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateDate",
|
|
||||||
label: "有效期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
const allEmptyStrings = Array.isArray(value) && value.every(item => item === "");
|
|
||||||
if (allEmptyStrings) {
|
|
||||||
return Promise.reject(new Error("请选择有效期"));
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "reviewDate",
|
|
||||||
label: "复审日期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "certificateImgs",
|
|
||||||
label: "证照照片",
|
|
||||||
render: (
|
|
||||||
<Upload
|
|
||||||
|
|
||||||
maxCount={2}
|
|
||||||
onGetRemoveFile={(file) => {
|
|
||||||
setDeleteCardImageFiles([...deleteCardImageFiles, file]);
|
|
||||||
}}
|
|
||||||
tipContent={(
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
lineHeight: 1.6,
|
|
||||||
color: "red",
|
|
||||||
fontSize: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
温馨提示:用户要上传证照照片正反面(证照照片数量是2张)单张大小不超过10MB,支持jpg、jpeg、png格式。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
labelCol={{
|
|
||||||
span: 10,
|
|
||||||
}}
|
|
||||||
showActionButtons={false}
|
|
||||||
onFinish={onSubmit}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const AddModal = AddModalComponent;
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(SpecialCertificateList));
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
/**
|
|
||||||
* 全局常量定义
|
|
||||||
*/
|
|
||||||
|
|
||||||
export {};
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
/**
|
|
||||||
* 全局上下文定义
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
// 获取antd全局静态方法
|
|
||||||
export const InjectContext = React.createContext({});
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
/**
|
|
||||||
* 全局数据状态管理模块定义
|
|
||||||
*/
|
|
||||||
import { defineNamespace } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
|
|
||||||
export const NS_GLOBAL = defineNamespace("global");
|
|
||||||
export const NS_PERSNONEL_CERTFICATE = defineNamespace("personnelCertificate");
|
|
||||||
export const NS_CORP_CERTIFICATE = defineNamespace("corpCertificate");
|
|
||||||
export const NS_USER_CERTIFICATE = defineNamespace("userCertificate");
|
|
||||||
export const NS_COURSEWARE = defineNamespace("courseware");
|
|
||||||
49
src/main.js
49
src/main.js
|
|
@ -1,49 +0,0 @@
|
||||||
import { setJJBCommonAntdMessage } from "@cqsjjb/jjb-common-lib";
|
|
||||||
import { setup } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { message } from "antd";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { getFileUrlFromServer } from "zy-react-library/utils";
|
|
||||||
import "dayjs/locale/zh-cn";
|
|
||||||
import "../blessed_by_buddha";
|
|
||||||
|
|
||||||
require("antd/dist/reset.css");
|
|
||||||
require("zy-react-library/css/common.less");
|
|
||||||
|
|
||||||
dayjs.locale("zh-cn");
|
|
||||||
setJJBCommonAntdMessage(message);
|
|
||||||
|
|
||||||
const app = setup();
|
|
||||||
getFileUrlFromServer();
|
|
||||||
// 非底座环境运行
|
|
||||||
if (!window.__POWERED_BY_QIANKUN__) {
|
|
||||||
// 云组件默认依赖
|
|
||||||
window.__coreLib = {};
|
|
||||||
window.__coreLib.React = require("react");
|
|
||||||
window.__coreLib.ReactDOM = require("react-dom");
|
|
||||||
window.__coreLib.jjbCommonLib = require("@cqsjjb/jjb-common-lib");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 挂载
|
|
||||||
* @param props {{ setGlobalState: ({ rendered: boolean }) => void }}
|
|
||||||
* @returns {Promise<*>} ''
|
|
||||||
*/
|
|
||||||
export const mount = async (props) => {
|
|
||||||
// 云组件默认依赖
|
|
||||||
window.__coreLib.React = require("react");
|
|
||||||
window.__coreLib.ReactDOM = require("react-dom");
|
|
||||||
window.__coreLib.jjbCommonLib = require("@cqsjjb/jjb-common-lib");
|
|
||||||
app.mount(props);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @description 卸载
|
|
||||||
* @param props {object}
|
|
||||||
* @returns {Promise<*>} ''
|
|
||||||
*/
|
|
||||||
export const unmount = async props => app.unmount(props);
|
|
||||||
/**
|
|
||||||
* @description 启动
|
|
||||||
* @param props
|
|
||||||
*/
|
|
||||||
export const bootstrap = async props => app.bootstrap(props);
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import EnterpriseLicenseList from "~/pages/Container/Supervision/EnterpriseLicense/EnterpriseLicense";
|
|
||||||
|
|
||||||
function EnterpriseLicense(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<EnterpriseLicenseList
|
|
||||||
props={props}
|
|
||||||
permissionAdd="qyd-qyzzgl-add"
|
|
||||||
permissionEdit="qyd-qyzzgl-edit"
|
|
||||||
permissionView="qyd-qyzzgl-info"
|
|
||||||
permissionDel="qyd-qyzzgl-del"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EnterpriseLicense;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业主要负责人管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
personnelType="zyfzr"
|
|
||||||
permissionAdd="qyd-zyfzrgl-add"
|
|
||||||
permissionEdit="qyd-zyfzrgl-edit"
|
|
||||||
permissionView="qyd-zyfzrgl-info"
|
|
||||||
permissionDel="qyd-zyfzrgl-del"
|
|
||||||
dictionaryType="zyfzrgwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonInCharge(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonInCharge;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业安全生产管理人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
personnelType="aqscglry"
|
|
||||||
permissionAdd="qyd-aqscglrygl-add"
|
|
||||||
permissionEdit="qyd-aqscglrygl-edit"
|
|
||||||
permissionView="qyd-aqscglrygl-info"
|
|
||||||
permissionDel="qyd-aqscglrygl-del"
|
|
||||||
dictionaryType="aqscglrygwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SecurityAdmini(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SecurityAdmini;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
import {Permission} from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
// 企业特种设备操作人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
personnelType="tzsbczry"
|
|
||||||
permissionAdd="qyd-tzsbczrygl-add"
|
|
||||||
permissionEdit="qyd-tzsbczrygl-edit"
|
|
||||||
permissionView="qyd-tzsbczrygl-info"
|
|
||||||
permissionDel="qyd-tzsbczrygl-del"
|
|
||||||
dictionaryType="tzsbczryczxmzylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialEquipment(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialEquipment;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种作业人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
personnelType="tezhongzuoye"
|
|
||||||
permissionAdd="qyd-tzzyrugl-add"
|
|
||||||
permissionEdit="qyd-tzzyrugl-edit"
|
|
||||||
permissionView="qyd-tzzyrugl-info"
|
|
||||||
permissionDel="qyd-tzzyrugl-del"
|
|
||||||
dictionaryType="tzzyryhylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialPersonnel(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialPersonnel;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonnelLicense(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonnelLicense;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function EnterpriseLicenseManage(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EnterpriseLicenseManage;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function BranchCompany(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BranchCompany;
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import { ImportCore } from "@cqsjjb/jjb-common-decorator/module";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export default class Entry extends React.Component {
|
|
||||||
state = {
|
|
||||||
Component: undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (process.env.app.appKey) {
|
|
||||||
ImportCore({
|
|
||||||
name: "$",
|
|
||||||
from: "https://cdn.cqjjb.cn/jcloud/use/plugin/b31c9840a57f11ef91cf7f3cabbb7484/latest",
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.status) {
|
|
||||||
this.setState({ Component: res.module?.default });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { Component } = this.state;
|
|
||||||
return (Component && process.env.app.appKey) && (
|
|
||||||
<Component
|
|
||||||
detail={{ componentKey: process.env.app.appKey }}
|
|
||||||
appKey={process.env.app.appKey}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,434 +0,0 @@
|
||||||
import React, {
|
|
||||||
useState,
|
|
||||||
useCallback,
|
|
||||||
useMemo,
|
|
||||||
useEffect,
|
|
||||||
} from "react";
|
|
||||||
import { Layout, Menu, Breadcrumb, Tabs, Button, Dropdown, Space, Typography } from "antd";
|
|
||||||
import {
|
|
||||||
ReloadOutlined,
|
|
||||||
CloseOutlined,
|
|
||||||
CloseCircleOutlined,
|
|
||||||
DownOutlined,
|
|
||||||
MenuFoldOutlined,
|
|
||||||
MenuUnfoldOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import menuItems, {
|
|
||||||
findMenuPath,
|
|
||||||
getPageLabel,
|
|
||||||
getOpenKeys,
|
|
||||||
getSelectedKeys,
|
|
||||||
} from "./menuConfig";
|
|
||||||
|
|
||||||
const { Header, Sider, Content } = Layout;
|
|
||||||
const { Text } = Typography;
|
|
||||||
|
|
||||||
const TABS_KEY = "sim_layout_tabs";
|
|
||||||
const ACTIVE_KEY = "sim_layout_active";
|
|
||||||
|
|
||||||
/* ---- sessionStorage 持久化 ---- */
|
|
||||||
function loadState() {
|
|
||||||
try {
|
|
||||||
const tabs = JSON.parse(sessionStorage.getItem(TABS_KEY) || "[]");
|
|
||||||
const activeKey = sessionStorage.getItem(ACTIVE_KEY) || "";
|
|
||||||
return { tabs, activeKey };
|
|
||||||
} catch {
|
|
||||||
return { tabs: [], activeKey: "" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveState(tabs, activeKey) {
|
|
||||||
sessionStorage.setItem(TABS_KEY, JSON.stringify(tabs));
|
|
||||||
sessionStorage.setItem(ACTIVE_KEY, activeKey || "");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function SimulatedLayout({ children }) {
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
const [state, setState] = useState(loadState);
|
|
||||||
const currentPath = window.location.pathname;
|
|
||||||
|
|
||||||
// 页面加载时自动将当前路径加入标签
|
|
||||||
useEffect(() => {
|
|
||||||
if (currentPath && !currentPath.endsWith("/container/")) {
|
|
||||||
addTab(currentPath);
|
|
||||||
}
|
|
||||||
}, []); // 仅挂载时执行一次
|
|
||||||
|
|
||||||
/* ---- 标签操作 ---- */
|
|
||||||
const addTab = useCallback((path) => {
|
|
||||||
setState((prev) => {
|
|
||||||
if (prev.tabs.find((t) => t.key === path)) {
|
|
||||||
// 已存在则仅更新 activeKey
|
|
||||||
if (prev.activeKey !== path) {
|
|
||||||
saveState(prev.tabs, path);
|
|
||||||
return { ...prev, activeKey: path };
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
const newTabs = [...prev.tabs, { key: path, label: getPageLabel(path) }];
|
|
||||||
saveState(newTabs, path);
|
|
||||||
return { tabs: newTabs, activeKey: path };
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const navigateTo = useCallback((path) => {
|
|
||||||
if (path !== currentPath) {
|
|
||||||
window.location.href = path;
|
|
||||||
}
|
|
||||||
}, [currentPath]);
|
|
||||||
|
|
||||||
const handleCloseTab = useCallback((targetKey) => {
|
|
||||||
setState((prev) => {
|
|
||||||
const idx = prev.tabs.findIndex((t) => t.key === targetKey);
|
|
||||||
const newTabs = prev.tabs.filter((t) => t.key !== targetKey);
|
|
||||||
if (newTabs.length === 0) {
|
|
||||||
saveState([], "");
|
|
||||||
return { tabs: [], activeKey: "" };
|
|
||||||
}
|
|
||||||
let newActive = prev.activeKey;
|
|
||||||
if (targetKey === prev.activeKey) {
|
|
||||||
newActive = newTabs[Math.max(0, idx - 1)]?.key || newTabs[0]?.key;
|
|
||||||
navigateTo(newActive);
|
|
||||||
}
|
|
||||||
saveState(newTabs, newActive);
|
|
||||||
return { tabs: newTabs, activeKey: newActive };
|
|
||||||
});
|
|
||||||
}, [navigateTo]);
|
|
||||||
|
|
||||||
const handleCloseOthers = useCallback((targetKey) => {
|
|
||||||
setState((prev) => {
|
|
||||||
const target = prev.tabs.find((t) => t.key === targetKey);
|
|
||||||
const newTabs = target ? [target] : [];
|
|
||||||
saveState(newTabs, targetKey);
|
|
||||||
if (targetKey !== currentPath) navigateTo(targetKey);
|
|
||||||
return { tabs: newTabs, activeKey: targetKey };
|
|
||||||
});
|
|
||||||
}, [currentPath, navigateTo]);
|
|
||||||
|
|
||||||
const handleCloseRight = useCallback((targetKey) => {
|
|
||||||
setState((prev) => {
|
|
||||||
const idx = prev.tabs.findIndex((t) => t.key === targetKey);
|
|
||||||
if (idx === -1) return prev;
|
|
||||||
const newTabs = prev.tabs.slice(0, idx + 1);
|
|
||||||
saveState(newTabs, targetKey);
|
|
||||||
return { tabs: newTabs, activeKey: targetKey };
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleCloseAll = useCallback(() => {
|
|
||||||
saveState([], "");
|
|
||||||
setState({ tabs: [], activeKey: "" });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleRefresh = useCallback(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/* ---- 菜单事件 ---- */
|
|
||||||
const handleMenuClick = useCallback(
|
|
||||||
({ key }) => {
|
|
||||||
navigateTo(key);
|
|
||||||
},
|
|
||||||
[navigateTo],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleTabChange = useCallback(
|
|
||||||
(key) => {
|
|
||||||
navigateTo(key);
|
|
||||||
},
|
|
||||||
[navigateTo],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleTabEdit = useCallback(
|
|
||||||
(targetKey, action) => {
|
|
||||||
if (action === "remove") handleCloseTab(targetKey);
|
|
||||||
},
|
|
||||||
[handleCloseTab],
|
|
||||||
);
|
|
||||||
|
|
||||||
/* ---- 面包屑 ---- */
|
|
||||||
const breadcrumbItems = useMemo(() => {
|
|
||||||
const path = findMenuPath(currentPath);
|
|
||||||
return path.map((item, idx) => ({
|
|
||||||
title:
|
|
||||||
idx === path.length - 1 ? (
|
|
||||||
item.label
|
|
||||||
) : (
|
|
||||||
<a onClick={() => handleMenuClick({ key: item.key })}>{item.label}</a>
|
|
||||||
),
|
|
||||||
key: item.key,
|
|
||||||
}));
|
|
||||||
}, [currentPath, handleMenuClick]);
|
|
||||||
|
|
||||||
/* ---- 菜单选中/展开 ---- */
|
|
||||||
const selectedKeys = useMemo(() => getSelectedKeys(currentPath), [currentPath]);
|
|
||||||
const defaultOpenKeys = useMemo(() => getOpenKeys(currentPath), [currentPath]);
|
|
||||||
|
|
||||||
/* ---- 标签页右键菜单 ---- */
|
|
||||||
const buildContextMenu = useCallback(
|
|
||||||
(tabKey) => {
|
|
||||||
const { tabs } = state;
|
|
||||||
const isOnlyOne = tabs.length <= 1;
|
|
||||||
const idx = tabs.findIndex((t) => t.key === tabKey);
|
|
||||||
const hasRight = idx >= 0 && idx < tabs.length - 1;
|
|
||||||
return {
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
key: "refresh",
|
|
||||||
icon: <ReloadOutlined />,
|
|
||||||
label: "刷新当前标签",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "close",
|
|
||||||
icon: <CloseOutlined />,
|
|
||||||
label: "关闭当前标签",
|
|
||||||
disabled: isOnlyOne,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "close-others",
|
|
||||||
icon: <CloseCircleOutlined />,
|
|
||||||
label: "关闭其他标签",
|
|
||||||
disabled: isOnlyOne,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "close-right",
|
|
||||||
icon: <CloseOutlined />,
|
|
||||||
label: "关闭右侧标签",
|
|
||||||
disabled: !hasRight,
|
|
||||||
},
|
|
||||||
{ type: "divider" },
|
|
||||||
{
|
|
||||||
key: "close-all",
|
|
||||||
icon: <CloseCircleOutlined />,
|
|
||||||
label: "关闭所有标签",
|
|
||||||
disabled: tabs.length === 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onClick: ({ key }) => {
|
|
||||||
switch (key) {
|
|
||||||
case "refresh":
|
|
||||||
handleRefresh();
|
|
||||||
break;
|
|
||||||
case "close":
|
|
||||||
handleCloseTab(tabKey);
|
|
||||||
break;
|
|
||||||
case "close-others":
|
|
||||||
handleCloseOthers(tabKey);
|
|
||||||
break;
|
|
||||||
case "close-right":
|
|
||||||
handleCloseRight(tabKey);
|
|
||||||
break;
|
|
||||||
case "close-all":
|
|
||||||
handleCloseAll();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
[state, handleRefresh, handleCloseTab, handleCloseOthers, handleCloseRight, handleCloseAll],
|
|
||||||
);
|
|
||||||
|
|
||||||
/* ---- 标签 label 渲染(带右键菜单) ---- */
|
|
||||||
const renderTabLabel = useCallback(
|
|
||||||
(tab) => (
|
|
||||||
<Dropdown menu={buildContextMenu(tab.key)} trigger={["contextMenu"]}>
|
|
||||||
<span style={{ display: "inline-block", padding: "0 8px", userSelect: "none" }}>
|
|
||||||
{tab.label}
|
|
||||||
</span>
|
|
||||||
</Dropdown>
|
|
||||||
),
|
|
||||||
[buildContextMenu],
|
|
||||||
);
|
|
||||||
|
|
||||||
const { tabs, activeKey } = state;
|
|
||||||
const siderWidth = collapsed ? 64 : 220;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout style={{ minHeight: "100vh" }}>
|
|
||||||
{/* ---- 侧边栏 ---- */}
|
|
||||||
<Sider
|
|
||||||
collapsible
|
|
||||||
collapsed={collapsed}
|
|
||||||
onCollapse={setCollapsed}
|
|
||||||
theme="dark"
|
|
||||||
width={220}
|
|
||||||
style={{
|
|
||||||
overflow: "auto",
|
|
||||||
height: "100vh",
|
|
||||||
position: "fixed",
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
bottom: 0,
|
|
||||||
zIndex: 10,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: 48,
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
color: "#fff",
|
|
||||||
fontWeight: 700,
|
|
||||||
fontSize: collapsed ? 15 : 17,
|
|
||||||
borderBottom: "1px solid rgba(255,255,255,0.1)",
|
|
||||||
letterSpacing: 1,
|
|
||||||
flexShrink: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{collapsed ? "证照" : "证照管理系统"}
|
|
||||||
</div>
|
|
||||||
<Menu
|
|
||||||
theme="dark"
|
|
||||||
mode="inline"
|
|
||||||
selectedKeys={selectedKeys}
|
|
||||||
defaultOpenKeys={defaultOpenKeys}
|
|
||||||
onClick={handleMenuClick}
|
|
||||||
items={menuItems}
|
|
||||||
style={{ borderRight: 0 }}
|
|
||||||
/>
|
|
||||||
</Sider>
|
|
||||||
|
|
||||||
{/* ---- 右侧主体 ---- */}
|
|
||||||
<Layout
|
|
||||||
style={{
|
|
||||||
marginLeft: siderWidth,
|
|
||||||
transition: "margin-left 0.2s",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* ---- Header + 面包屑 + 操作按钮 ---- */}
|
|
||||||
<Header
|
|
||||||
style={{
|
|
||||||
background: "#fff",
|
|
||||||
padding: "0 16px",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
borderBottom: "1px solid #f0f0f0",
|
|
||||||
height: 48,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Space>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
||||||
onClick={() => setCollapsed(!collapsed)}
|
|
||||||
/>
|
|
||||||
<Breadcrumb items={breadcrumbItems} />
|
|
||||||
</Space>
|
|
||||||
<Space>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<ReloadOutlined />}
|
|
||||||
onClick={handleRefresh}
|
|
||||||
>
|
|
||||||
刷新
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<CloseCircleOutlined />}
|
|
||||||
onClick={handleCloseAll}
|
|
||||||
disabled={tabs.length === 0}
|
|
||||||
>
|
|
||||||
关闭所有
|
|
||||||
</Button>
|
|
||||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
|
||||||
模拟布局·Dev
|
|
||||||
</Text>
|
|
||||||
</Space>
|
|
||||||
</Header>
|
|
||||||
|
|
||||||
{/* ---- 标签栏 ---- */}
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
background: "#fff",
|
|
||||||
borderBottom: "1px solid #f0f0f0",
|
|
||||||
padding: "4px 8px 0",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tabs.length > 0 ? (
|
|
||||||
<Tabs
|
|
||||||
type="editable-card"
|
|
||||||
hideAdd
|
|
||||||
activeKey={activeKey}
|
|
||||||
onChange={handleTabChange}
|
|
||||||
onEdit={handleTabEdit}
|
|
||||||
size="small"
|
|
||||||
style={{ marginBottom: 0 }}
|
|
||||||
items={tabs.map((tab) => ({
|
|
||||||
key: tab.key,
|
|
||||||
label: renderTabLabel(tab),
|
|
||||||
closable: true,
|
|
||||||
}))}
|
|
||||||
tabBarExtraContent={
|
|
||||||
<Dropdown
|
|
||||||
menu={{
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
key: "refresh",
|
|
||||||
icon: <ReloadOutlined />,
|
|
||||||
label: "刷新当前标签",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "close-others",
|
|
||||||
icon: <CloseOutlined />,
|
|
||||||
label: "关闭其他标签",
|
|
||||||
disabled: tabs.length <= 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "close-all",
|
|
||||||
icon: <CloseCircleOutlined />,
|
|
||||||
label: "关闭所有标签",
|
|
||||||
disabled: tabs.length === 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
onClick: ({ key }) => {
|
|
||||||
switch (key) {
|
|
||||||
case "refresh":
|
|
||||||
handleRefresh();
|
|
||||||
break;
|
|
||||||
case "close-others":
|
|
||||||
handleCloseOthers(activeKey);
|
|
||||||
break;
|
|
||||||
case "close-all":
|
|
||||||
handleCloseAll();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
placement="bottomRight"
|
|
||||||
>
|
|
||||||
<Button type="text" size="small" icon={<DownOutlined />} />
|
|
||||||
</Dropdown>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: 36,
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingLeft: 8,
|
|
||||||
color: "#bbb",
|
|
||||||
fontSize: 12,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
暂无打开的标签页,请从左侧菜单选择页面
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* ---- 内容区 ---- */}
|
|
||||||
<Content
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
minHeight: 280,
|
|
||||||
position: "relative",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Content>
|
|
||||||
</Layout>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,239 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import {
|
|
||||||
DashboardOutlined,
|
|
||||||
FileProtectOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
BankOutlined,
|
|
||||||
UserSwitchOutlined,
|
|
||||||
IdcardOutlined,
|
|
||||||
SafetyCertificateOutlined,
|
|
||||||
ToolOutlined,
|
|
||||||
UserOutlined,
|
|
||||||
BarChartOutlined,
|
|
||||||
PieChartOutlined,
|
|
||||||
ExperimentOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
|
|
||||||
const menuItems = [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision",
|
|
||||||
label: "监管端",
|
|
||||||
icon: <DashboardOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/test2",
|
|
||||||
label: "Test2 测试",
|
|
||||||
icon: <ExperimentOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/EnterpriseLicense",
|
|
||||||
label: "企业证照",
|
|
||||||
icon: <FileProtectOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/EnterpriseLicense/EnterpriseLicense",
|
|
||||||
label: "企业证照管理",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/EnterpriseLicense/BranchStatistics/List",
|
|
||||||
label: "分公司统计",
|
|
||||||
icon: <BarChartOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/EnterpriseLicense/StakeholderStatistics/List",
|
|
||||||
label: "干系人统计",
|
|
||||||
icon: <PieChartOutlined />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense",
|
|
||||||
label: "人员证照",
|
|
||||||
icon: <TeamOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/PersonInCharge/List",
|
|
||||||
label: "负责人",
|
|
||||||
icon: <UserOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/SecurityAdmini/List",
|
|
||||||
label: "安全管理员",
|
|
||||||
icon: <SafetyCertificateOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/SpecialDevice/List",
|
|
||||||
label: "特种设备",
|
|
||||||
icon: <ToolOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/SpecialPersonnel/List",
|
|
||||||
label: "特种作业人员",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/BranchCompanyStat/List",
|
|
||||||
label: "分公司人员统计",
|
|
||||||
icon: <BarChartOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Supervision/PersonnelLicense/StakeholderStat/List",
|
|
||||||
label: "干系人人员统计",
|
|
||||||
icon: <PieChartOutlined />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany",
|
|
||||||
label: "分公司端",
|
|
||||||
icon: <BankOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/EnterpriseLicense",
|
|
||||||
label: "企业证照管理",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/PersonnelLicense",
|
|
||||||
label: "人员证照",
|
|
||||||
icon: <TeamOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/PersonnelLicense/PersonInCharge/List",
|
|
||||||
label: "负责人",
|
|
||||||
icon: <UserOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/PersonnelLicense/SecurityAdmini/List",
|
|
||||||
label: "安全管理员",
|
|
||||||
icon: <SafetyCertificateOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/PersonnelLicense/SpecialDevice/List",
|
|
||||||
label: "特种设备",
|
|
||||||
icon: <ToolOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/BranchCompany/EnterpriseLicense/PersonnelLicense/SpecialPersonnel/List",
|
|
||||||
label: "特种作业人员",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder",
|
|
||||||
label: "干系人端",
|
|
||||||
icon: <UserSwitchOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/EnterpriseLicense",
|
|
||||||
label: "企业证照管理",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense",
|
|
||||||
label: "人员证照",
|
|
||||||
icon: <TeamOutlined />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense/PersonInCharge/List",
|
|
||||||
label: "负责人",
|
|
||||||
icon: <UserOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense/SecurityAdmini/List",
|
|
||||||
label: "安全管理员",
|
|
||||||
icon: <SafetyCertificateOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense/SpecialDevice/List",
|
|
||||||
label: "特种设备",
|
|
||||||
icon: <ToolOutlined />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Stakeholder/EnterpriseLicense/PersonnelLicense/SpecialPersonnel/List",
|
|
||||||
label: "特种作业人员",
|
|
||||||
icon: <IdcardOutlined />,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "/certificate/container/Test",
|
|
||||||
label: "测试页面",
|
|
||||||
icon: <ExperimentOutlined />,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default menuItems;
|
|
||||||
|
|
||||||
/** 扁平化菜单 */
|
|
||||||
export function flattenMenu(items) {
|
|
||||||
const result = [];
|
|
||||||
function walk(list) {
|
|
||||||
for (const item of list) {
|
|
||||||
result.push(item);
|
|
||||||
if (item.children) walk(item.children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
walk(items);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据路径查找面包屑路径
|
|
||||||
* 返回从根到叶子节点的菜单项数组
|
|
||||||
*/
|
|
||||||
export function findMenuPath(path) {
|
|
||||||
function search(items, ancestors) {
|
|
||||||
for (const item of items) {
|
|
||||||
const current = [...ancestors, item];
|
|
||||||
if (item.key === path) {
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
if (item.children) {
|
|
||||||
const found = search(item.children, current);
|
|
||||||
if (found) return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return search(menuItems, []) || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据路径获取页面标签名
|
|
||||||
*/
|
|
||||||
export function getPageLabel(path) {
|
|
||||||
const flat = flattenMenu(menuItems);
|
|
||||||
const item = flat.find((m) => m.key === path);
|
|
||||||
return item?.label || path.split("/").filter(Boolean).pop() || "未命名页面";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据路径获取默认展开的菜单项
|
|
||||||
*/
|
|
||||||
export function getOpenKeys(path) {
|
|
||||||
const breadcrumb = findMenuPath(path);
|
|
||||||
return breadcrumb.slice(0, -1).map((i) => i.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据路径获取选中的菜单项
|
|
||||||
*/
|
|
||||||
export function getSelectedKeys(path) {
|
|
||||||
const allPaths = flattenMenu(menuItems).map((m) => m.key);
|
|
||||||
let match = "";
|
|
||||||
for (const p of allPaths) {
|
|
||||||
if (path.startsWith(p) && p.length > match.length) {
|
|
||||||
match = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return match ? [match] : [];
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import EnterpriseLicenseList from "~/pages/Container/Supervision/EnterpriseLicense/EnterpriseLicense";
|
|
||||||
|
|
||||||
function EnterpriseLicense(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<EnterpriseLicenseList
|
|
||||||
props={props}
|
|
||||||
permissionAdd="xgfd-qyzzgl-add"
|
|
||||||
permissionEdit="xgfd-qyzzgl-edit"
|
|
||||||
permissionView="xgfd-qyzzgl-info"
|
|
||||||
permissionDel="xgfd-qyzzgl-del"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EnterpriseLicense;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业主要负责人管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
personnelType="zyfzr"
|
|
||||||
permissionAdd="xgfd-zyfzrgl-add"
|
|
||||||
permissionEdit="xgfd-zyfzrgl-edit"
|
|
||||||
permissionView="xgfd-zyfzrgl-info"
|
|
||||||
permissionDel="xgfd-zyfzrgl-del"
|
|
||||||
dictionaryType="zyfzrgwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonInCharge(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonInCharge;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业安全生产管理人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
personnelType="aqscglry"
|
|
||||||
permissionAdd="xgfd-aqscglrygl-add"
|
|
||||||
permissionEdit="xgfd-aqscglrygl-edit"
|
|
||||||
permissionView="xgfd-aqscglrygl-info"
|
|
||||||
permissionDel="xgfd-aqscglrygl-del"
|
|
||||||
dictionaryType="aqscglrygwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SecurityAdmini(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SecurityAdmini;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
import {Permission} from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
// 企业特种设备操作人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
personnelType="tzsbczry"
|
|
||||||
permissionAdd="xgfd-tzzzsbczrygl-add"
|
|
||||||
permissionEdit="xgfd-tzzzsbczrygl-edit"
|
|
||||||
permissionView="xgfd-tzzzsbczrygl-info"
|
|
||||||
permissionDel="xgfd-tzzzsbczrygl-del"
|
|
||||||
dictionaryType="tzsbczryczxmzylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialEquipment(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialEquipment;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种作业人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
personnelType="tezhongzuoye"
|
|
||||||
permissionAdd="xgfd-tzzyrugl-add"
|
|
||||||
permissionEdit="xgfd-tzzyrugl-edit"
|
|
||||||
permissionView="xgfd-tzzyrugl-info"
|
|
||||||
permissionDel="xgfd-tzzyrugl-del"
|
|
||||||
dictionaryType="tzzyryhylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialPersonnel(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialPersonnel;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonnelLicense(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonnelLicense;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function EnterpriseLicenseManage(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EnterpriseLicenseManage;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function Stakeholder(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Stakeholder;
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, Space } from "antd";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import { NS_CORP_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["corpCertificateStatPage"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
corpType: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "corpName",
|
|
||||||
label: "公司名称",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "公司名称",
|
|
||||||
dataIndex: "corpName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书数量",
|
|
||||||
dataIndex: "certCount",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 200,
|
|
||||||
hidden: !props.permission("gfd-zgsztj-info"),
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./View?corpinfoId=${record.corpId}`)}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Connect([NS_CORP_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import EnterpriseLicense from "../../EnterpriseLicense";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<EnterpriseLicense
|
|
||||||
props={props}
|
|
||||||
type="View"
|
|
||||||
permissionView="gfd-zgsztj-insideInfo"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default View;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function BranchStatistics(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BranchStatistics;
|
|
||||||
|
|
@ -1,600 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Descriptions, Form, message, Modal, Space } from "antd";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
|
||||||
import AddIcon from "zy-react-library/components/Icon/AddIcon";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PreviewImg from "zy-react-library/components/PreviewImg";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
import TooltipPreviewImg from "zy-react-library/components/TooltipPreviewImg";
|
|
||||||
import Upload from "zy-react-library/components/Upload";
|
|
||||||
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
|
||||||
|
|
||||||
import { UPLOAD_FILE_TYPE_ENUM } from "zy-react-library/enum/uploadFile/gwj";
|
|
||||||
import useDeleteFile from "zy-react-library/hooks/useDeleteFile";
|
|
||||||
import useGetFile from "zy-react-library/hooks/useGetFile";
|
|
||||||
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import useUploadFile from "zy-react-library/hooks/useUploadFile";
|
|
||||||
import { NS_CORP_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
import { useDebounce } from "~/utils";
|
|
||||||
|
|
||||||
function EnterpriseLicense(props) {
|
|
||||||
const [addModalOpen, setAddModalOpen] = useState(false);
|
|
||||||
const [viewModalOpen, setViewModalOpen] = useState(false);
|
|
||||||
const [currentId, setCurrentId] = useState("");
|
|
||||||
const queryParams = useGetUrlQuery();
|
|
||||||
|
|
||||||
const permissionAdd = props.permissionAdd ? props.permissionAdd : "gfd-qyzzgl-add";
|
|
||||||
const permissionEdit = props.permissionEdit ? props.permissionEdit : "gfd-qyzzgl-edit";
|
|
||||||
const permissionView = props.permissionView ? props.permissionView : "gfd-qyzzgl-info";
|
|
||||||
const permissionDel = props.permissionDel ? props.permissionDel : "gfd-qyzzgl-del";
|
|
||||||
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["corpCertificateList"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
geCertificateDateStart: formData.certificateDate?.[0],
|
|
||||||
leCertificateDateEnd: formData.certificateDate?.[1],
|
|
||||||
eqCorpinfoId: queryParams["corpinfoId"],
|
|
||||||
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const onDelete = (id) => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: "确定删除吗?",
|
|
||||||
onOk: () => {
|
|
||||||
props["corpCertificateRemove"]({
|
|
||||||
id,
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
message.success("删除成功");
|
|
||||||
getData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
getData();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const [fileCache, setFileCache] = useState({});
|
|
||||||
const [loadingKeys, setLoadingKeys] = useState(new Set());
|
|
||||||
const pendingLoadIdsRef = useRef(new Set());
|
|
||||||
const requestQueueRef = useRef([]);
|
|
||||||
const activeRequestsRef = useRef(0);
|
|
||||||
const MAX_CONCURRENT_REQUESTS = 3; // 最大并发请求数
|
|
||||||
|
|
||||||
const processQueue = () => {
|
|
||||||
while (
|
|
||||||
requestQueueRef.current.length > 0
|
|
||||||
&& activeRequestsRef.current < MAX_CONCURRENT_REQUESTS
|
|
||||||
) {
|
|
||||||
const { id, resolve, reject } = requestQueueRef.current.shift();
|
|
||||||
activeRequestsRef.current++;
|
|
||||||
|
|
||||||
getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM["6"],
|
|
||||||
eqForeignKey: id,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
setFileCache(prev => ({
|
|
||||||
...prev,
|
|
||||||
[id]: res || [],
|
|
||||||
}));
|
|
||||||
resolve(res);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
reject(err);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
activeRequestsRef.current--;
|
|
||||||
setLoadingKeys((prev) => {
|
|
||||||
const newSet = new Set(prev);
|
|
||||||
newSet.delete(id);
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
processQueue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadFileForRecord = (userQualificationinfoId) => {
|
|
||||||
if (!userQualificationinfoId)
|
|
||||||
return Promise.resolve();
|
|
||||||
if (fileCache[userQualificationinfoId])
|
|
||||||
return Promise.resolve();
|
|
||||||
if (loadingKeys.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
if (pendingLoadIdsRef.current.has(userQualificationinfoId))
|
|
||||||
return Promise.resolve();
|
|
||||||
|
|
||||||
pendingLoadIdsRef.current.add(userQualificationinfoId);
|
|
||||||
setLoadingKeys(prev => new Set([...prev, userQualificationinfoId]));
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
requestQueueRef.current.push({ id: userQualificationinfoId, resolve, reject });
|
|
||||||
processQueue();
|
|
||||||
}).finally(() => {
|
|
||||||
pendingLoadIdsRef.current.delete(userQualificationinfoId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 缓存数据变化时清空图片缓存
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
const currentIds = new Set(tableProps.dataSource.map(item => item.corpCertificateId).filter(Boolean));
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = {};
|
|
||||||
Object.keys(prev).forEach((id) => {
|
|
||||||
if (currentIds.has(id)) {
|
|
||||||
newCache[id] = prev[id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
|
|
||||||
// 记录已经触发过加载的 ID,避免 render 重复触发
|
|
||||||
const triggeredLoadIdsRef = useRef(new Set());
|
|
||||||
useEffect(() => {
|
|
||||||
if (tableProps.dataSource) {
|
|
||||||
tableProps.dataSource.forEach((record) => {
|
|
||||||
const id = record.corpCertificateId;
|
|
||||||
if (id && !triggeredLoadIdsRef.current.has(id)) {
|
|
||||||
triggeredLoadIdsRef.current.add(id);
|
|
||||||
loadFileForRecord(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 组件卸载或数据源变化时重置
|
|
||||||
return () => {
|
|
||||||
triggeredLoadIdsRef.current.clear();
|
|
||||||
};
|
|
||||||
}, [tableProps.dataSource]);
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "likeCertificateName",
|
|
||||||
label: "证书名称",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateDate",
|
|
||||||
label: "证书有效期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
loding={getFileLoading}
|
|
||||||
toolBarRender={() => (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
(!props.type && props.permission(permissionAdd))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
icon={<AddIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
columns={[
|
|
||||||
|
|
||||||
{
|
|
||||||
title: "证书名称",
|
|
||||||
dataIndex: "certificateName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书编号",
|
|
||||||
dataIndex: "certificateCode",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书有效期",
|
|
||||||
dataIndex: "certificateNo",
|
|
||||||
width: 370,
|
|
||||||
render: (_, record) =>
|
|
||||||
<div>{`${record.certificateDateStart ?? ""} - ${record.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
title: "图片",
|
|
||||||
render: (_, record) => {
|
|
||||||
const id = record.corpCertificateId;
|
|
||||||
const files = fileCache[id] || [];
|
|
||||||
|
|
||||||
if (!files.length)
|
|
||||||
return <span>无</span>;
|
|
||||||
return <TooltipPreviewImg files={files} />;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 200,
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
{
|
|
||||||
props.permission(permissionView)
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => {
|
|
||||||
setViewModalOpen(true);
|
|
||||||
setCurrentId(record.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
(!props.type && props.permission(permissionEdit))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => {
|
|
||||||
setAddModalOpen(true);
|
|
||||||
setCurrentId(record.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
(!props.type && props.permission(permissionDel))
|
|
||||||
&& (
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
type="link"
|
|
||||||
onClick={() => onDelete(record.id)}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{addModalOpen && (
|
|
||||||
<AddModal
|
|
||||||
open={addModalOpen}
|
|
||||||
loding={props.corpCertificate.corpCertificateLoading}
|
|
||||||
getData={getData}
|
|
||||||
currentId={currentId}
|
|
||||||
requestAdd={props["corpCertificateAdd"]}
|
|
||||||
requestEdit={props["corpCertificateEdit"]}
|
|
||||||
requestDetails={props["corpCertificateInfo"]}
|
|
||||||
corpCertificateIsExistCertNo={props["corpCertificateIsExistCertNo"]}
|
|
||||||
onCancel={() => {
|
|
||||||
setAddModalOpen(false);
|
|
||||||
setCurrentId("");
|
|
||||||
}}
|
|
||||||
onSuccess={(userQualificationinfoId) => {
|
|
||||||
// 清除该记录的图片缓存,强制下次 render 时重新加载
|
|
||||||
setFileCache((prev) => {
|
|
||||||
const newCache = { ...prev };
|
|
||||||
delete newCache[userQualificationinfoId];
|
|
||||||
return newCache;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{viewModalOpen && (
|
|
||||||
<ViewModal
|
|
||||||
open={viewModalOpen}
|
|
||||||
loding={props.corpCertificate.corpCertificateLoading}
|
|
||||||
getData={getData}
|
|
||||||
currentId={currentId}
|
|
||||||
requestDetails={props["corpCertificateInfo"]}
|
|
||||||
onCancel={() => {
|
|
||||||
setViewModalOpen(false);
|
|
||||||
setCurrentId("");
|
|
||||||
}}
|
|
||||||
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function AddModalComponent(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const [userQualificationinfoId, setUserQualificationinfoId] = useState("");
|
|
||||||
|
|
||||||
const { loading: deleteFileLoading, deleteFile } = useDeleteFile();
|
|
||||||
const { loading: uploadFileLoading, uploadFile } = useUploadFile();
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
const [deleteCardImageFiles, setDeleteCardImageFiles] = useState([]);
|
|
||||||
const [CertificateCodeValue, setPertificateCodeValue] = useState(null);
|
|
||||||
const [isSubmit, setIsSubmit] = useState(true);
|
|
||||||
const debouncedCertificateCodeValue = useDebounce(CertificateCodeValue, 100);
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.currentId) {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const { data } = await props.requestDetails({
|
|
||||||
id: props.currentId,
|
|
||||||
});
|
|
||||||
|
|
||||||
data.certificateDate = [data.certificateDateStart, data.certificateDateEnd];
|
|
||||||
const certificateImgs = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM["6"],
|
|
||||||
eqForeignKey: data.corpCertificateId,
|
|
||||||
});
|
|
||||||
data.certificateImgs = certificateImgs;
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setUserQualificationinfoId(data.corpCertificateId);
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
}, [props.currentId]);
|
|
||||||
const onCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
props.onCancel();
|
|
||||||
};
|
|
||||||
const onSubmit = async (values) => {
|
|
||||||
await deleteFile({
|
|
||||||
single: false,
|
|
||||||
files: deleteCardImageFiles,
|
|
||||||
});
|
|
||||||
values.certificateDateStart = values.certificateDate[0];
|
|
||||||
values.certificateDateEnd = values.certificateDate[1];
|
|
||||||
|
|
||||||
if (!isSubmit) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = await uploadFile({
|
|
||||||
single: false,
|
|
||||||
files: values.certificateImgs,
|
|
||||||
params: {
|
|
||||||
type: UPLOAD_FILE_TYPE_ENUM["6"],
|
|
||||||
foreignKey: userQualificationinfoId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (props.currentId) {
|
|
||||||
values.id = props.currentId;
|
|
||||||
values.corpCertificateId = userQualificationinfoId;
|
|
||||||
|
|
||||||
await props.requestEdit(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
message.success("编辑成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
values.corpCertificateId = id;
|
|
||||||
await props.requestAdd(values).then((res) => {
|
|
||||||
if (res.success) {
|
|
||||||
onCancel();
|
|
||||||
props.getData();
|
|
||||||
message.success("新增成功");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 校验重复
|
|
||||||
useEffect(() => {
|
|
||||||
if (!debouncedCertificateCodeValue) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
props["corpCertificateIsExistCertNo"]({
|
|
||||||
certNo: debouncedCertificateCodeValue,
|
|
||||||
id: props.currentId ?? "",
|
|
||||||
}).then((res) => {
|
|
||||||
if (res.data) {
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
errors: ["证书编号重复"],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
setIsSubmit(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setIsSubmit(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [debouncedCertificateCodeValue]);
|
|
||||||
|
|
||||||
const onValuesChange = (changedValues) => {
|
|
||||||
if ("certificateCode" in changedValues) {
|
|
||||||
setPertificateCodeValue(changedValues.certificateCode ?? "");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={props.open}
|
|
||||||
maskClosable={false}
|
|
||||||
title={props.currentId ? "编辑" : "新增"}
|
|
||||||
width={800}
|
|
||||||
confirmLoading={
|
|
||||||
deleteFileLoading || uploadFileLoading || getFileLoading || props.loding
|
|
||||||
}
|
|
||||||
onOk={form.submit}
|
|
||||||
onCancel={onCancel}
|
|
||||||
>
|
|
||||||
<FormBuilder
|
|
||||||
form={form}
|
|
||||||
span={24}
|
|
||||||
onValuesChange={onValuesChange}
|
|
||||||
values={{
|
|
||||||
securityFlag: 0,
|
|
||||||
}}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "certificateName",
|
|
||||||
label: "证书名称",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateDate",
|
|
||||||
label: "证书有效期",
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE_RANGE,
|
|
||||||
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
const allEmptyStrings = Array.isArray(value) && value.every(item => item === "");
|
|
||||||
if (allEmptyStrings) {
|
|
||||||
return Promise.reject(new Error("请选择有效期"));
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateCode",
|
|
||||||
label: "证书编号",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "remark",
|
|
||||||
label: "备注",
|
|
||||||
required: false,
|
|
||||||
render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "certificateImgs",
|
|
||||||
label: "证书图片",
|
|
||||||
render: (
|
|
||||||
<Upload
|
|
||||||
|
|
||||||
maxCount={3}
|
|
||||||
onGetRemoveFile={(file) => {
|
|
||||||
setDeleteCardImageFiles([...deleteCardImageFiles, file]);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
labelCol={{
|
|
||||||
span: 10,
|
|
||||||
}}
|
|
||||||
showActionButtons={false}
|
|
||||||
onFinish={onSubmit}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const AddModal = AddModalComponent;
|
|
||||||
|
|
||||||
function ViewModalComponent(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
const [info, setInfo] = useState({});
|
|
||||||
|
|
||||||
const { loading: getFileLoading, getFile } = useGetFile();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (props.currentId) {
|
|
||||||
const fetchData = async () => {
|
|
||||||
const { data } = await props.requestDetails({
|
|
||||||
id: props.currentId,
|
|
||||||
});
|
|
||||||
const certificateImgs = await getFile({
|
|
||||||
eqType: UPLOAD_FILE_TYPE_ENUM["6"],
|
|
||||||
eqForeignKey: data.corpCertificateId,
|
|
||||||
});
|
|
||||||
|
|
||||||
data.certificateImgs = certificateImgs;
|
|
||||||
setInfo(data);
|
|
||||||
};
|
|
||||||
fetchData();
|
|
||||||
}
|
|
||||||
}, [props.currentId]);
|
|
||||||
const onCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
props.onCancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={props.open}
|
|
||||||
maskClosable={false}
|
|
||||||
title="查看"
|
|
||||||
width={800}
|
|
||||||
cancelText="关闭"
|
|
||||||
okButtonProps={{
|
|
||||||
style: {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
confirmLoading={
|
|
||||||
getFileLoading || props.loding
|
|
||||||
}
|
|
||||||
|
|
||||||
onCancel={onCancel}
|
|
||||||
>
|
|
||||||
<Descriptions
|
|
||||||
size="middle"
|
|
||||||
bordered
|
|
||||||
labelStyle={{ width: 200 }}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: "证书名称",
|
|
||||||
children: info.certificateName,
|
|
||||||
span: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证书有效期",
|
|
||||||
children: <div>{`${info.certificateDateStart ?? ""} - ${info.certificateDateEnd ?? ""}`}</div>,
|
|
||||||
span: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证书编号",
|
|
||||||
children: info.certificateCode,
|
|
||||||
span: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "备注",
|
|
||||||
children: info.remark,
|
|
||||||
span: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "证书图片",
|
|
||||||
children: <PreviewImg files={info.certificateImgs} />,
|
|
||||||
span: 4,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const ViewModal = ViewModalComponent;
|
|
||||||
export default Connect([NS_CORP_CERTIFICATE], true)(Permission(EnterpriseLicense));
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, Space } from "antd";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import { NS_CORP_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["corpCertificateStatPage"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
corpType: 1,
|
|
||||||
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "corpName",
|
|
||||||
label: "公司名称",
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "公司名称",
|
|
||||||
dataIndex: "corpName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "证书数量",
|
|
||||||
dataIndex: "certCount",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 200,
|
|
||||||
hidden: !props.permission("gfd-xgfztj-info"),
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./View?corpinfoId=${record.corpId}`)}
|
|
||||||
>
|
|
||||||
查看
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Connect([NS_CORP_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import EnterpriseLicense from "../../EnterpriseLicense";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<EnterpriseLicense
|
|
||||||
props={props}
|
|
||||||
type="View"
|
|
||||||
permissionView="gfd-xgfztj-insideInfo"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default View;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function StakeholderStatistics(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default StakeholderStatistics;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function EnterpriseLicenseManage(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EnterpriseLicenseManage;
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, Space } from "antd";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["userCertificateStatPage"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
corpType: 0,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "corpName",
|
|
||||||
label: "公司名称",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "公司名称",
|
|
||||||
dataIndex: "corpName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "特种作业人员证书数",
|
|
||||||
dataIndex: "specialWorkCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./SpecialPersonnel/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-fzgsryzztj-tzzyInfo")}
|
|
||||||
>
|
|
||||||
{record.specialWorkCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "特种设备操作人员证书数",
|
|
||||||
dataIndex: "specialEquipmentCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./SpecialDevice/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-fzgsryzztj-tzsbInfo")}
|
|
||||||
>
|
|
||||||
{record.specialEquipmentCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "主要负责人证书数",
|
|
||||||
dataIndex: "principalCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./PersonInCharge/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-fzgsryzztj-zyfzrInfo")}
|
|
||||||
>
|
|
||||||
{record.principalCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "安全生产管理人员证书数",
|
|
||||||
dataIndex: "safetyManagerCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./SecurityAdmini/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-fzgsryzztj-aqgly-info")}
|
|
||||||
>
|
|
||||||
{record.safetyManagerCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业主要负责人管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<Page headerTitle="主要负责人证书数" isShowFooter={false}>
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
displayType="View"
|
|
||||||
personnelType="zyfzr"
|
|
||||||
permissionView="gfd-fzgsryzztj-zyfzrInfoNb"
|
|
||||||
dictionaryType="zyfzrgwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonInCharge(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonInCharge;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业安全生产管理人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<Page headerTitle="安全生产管理人员证书数" isShowFooter={false}>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
displayType="View"
|
|
||||||
personnelType="aqscglry"
|
|
||||||
permissionView="gfd-fzgsryzztj-aqgly-infoNb"
|
|
||||||
dictionaryType="aqscglrygwmc0000"
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SecurityAdmini(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SecurityAdmini;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种设备操作人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<Page headerTitle="特种设备操作人员证书数" isShowFooter={false}>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
displayType="View"
|
|
||||||
personnelType="tzsbczry"
|
|
||||||
permissionView="gfd-fzgsryzztj-tzsbInfoNb"
|
|
||||||
dictionaryType="tzsbczryczxmzylb0000"
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialEquipment(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialEquipment;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种作业人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<Page headerTitle="特种作业人员证书数" isShowFooter={false}>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
displayType="View"
|
|
||||||
personnelType="tezhongzuoye"
|
|
||||||
permissionView="gfd-fzgsryzztj-tzzyInfoNb"
|
|
||||||
dictionaryType="tzzyryhylb0000"
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialPersonnel(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialPersonnel;
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function BranchCompanyStat(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BranchCompanyStat;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业主要负责人管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
personnelType="zyfzr"
|
|
||||||
permissionAdd="gfd-qyzyfzrgl-add"
|
|
||||||
permissionEdit="gfd-qyzyfzrgl-edit"
|
|
||||||
permissionView="gfd-qyzyfzrgl-info"
|
|
||||||
permissionDel="gfd-qyzyfzrgl-del"
|
|
||||||
dictionaryType="zyfzrgwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function PersonInCharge(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PersonInCharge;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业安全生产管理人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
personnelType="aqscglry"
|
|
||||||
permissionAdd="gfd-qyaqscglrygl-add"
|
|
||||||
permissionEdit="gfd-qyaqscglrygl-edit"
|
|
||||||
permissionView="gfd-qyaqscglrygl-info"
|
|
||||||
permissionDel="gfd-qyaqscglrygl-del"
|
|
||||||
dictionaryType="aqscglrygwmc0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import PersonInChargeInfo from "~/components/PersonInChargeInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<PersonInChargeInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={162}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SecurityAdmini(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SecurityAdmini;
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种设备操作人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
personnelType="tzsbczry"
|
|
||||||
permissionAdd="gfd-tzsbczrygl-add"
|
|
||||||
permissionEdit="gfd-tzsbczrygl-edit"
|
|
||||||
permissionView="gfd-tzsbczrygl-info"
|
|
||||||
permissionDel="gfd-tzsbczrygl-del"
|
|
||||||
dictionaryType="tzsbczryczxmzylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={160}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialEquipment(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialEquipment;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateList from "~/components/SpecialCertificateList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业特种作业人员管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
personnelType="tezhongzuoye"
|
|
||||||
permissionAdd="gfd-tzzyrugl-add"
|
|
||||||
permissionEdit="gfd-tzzyrugl-edit"
|
|
||||||
permissionView="gfd-tzzyrugl-info"
|
|
||||||
permissionDel="gfd-tzzyrugl-del"
|
|
||||||
dictionaryType="tzzyryhylb0000"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import SpecialCertificateInfo from "~/components/SpecialCertificateInfo";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function View(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SpecialCertificateInfo
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={159}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(View);
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
function SpecialPersonnel(props) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SpecialPersonnel;
|
|
||||||
|
|
@ -1,119 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import { Button, Form, Space } from "antd";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import Search from "zy-react-library/components/Search";
|
|
||||||
import Table from "zy-react-library/components/Table";
|
|
||||||
|
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
|
|
||||||
function List(props) {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const { tableProps, getData } = useTable(props["userCertificateStatPage"], {
|
|
||||||
form,
|
|
||||||
transform: (formData) => {
|
|
||||||
return {
|
|
||||||
...formData,
|
|
||||||
corpType: 1,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page isShowAllAction={false}>
|
|
||||||
|
|
||||||
<Search
|
|
||||||
form={form}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
name: "corpName",
|
|
||||||
label: "公司名称",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onFinish={getData}
|
|
||||||
/>
|
|
||||||
<Table
|
|
||||||
columns={[
|
|
||||||
{
|
|
||||||
title: "公司名称",
|
|
||||||
dataIndex: "corpName",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "特种作业人员证书数",
|
|
||||||
dataIndex: "specialWorkCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
|
|
||||||
disabled={!props.permission("gfd-xgfryzztj-tzzyInfo")}
|
|
||||||
onClick={() => props.history.push(`./SpecialPersonnel/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
>
|
|
||||||
{record.specialWorkCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "特种设备操作人员证书数",
|
|
||||||
dataIndex: "specialEquipmentCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./SpecialDevice/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-xgfryzztj-tzsbInfo")}
|
|
||||||
>
|
|
||||||
{record.specialEquipmentCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "主要负责人证书数",
|
|
||||||
dataIndex: "principalCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./PersonInCharge/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-xgfryzztj-zyfzrInfo")}
|
|
||||||
>
|
|
||||||
{record.principalCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "安全生产管理人员证书数",
|
|
||||||
dataIndex: "safetyManagerCertCount",
|
|
||||||
render: (_, record) => (
|
|
||||||
<Space>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => props.history.push(`./SecurityAdmini/List?corpinfoId=${record.corpinfoId}`)}
|
|
||||||
disabled={!props.permission("gfd-xgfryzztj-aqscInfo")}
|
|
||||||
>
|
|
||||||
{record.safetyManagerCertCount}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
|
|
||||||
]}
|
|
||||||
{...tableProps}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
|
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
||||||
import Page from "zy-react-library/components/Page";
|
|
||||||
import PersonInChargeList from "~/components/PersonInChargeList";
|
|
||||||
import { NS_USER_CERTIFICATE } from "~/enumerate/namespace";
|
|
||||||
// 企业主要负责人管理
|
|
||||||
function List(props) {
|
|
||||||
return (
|
|
||||||
<Page headerTitle="主要负责人证书数" isShowFooter={false}>
|
|
||||||
<PersonInChargeList
|
|
||||||
props={props}
|
|
||||||
certificatePhotoType={161}
|
|
||||||
displayType="View"
|
|
||||||
personnelType="zyfzr"
|
|
||||||
permissionView="gfd-xgfryzztj-zyfzrInfoNb"
|
|
||||||
dictionaryType="zyfzrgwmc0000"
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Connect([NS_USER_CERTIFICATE], true)(Permission(List));
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue