init
commit
1476e3276e
|
|
@ -0,0 +1,13 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# production
|
||||
/dist
|
||||
/demo
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.idea
|
||||
yarn.lock
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
# 微应用模板说明文档
|
||||
|
||||
## 在线文档
|
||||
|
||||
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`。
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
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",
|
||||
"react/no-implicit-key": "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"],
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
module.exports = {
|
||||
compact: false,
|
||||
// 插件
|
||||
plugins: [
|
||||
[
|
||||
"@babel/plugin-proposal-decorators",
|
||||
{
|
||||
legacy: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
// 预设
|
||||
presets: [
|
||||
["@babel/preset-env", {
|
||||
targets: {
|
||||
browsers: ["ie >= 10"],
|
||||
},
|
||||
}],
|
||||
["@babel/preset-react", {
|
||||
runtime: "automatic",
|
||||
}],
|
||||
],
|
||||
};
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
module.exports = {
|
||||
// 应用后端git地址,部署上线需要
|
||||
javaGit: "<git-url>",
|
||||
// 应用后端仓库名称,部署上线需要
|
||||
javaGitName: "<git-name>",
|
||||
// 环境配置
|
||||
environment: {
|
||||
development: {
|
||||
// 应用后端分支名称,部署上线需要
|
||||
javaGitBranch: "<branch-name>",
|
||||
// 接口服务地址
|
||||
API_HOST: "https://gbs-gateway.qhdsafety.com",
|
||||
},
|
||||
production: {
|
||||
// 应用后端分支名称,部署上线需要
|
||||
javaGitBranch: "<branch-name>",
|
||||
// 接口服务地址
|
||||
API_HOST: "",
|
||||
},
|
||||
},
|
||||
// 应用唯一标识符
|
||||
appIdentifier: "proDispatch",
|
||||
// 应用上下文注入全局变量
|
||||
contextInject: {
|
||||
// 应用Key
|
||||
appKey: "",
|
||||
},
|
||||
// public/index.html注入全局变量
|
||||
windowInject: {
|
||||
// 应用标题
|
||||
title: "微应用模板",
|
||||
// 注入css链接集合
|
||||
links: [],
|
||||
element: {
|
||||
root: {
|
||||
// 挂载DOM元素ID
|
||||
id: "root",
|
||||
},
|
||||
},
|
||||
// 注入js链接集合
|
||||
scripts: [],
|
||||
},
|
||||
// 开发服务
|
||||
server: {
|
||||
// 监听端口号
|
||||
port: "8088",
|
||||
// 服务地址
|
||||
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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src",
|
||||
"paths": {
|
||||
"~/*": ["*"]
|
||||
},
|
||||
"jsx": "react"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "micro-app",
|
||||
"version": "2.0.0",
|
||||
"description": "建教帮微应用模板",
|
||||
"author": "JJB",
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"serve": "node node_modules/@cqsjjb/scripts/webpack.dev.server.js",
|
||||
"build": "node node_modules/@cqsjjb/scripts/webpack.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": {
|
||||
"@ahooksjs/use-url-state": "^3.5.1",
|
||||
"@ant-design/icons": "^5.6.1",
|
||||
"@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",
|
||||
"ahooks": "^3.9.5",
|
||||
"antd": "^5.27.6",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mockjs": "^1.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"throttle-debounce": "^5.0.2",
|
||||
"zy-react-library": "^1.3.31"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^5.4.1",
|
||||
"@babel/plugin-proposal-decorators": "^7.19.3",
|
||||
"@cqsjjb/scripts": "2.0.0-alpha-1",
|
||||
"@eslint-react/eslint-plugin": "^2.2.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9.37.0",
|
||||
"eslint-plugin-format": "^1.0.2",
|
||||
"eslint-plugin-react-hooks": "^7.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.23",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<!--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">
|
||||
<meta charset="UTF-8" name="referrer" content="strict-origin-when-cross-origin"/>
|
||||
<% 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>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# 生产派工管理路由规划
|
||||
|
||||
## 派工工单管理
|
||||
|
||||
### 人员派工
|
||||
|
||||
- 生产派工
|
||||
`/proDispatch/container/personnelDispatch/productionDispatch`
|
||||
- 清扫派工
|
||||
`/proDispatch/container/personnelDispatch/cleaningDispatch`
|
||||
|
||||
### 车辆派工
|
||||
|
||||
- 生产派工
|
||||
`/proDispatch/container/vehicleDispatch/productionDispatch`
|
||||
- 清扫派工
|
||||
`/proDispatch/container/vehicleDispatch/cleaningDispatch`
|
||||
|
||||
## 设备管理
|
||||
|
||||
- 内部设备管理
|
||||
`/proDispatch/container/deviceManagement/internalDevice`
|
||||
- 相关方设备管理
|
||||
`/proDispatch/container/deviceManagement/partnerDevice`
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
// 当前接口地址仅用于原型阶段的本地请求拦截,收到正式接口文档后需按文档替换。
|
||||
export const internalDeviceList = declareRequest(
|
||||
"internalDeviceLoading",
|
||||
"Post > @/production-dispatch/device/internal/list",
|
||||
);
|
||||
|
||||
export const internalDeviceSync = declareRequest(
|
||||
"internalDeviceSyncLoading",
|
||||
"Post > @/production-dispatch/device/internal/sync",
|
||||
);
|
||||
|
||||
export const partnerDeviceList = declareRequest(
|
||||
"partnerDeviceLoading",
|
||||
"Post > @/production-dispatch/device/partner/list",
|
||||
);
|
||||
|
||||
export const partnerDeviceSync = declareRequest(
|
||||
"partnerDeviceSyncLoading",
|
||||
"Post > @/production-dispatch/device/partner/sync",
|
||||
);
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
// 当前接口地址仅用于原型阶段的本地请求拦截,收到正式接口文档后需按文档替换。
|
||||
export const productionDispatchList = declareRequest(
|
||||
"productionDispatchLoading",
|
||||
"Post > @/production-dispatch/personnel/production/list",
|
||||
);
|
||||
|
||||
export const productionDispatchApproval = declareRequest(
|
||||
"productionDispatchApprovalLoading",
|
||||
"Post > @/production-dispatch/personnel/production/approval",
|
||||
);
|
||||
|
||||
export const productionDispatchSync = declareRequest(
|
||||
"productionDispatchSyncLoading",
|
||||
"Post > @/production-dispatch/personnel/production/sync",
|
||||
);
|
||||
|
||||
export const cleaningDispatchList = declareRequest(
|
||||
"cleaningDispatchLoading",
|
||||
"Post > @/production-dispatch/personnel/cleaning/list",
|
||||
);
|
||||
|
||||
export const cleaningDispatchApproval = declareRequest(
|
||||
"cleaningDispatchApprovalLoading",
|
||||
"Post > @/production-dispatch/personnel/cleaning/approval",
|
||||
);
|
||||
|
||||
export const cleaningDispatchSync = declareRequest(
|
||||
"cleaningDispatchSyncLoading",
|
||||
"Post > @/production-dispatch/personnel/cleaning/sync",
|
||||
);
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
// 当前接口地址仅用于原型阶段的本地请求拦截,收到正式接口文档后需按文档替换。
|
||||
export const productionDispatchList = declareRequest(
|
||||
"productionDispatchLoading",
|
||||
"Post > @/production-dispatch/vehicle/production/list",
|
||||
);
|
||||
|
||||
export const productionDispatchApproval = declareRequest(
|
||||
"productionDispatchApprovalLoading",
|
||||
"Post > @/production-dispatch/vehicle/production/approval",
|
||||
);
|
||||
|
||||
export const productionDispatchSync = declareRequest(
|
||||
"productionDispatchSyncLoading",
|
||||
"Post > @/production-dispatch/vehicle/production/sync",
|
||||
);
|
||||
|
||||
export const cleaningDispatchList = declareRequest(
|
||||
"cleaningDispatchLoading",
|
||||
"Post > @/production-dispatch/vehicle/cleaning/list",
|
||||
);
|
||||
|
||||
export const cleaningDispatchApproval = declareRequest(
|
||||
"cleaningDispatchApprovalLoading",
|
||||
"Post > @/production-dispatch/vehicle/cleaning/approval",
|
||||
);
|
||||
|
||||
export const cleaningDispatchSync = declareRequest(
|
||||
"cleaningDispatchSyncLoading",
|
||||
"Post > @/production-dispatch/vehicle/cleaning/sync",
|
||||
);
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import { Button, Descriptions, Divider, Modal } from "antd";
|
||||
|
||||
export default function DeviceDetailModal(props) {
|
||||
const { onClose, record, unitLabel } = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={`${record.deviceName} 设备详情`}
|
||||
width={720}
|
||||
open
|
||||
footer={<Button onClick={onClose}>关闭</Button>}
|
||||
maskClosable={false}
|
||||
onCancel={onClose}
|
||||
>
|
||||
<Divider orientation="left">设备基础信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "deviceNo", label: "设备编号", children: record.deviceNo },
|
||||
{ key: "deviceName", label: "设备名称", children: record.deviceName },
|
||||
{ key: "deviceType", label: "设备类型", children: record.deviceType },
|
||||
{ key: "unit", label: unitLabel, children: record.unit },
|
||||
{ key: "status", label: "设备状态", children: record.status },
|
||||
{ key: "updateTime", label: "更新时间", children: record.updateTime },
|
||||
{ key: "sourceSystem", label: "来源系统", children: record.sourceSystem },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
<Divider orientation="left">定位绑定信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "gpsNo", label: "定位设备编号", children: record.gpsNo },
|
||||
{ key: "bindingObject", label: "绑定对象", children: record.bindingObject },
|
||||
{ key: "relatedVehicle", label: "关联车辆", children: record.relatedVehicle },
|
||||
{ key: "location", label: "当前位置", children: record.location },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
<Divider orientation="left">维护边界</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{
|
||||
key: "maintenanceBoundary",
|
||||
label: "维护说明",
|
||||
children: "设备主数据由生产派工调度系统同步,双控系统只用于监管查询、详情查看和定位绑定展示。",
|
||||
},
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
import { Button, Tag } from "antd";
|
||||
import { useState } from "react";
|
||||
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 { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
||||
import useTable from "zy-react-library/hooks/useTable";
|
||||
|
||||
import DeviceDetailModal from "~/components/DeviceDetailModal";
|
||||
import SummaryMetrics from "~/components/SummaryMetrics";
|
||||
import SyncExportActions from "~/components/SyncExportActions";
|
||||
|
||||
const selectItems = values => [...new Set(values)].map(value => ({ bianma: value, name: value }));
|
||||
|
||||
export default function DeviceManagementList(props) {
|
||||
const { listRequest, requestSync, scope, syncLoading } = props;
|
||||
const [form] = Search.useForm();
|
||||
const [currentRecord, setCurrentRecord] = useState({});
|
||||
const [detailModalOpen, setDetailModalOpen] = useState(false);
|
||||
const { tableProps, getData } = useTable(listRequest, { form });
|
||||
const partner = scope === "partner";
|
||||
const currentList = tableProps.dataSource || [];
|
||||
const locatedCount = currentList.filter(item => item.gpsNo && item.gpsNo !== "-").length;
|
||||
const normalCount = currentList.filter(item => item.status === "正常").length;
|
||||
const unitLabel = partner ? "相关方单位" : "所属单位";
|
||||
const unitItems = partner ? ["相关方清扫一队", "相关方清扫二队"] : ["流机公司", "清扫二队"];
|
||||
const statusItems = partner ? ["正常", "维修", "停用"] : ["正常"];
|
||||
|
||||
return (
|
||||
<Page isShowAllAction={false}>
|
||||
<SummaryMetrics
|
||||
items={[
|
||||
{
|
||||
label: "设备台账",
|
||||
value: tableProps.pagination?.total || 0,
|
||||
note: `当前页 ${currentList.length} 条`,
|
||||
},
|
||||
{ label: "定位绑定", value: locatedCount, note: "查看终端与绑定对象", type: "blue" },
|
||||
{ label: "正常设备", value: normalCount, note: "同步状态正常", type: "green" },
|
||||
{ label: "维护边界", value: "只读", note: "双控系统不维护设备主数据", type: "orange" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Search
|
||||
form={form}
|
||||
options={[
|
||||
{ name: "keyword", label: "关键词", placeholder: "设备编号、设备名称、绑定对象" },
|
||||
{
|
||||
name: "deviceType",
|
||||
label: "设备类型",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["定位终端", "车辆"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "unit",
|
||||
label: unitLabel,
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(unitItems),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
label: "设备状态",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(statusItems),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
]}
|
||||
onFinish={getData}
|
||||
/>
|
||||
|
||||
<Table
|
||||
toolBarRender={() => (
|
||||
<SyncExportActions
|
||||
syncText="同步设备"
|
||||
syncMessage="已同步内部与相关方设备台账"
|
||||
syncLoading={syncLoading}
|
||||
requestSync={requestSync}
|
||||
onSyncSuccess={getData}
|
||||
exportUrl={`/production-dispatch/device/${scope}/export`}
|
||||
exportName={partner ? "相关方设备管理" : "内部设备管理"}
|
||||
getExportParams={() => form.getFieldsValue()}
|
||||
/>
|
||||
)}
|
||||
columns={[
|
||||
{ title: "设备编号", dataIndex: "deviceNo", render: (_, record) => <strong>{record.deviceNo}</strong> },
|
||||
{ title: "设备名称", dataIndex: "deviceName" },
|
||||
{ title: "设备类型", dataIndex: "deviceType" },
|
||||
{ title: unitLabel, dataIndex: "unit" },
|
||||
{ title: "绑定对象", dataIndex: "bindingObject" },
|
||||
{
|
||||
title: "设备状态",
|
||||
dataIndex: "status",
|
||||
render: (_, record) => <Tag color={record.status === "正常" ? "green" : "red"}>{record.status}</Tag>,
|
||||
},
|
||||
{ title: "更新时间", dataIndex: "updateTime" },
|
||||
{
|
||||
title: "操作",
|
||||
fixed: "right",
|
||||
width: 80,
|
||||
render: (_, record) => (
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => {
|
||||
setCurrentRecord(record);
|
||||
setDetailModalOpen(true);
|
||||
}}
|
||||
>
|
||||
详情
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
]}
|
||||
showIndexColumn={false}
|
||||
{...tableProps}
|
||||
/>
|
||||
|
||||
{detailModalOpen && (
|
||||
<DeviceDetailModal
|
||||
record={currentRecord}
|
||||
unitLabel={unitLabel}
|
||||
onClose={() => {
|
||||
setDetailModalOpen(false);
|
||||
setCurrentRecord({});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,310 @@
|
|||
import { Button, Descriptions, Divider, message, Modal, Steps, Tag } from "antd";
|
||||
import FormBuilder from "zy-react-library/components/FormBuilder";
|
||||
import Table from "zy-react-library/components/Table";
|
||||
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
||||
|
||||
import DispatchMap from "~/components/DispatchMap";
|
||||
|
||||
import styles from "./index.module.less";
|
||||
|
||||
const productionWorkflowNodes = [
|
||||
"公务公司审核",
|
||||
"港务公司计划员审核",
|
||||
"港务公司业务部长审核",
|
||||
"流机计划员审核",
|
||||
"流机业务部长审核",
|
||||
"流机计划员分发",
|
||||
"流机调度员下达",
|
||||
];
|
||||
const cleaningWorkflowNodes = ["任务同步", "双控审核", "作业前确认", "派工下达", "作业后确认", "归档"];
|
||||
|
||||
function getCurrentWorkflowIndex(record, workflowNodes, cleaning) {
|
||||
if (/已下达|已完成|已通过/.test(record.approvalStatus) && !/审核中|待审/.test(record.approvalStatus)) {
|
||||
return workflowNodes.length - 1;
|
||||
}
|
||||
const currentIndex = workflowNodes.findIndex(node => record.currentRole.includes(node) || node.includes(record.currentRole));
|
||||
if (currentIndex >= 0) {
|
||||
return currentIndex;
|
||||
}
|
||||
if (cleaning && /现场值守人/.test(record.currentRole)) {
|
||||
return 2;
|
||||
}
|
||||
return record.approvalStatus === "待审" ? 0 : 1;
|
||||
}
|
||||
|
||||
function getApprovalResultColor(value) {
|
||||
if (/异常|驳回/.test(value)) {
|
||||
return "red";
|
||||
}
|
||||
if (/处理中|待审/.test(value)) {
|
||||
return "gold";
|
||||
}
|
||||
return "green";
|
||||
}
|
||||
|
||||
function getModalTitle(record, cleaning, vehicle) {
|
||||
if (cleaning && vehicle) {
|
||||
return `${record.id} 车辆清扫派工详情`;
|
||||
}
|
||||
if (cleaning) {
|
||||
return `${record.id} 清扫派工详情`;
|
||||
}
|
||||
if (vehicle) {
|
||||
return `${record.planNo} 车辆派工详情`;
|
||||
}
|
||||
return `${record.planNo} 派工详情`;
|
||||
}
|
||||
|
||||
function getWorkflowDescription(index, currentIndex) {
|
||||
if (index < currentIndex) {
|
||||
return "已处理";
|
||||
}
|
||||
if (index === currentIndex) {
|
||||
return "当前节点";
|
||||
}
|
||||
return "待流转";
|
||||
}
|
||||
|
||||
export default function DispatchDetailModal(props) {
|
||||
const {
|
||||
approvalLoading,
|
||||
approvalMode,
|
||||
businessType,
|
||||
objectType,
|
||||
onClose,
|
||||
onSuccess,
|
||||
record,
|
||||
requestApproval,
|
||||
} = props;
|
||||
const [form] = FormBuilder.useForm();
|
||||
const cleaning = businessType === "cleaning";
|
||||
const vehicle = objectType === "vehicle";
|
||||
const approvalObject = cleaning ? record.cleaningPeople : record.personnel;
|
||||
const workflowNodes = cleaning ? cleaningWorkflowNodes : productionWorkflowNodes;
|
||||
const currentWorkflowIndex = getCurrentWorkflowIndex(record, workflowNodes, cleaning);
|
||||
const canApprove = approvalMode
|
||||
&& record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${approvalObject}`);
|
||||
|
||||
const handleApproval = async (values) => {
|
||||
const { success } = await requestApproval({ id: record.id, ...values });
|
||||
if (success) {
|
||||
message.success(values.approvalResult === "PASS" ? "审批已通过" : "审批已驳回");
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={getModalTitle(record, cleaning, vehicle)}
|
||||
width={960}
|
||||
open
|
||||
footer={canApprove ? undefined : <Button onClick={onClose}>关闭</Button>}
|
||||
confirmLoading={approvalLoading}
|
||||
maskClosable={false}
|
||||
okText="提交审批"
|
||||
onOk={canApprove ? form.submit : undefined}
|
||||
onCancel={onClose}
|
||||
>
|
||||
{canApprove && (
|
||||
<>
|
||||
<Divider orientation="left">审批处理</Divider>
|
||||
<FormBuilder
|
||||
form={form}
|
||||
loading={approvalLoading}
|
||||
values={{ approvalResult: "PASS" }}
|
||||
span={24}
|
||||
labelCol={{ span: 6 }}
|
||||
showActionButtons={false}
|
||||
options={[
|
||||
{
|
||||
name: "approvalResult",
|
||||
label: "审批结果",
|
||||
render: FORM_ITEM_RENDER_ENUM.RADIO,
|
||||
items: [
|
||||
{ bianma: "PASS", name: "通过" },
|
||||
{ bianma: "REJECT", name: "驳回" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "rejectReason",
|
||||
label: "驳回原因",
|
||||
render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
|
||||
dependencies: ["approvalResult"],
|
||||
hidden: values => values.approvalResult !== "REJECT",
|
||||
required: values => values.approvalResult === "REJECT",
|
||||
rules: [{ whitespace: true, message: "请输入驳回原因" }],
|
||||
},
|
||||
]}
|
||||
onFinish={handleApproval}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Divider orientation="left">位置与轨迹</Divider>
|
||||
<DispatchMap latitude={record.latitude} longitude={record.longitude} trackPoints={record.trackPoints} />
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "position", label: "当前位置", children: record.position },
|
||||
{ key: "locationTime", label: "定位时间", children: record.locationTime },
|
||||
{ key: "trackStatus", label: "轨迹状态", children: record.trackStatus },
|
||||
{ key: "accessState", label: "门禁状态", children: record.accessState },
|
||||
{ key: "videoState", label: "视频状态", children: record.videoState },
|
||||
{ key: "progress", label: "执行进度", children: record.progress },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
<Divider orientation="left">基础信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "id", label: "监管派工单号", children: record.id },
|
||||
{ key: "sourceNo", label: "来源派工单号", children: record.sourceNo },
|
||||
{ key: "sourceSystem", label: "来源系统", children: record.sourceSystem },
|
||||
{ key: "businessType", label: "业务类别", children: record.businessType },
|
||||
{ key: "objectType", label: "派工对象", children: record.objectType },
|
||||
{ key: "dispatchMode", label: "派工方式", children: record.dispatchMode },
|
||||
{ key: "orderStatus", label: "工单状态", children: record.orderStatus },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
{cleaning && (
|
||||
<>
|
||||
<Divider orientation="left">清扫派工作业信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "id", label: "工单编号", children: record.id },
|
||||
{ key: "workDate", label: "作业日期", children: record.workDate },
|
||||
{ key: "workSource", label: "工单来源", children: record.workSource },
|
||||
{ key: "companyName", label: "公司名称", children: record.companyName },
|
||||
{ key: "workCompany", label: "作业公司", children: record.workCompany },
|
||||
{ key: "workProject", label: "作业项目", children: record.workProject },
|
||||
{ key: "workProcess", label: "作业过程", children: record.workProcess },
|
||||
{ key: "workPlace", label: "作业地点", children: record.workPlace },
|
||||
{ key: "description", label: "工单说明", children: record.description },
|
||||
{ key: "orderStatus", label: "工单状态", children: record.orderStatus },
|
||||
{ key: "settlementStatus", label: "结算状态", children: record.settlementStatus },
|
||||
{ key: "timeout", label: "作业是否超时", children: record.timeout },
|
||||
{ key: "evaluation", label: "评价", children: record.evaluation },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
<Divider orientation="left">清扫执行信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "inspector", label: "流机现场巡视员", children: record.inspector },
|
||||
{ key: "cleaningPeople", label: "清扫人员", children: record.cleaningPeople },
|
||||
{ key: "markerName", label: "标识名称", children: record.markerName },
|
||||
{ key: "deviceName", label: "设备名称", children: record.deviceName },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!cleaning && (
|
||||
<>
|
||||
<Divider orientation="left">生产派工作业信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "planNo", label: "计划号", children: record.planNo },
|
||||
{ key: "carUnit", label: "用车单位", children: record.carUnit },
|
||||
{ key: "applyDept", label: "申请用车部门", children: record.applyDept },
|
||||
{ key: "responsibleDept", label: "现场负责部门", children: record.responsibleDept },
|
||||
{ key: "responsiblePerson", label: "现场负责人", children: record.responsiblePerson },
|
||||
{ key: "expectedArrivalTime", label: "预到位时间", children: record.expectedArrivalTime },
|
||||
{ key: "shift", label: "白/夜班", children: record.shift },
|
||||
{ key: "workPlace", label: "作业地点", children: record.workPlace },
|
||||
{ key: "arrivalPlace", label: "到位地点", children: record.arrivalPlace },
|
||||
{ key: "workContent", label: "作业内容", children: record.workContent },
|
||||
{ key: "workProcess", label: "作业过程", children: record.workProcess },
|
||||
{ key: "cargoName", label: "作业货名", children: record.cargoName },
|
||||
{ key: "voyage", label: "船名航次", children: record.voyage },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!cleaning && vehicle && (
|
||||
<>
|
||||
<Divider orientation="left">车辆/设备信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "requestedEquipment", label: "申请设备", children: record.requestedEquipment },
|
||||
{ key: "fulfilledEquipment", label: "兑现设备", children: record.fulfilledEquipment },
|
||||
{ key: "licenseNo", label: "车牌号", children: record.licenseNo },
|
||||
{ key: "vehicleType", label: "车辆类型", children: record.vehicleType },
|
||||
{ key: "driver", label: "司机", children: record.driver },
|
||||
{ key: "personnel", label: "关联人员", children: record.personnel },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!cleaning && !vehicle && (
|
||||
<>
|
||||
<Divider orientation="left">人员信息</Divider>
|
||||
<Descriptions
|
||||
bordered
|
||||
column={1}
|
||||
items={[
|
||||
{ key: "personnel", label: "派工人员", children: record.personnel },
|
||||
{ key: "personId", label: "人员ID", children: record.personId },
|
||||
{ key: "licenseNo", label: "关联车辆", children: record.licenseNo },
|
||||
{ key: "requestedEquipment", label: "申请设备", children: record.requestedEquipment },
|
||||
{ key: "fulfilledEquipment", label: "兑现设备", children: record.fulfilledEquipment },
|
||||
]}
|
||||
styles={{ label: { width: 200 } }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Divider orientation="left">审批与执行链路</Divider>
|
||||
<div className={styles.workflowSteps}>
|
||||
<Steps
|
||||
current={currentWorkflowIndex}
|
||||
items={workflowNodes.map((node, index) => ({
|
||||
title: node,
|
||||
description: getWorkflowDescription(index, currentWorkflowIndex),
|
||||
}))}
|
||||
labelPlacement="vertical"
|
||||
responsive={false}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<Divider orientation="left">处理记录</Divider>
|
||||
<Table
|
||||
columns={[
|
||||
{ title: "处理时间", dataIndex: "time" },
|
||||
{ title: "节点", dataIndex: "node" },
|
||||
{
|
||||
title: "结果",
|
||||
dataIndex: "result",
|
||||
render: (_, record) => <Tag color={getApprovalResultColor(record.result)}>{record.result}</Tag>,
|
||||
},
|
||||
{ title: "意见", dataIndex: "opinion" },
|
||||
]}
|
||||
dataSource={(record.approvalRecords || []).map(([time, node, result, opinion], index) => ({
|
||||
id: `${record.id}-${index}`,
|
||||
time,
|
||||
node,
|
||||
result,
|
||||
opinion,
|
||||
}))}
|
||||
disabledResizer
|
||||
options={false}
|
||||
pagination={false}
|
||||
showIndexColumn={false}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.workflowSteps {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: 8px;
|
||||
|
||||
:global(.micro-temp-steps) {
|
||||
min-width: 900px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
import { Button, Space, Tag } from "antd";
|
||||
import { useState } from "react";
|
||||
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 { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
||||
import useTable from "zy-react-library/hooks/useTable";
|
||||
|
||||
import DispatchDetailModal from "~/components/DispatchDetailModal";
|
||||
import SummaryMetrics from "~/components/SummaryMetrics";
|
||||
import SyncExportActions from "~/components/SyncExportActions";
|
||||
|
||||
const statusColor = {
|
||||
待审: "gold",
|
||||
审核中: "orange",
|
||||
已通过: "green",
|
||||
已驳回: "red",
|
||||
已下达: "green",
|
||||
};
|
||||
|
||||
const orderStatusColor = {
|
||||
待下达: "gold",
|
||||
作业中: "blue",
|
||||
已完成: "green",
|
||||
};
|
||||
|
||||
const selectItems = values => [...new Set(values)].map(value => ({ bianma: value, name: value }));
|
||||
|
||||
export default function CleaningDispatchList(props) {
|
||||
const {
|
||||
approvalLoading,
|
||||
listRequest,
|
||||
objectType,
|
||||
requestApproval,
|
||||
requestSync,
|
||||
syncLoading,
|
||||
} = props;
|
||||
const [form] = Search.useForm();
|
||||
const [currentRecord, setCurrentRecord] = useState({});
|
||||
const [detailModalOpen, setDetailModalOpen] = useState(false);
|
||||
const [approvalMode, setApprovalMode] = useState(false);
|
||||
const { tableProps, getData } = useTable(listRequest, { form });
|
||||
const personnel = objectType === "personnel";
|
||||
const currentList = tableProps.dataSource || [];
|
||||
const pendingCount = currentList.filter(item => ["待审", "审核中"].includes(item.approvalStatus)).length;
|
||||
const dualApprovalCount = currentList.filter(item => item.approvalOwner === "双控系统审批").length;
|
||||
const activeCount = currentList.filter(item => ["待下达", "作业中"].includes(item.orderStatus)).length;
|
||||
|
||||
const closeDetailModal = () => {
|
||||
setApprovalMode(false);
|
||||
setDetailModalOpen(false);
|
||||
setCurrentRecord({});
|
||||
};
|
||||
|
||||
const openDetailModal = (record, approve = false) => {
|
||||
setApprovalMode(approve);
|
||||
setCurrentRecord(record);
|
||||
setDetailModalOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page isShowAllAction={false}>
|
||||
<SummaryMetrics
|
||||
items={[
|
||||
{
|
||||
label: "当前菜单工单",
|
||||
value: tableProps.pagination?.total || 0,
|
||||
note: `当前页 ${currentList.length} 条`,
|
||||
},
|
||||
{ label: "双控审批", value: dualApprovalCount, note: "仅有权限节点可操作", type: "blue" },
|
||||
{ label: "执行监管", value: activeCount, note: "位置、轨迹和工单状态联动展示", type: "green" },
|
||||
{ label: "待处理", value: pendingCount, note: "包含待审和审核中工单", type: "orange" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Search
|
||||
form={form}
|
||||
options={[
|
||||
{ name: "keyword", label: "关键词", placeholder: "工单编号、作业地点、清扫人员、设备名称" },
|
||||
{
|
||||
name: "workSource",
|
||||
label: "工单来源",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["临时清扫", "清扫计划"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "workCompany",
|
||||
label: "作业公司",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["相关方清扫一队", "清扫二队"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "orderStatus",
|
||||
label: "工单状态",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["待下达", "作业中", "已完成"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "settlementStatus",
|
||||
label: "结算状态",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["未结算", "已结算"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "timeout",
|
||||
label: "作业是否超时",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["是", "否"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
]}
|
||||
onFinish={getData}
|
||||
/>
|
||||
|
||||
<Table
|
||||
toolBarRender={() => (
|
||||
<SyncExportActions
|
||||
syncText="同步工单"
|
||||
syncMessage="已同步派工和实时作业信息"
|
||||
syncLoading={syncLoading}
|
||||
requestSync={requestSync}
|
||||
onSyncSuccess={getData}
|
||||
exportUrl={`/production-dispatch/${objectType}/cleaning/export`}
|
||||
exportName={`${personnel ? "人员" : "车辆"}清扫派工`}
|
||||
getExportParams={() => form.getFieldsValue()}
|
||||
/>
|
||||
)}
|
||||
columns={[
|
||||
{ title: "工单编号", dataIndex: "id", render: (_, record) => <strong>{record.id}</strong> },
|
||||
{ title: "作业日期", dataIndex: "workDate" },
|
||||
{ title: "工单来源", dataIndex: "workSource" },
|
||||
{ title: "公司名称", dataIndex: "companyName" },
|
||||
{ title: "作业公司", dataIndex: "workCompany" },
|
||||
{ title: "作业项目", dataIndex: "workProject" },
|
||||
{ title: "作业过程", dataIndex: "workProcess" },
|
||||
{ title: "作业地点", dataIndex: "workPlace" },
|
||||
{ title: "流机现场巡视员", dataIndex: "inspector" },
|
||||
{ title: "清扫人员", dataIndex: "cleaningPeople" },
|
||||
{ title: "标识名称", dataIndex: "markerName" },
|
||||
{ title: "设备名称", dataIndex: "deviceName" },
|
||||
{ title: "工单说明", dataIndex: "description" },
|
||||
{
|
||||
title: "工单状态",
|
||||
dataIndex: "orderStatus",
|
||||
render: (_, record) => (
|
||||
<Tag color={orderStatusColor[record.orderStatus]}>{record.orderStatus}</Tag>
|
||||
),
|
||||
},
|
||||
{ title: "结算状态", dataIndex: "settlementStatus" },
|
||||
{
|
||||
title: "作业是否超时",
|
||||
dataIndex: "timeout",
|
||||
render: (_, record) => <Tag color={record.timeout === "是" ? "red" : "green"}>{record.timeout}</Tag>,
|
||||
},
|
||||
{ title: "评价", dataIndex: "evaluation" },
|
||||
{
|
||||
title: "审批归属",
|
||||
dataIndex: "approvalOwner",
|
||||
render: (_, record) => (
|
||||
<Tag color={record.approvalOwner === "双控系统审批" ? "blue" : "cyan"}>{record.approvalOwner}</Tag>
|
||||
),
|
||||
},
|
||||
{ title: "当前审批角色", dataIndex: "currentRole" },
|
||||
{
|
||||
title: "审批状态",
|
||||
dataIndex: "approvalStatus",
|
||||
render: (_, record) => <Tag color={statusColor[record.approvalStatus]}>{record.approvalStatus}</Tag>,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (_, record) => {
|
||||
const canApprove = record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.cleaningPeople}`);
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button type="link" onClick={() => openDetailModal(record)}>详情</Button>
|
||||
{canApprove && <Button type="link" onClick={() => openDetailModal(record, true)}>审批</Button>}
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
{...tableProps}
|
||||
/>
|
||||
|
||||
{detailModalOpen && (
|
||||
<DispatchDetailModal
|
||||
approvalMode={approvalMode}
|
||||
approvalLoading={approvalLoading}
|
||||
businessType="cleaning"
|
||||
objectType={objectType}
|
||||
record={currentRecord}
|
||||
requestApproval={requestApproval}
|
||||
onClose={closeDetailModal}
|
||||
onSuccess={() => {
|
||||
closeDetailModal();
|
||||
getData();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
import { Button, Space, Tag } from "antd";
|
||||
import { useState } from "react";
|
||||
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 { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
||||
import useTable from "zy-react-library/hooks/useTable";
|
||||
|
||||
import DispatchDetailModal from "~/components/DispatchDetailModal";
|
||||
import styles from "~/components/ManagementList/index.module.less";
|
||||
import SummaryMetrics from "~/components/SummaryMetrics";
|
||||
import SyncExportActions from "~/components/SyncExportActions";
|
||||
|
||||
const statusColor = {
|
||||
待审: "gold",
|
||||
审核中: "orange",
|
||||
已通过: "green",
|
||||
已驳回: "red",
|
||||
已下达: "green",
|
||||
};
|
||||
|
||||
const selectItems = values => [...new Set(values)].map(value => ({ bianma: value, name: value }));
|
||||
|
||||
export default function ProductionDispatchList(props) {
|
||||
const {
|
||||
approvalLoading,
|
||||
listRequest,
|
||||
objectType,
|
||||
requestApproval,
|
||||
requestSync,
|
||||
syncLoading,
|
||||
} = props;
|
||||
const [form] = Search.useForm();
|
||||
const [currentRecord, setCurrentRecord] = useState({});
|
||||
const [detailModalOpen, setDetailModalOpen] = useState(false);
|
||||
const [approvalMode, setApprovalMode] = useState(false);
|
||||
const { tableProps, getData } = useTable(listRequest, { form });
|
||||
const personnel = objectType === "personnel";
|
||||
const carUnitItems = personnel
|
||||
? ["杂货公司东港作业部", "东港业务部", "西港业务部"]
|
||||
: ["西港业务部", "东港业务部"];
|
||||
const currentRoleItems = personnel
|
||||
? ["港务公司计划员审核", "审批角色未配置", "已归档"]
|
||||
: ["流机调度员下达", "港务公司业务部长审核", "已归档"];
|
||||
const currentList = tableProps.dataSource || [];
|
||||
const pendingCount = currentList.filter(item => ["待审", "审核中"].includes(item.approvalStatus)).length;
|
||||
const dualApprovalCount = currentList.filter(item => item.approvalOwner === "双控系统审批").length;
|
||||
const activeCount = currentList.filter(item => ["待下达", "作业中"].includes(item.orderStatus)).length;
|
||||
|
||||
const closeDetailModal = () => {
|
||||
setApprovalMode(false);
|
||||
setDetailModalOpen(false);
|
||||
setCurrentRecord({});
|
||||
};
|
||||
|
||||
const openDetailModal = (record, approve = false) => {
|
||||
setApprovalMode(approve);
|
||||
setCurrentRecord(record);
|
||||
setDetailModalOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Page isShowAllAction={false}>
|
||||
<SummaryMetrics
|
||||
items={[
|
||||
{
|
||||
label: "当前菜单工单",
|
||||
value: tableProps.pagination?.total || 0,
|
||||
note: `当前页 ${currentList.length} 条`,
|
||||
},
|
||||
{
|
||||
label: "双控审批",
|
||||
value: dualApprovalCount,
|
||||
note: personnel ? "当前仅展示审批归属与状态" : "仅有权限节点可操作",
|
||||
type: "blue",
|
||||
},
|
||||
{
|
||||
label: "执行监管",
|
||||
value: activeCount,
|
||||
note: personnel ? "位置、轨迹和状态联动展示" : "位置、轨迹和工单状态联动展示",
|
||||
type: "green",
|
||||
},
|
||||
{ label: "待处理", value: pendingCount, note: "包含待审和审核中工单", type: "orange" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Search
|
||||
form={form}
|
||||
options={[
|
||||
{ name: "keyword", label: "关键词", placeholder: "计划号、地点、人员、车辆、申请人" },
|
||||
{
|
||||
name: "carUnit",
|
||||
label: "用车单位",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(carUnitItems),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "shift",
|
||||
label: "白/夜班",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["白班", "夜班"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "approvalStatus",
|
||||
label: "审批状态",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(["待审", "审核中", "已通过", "已驳回", "已下达"]),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
{
|
||||
name: "currentRole",
|
||||
label: "当前审批角色",
|
||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||
items: selectItems(currentRoleItems),
|
||||
componentProps: { allowClear: true },
|
||||
},
|
||||
]}
|
||||
onFinish={getData}
|
||||
/>
|
||||
|
||||
<Table
|
||||
toolBarRender={() => (
|
||||
<SyncExportActions
|
||||
syncText="同步工单"
|
||||
syncMessage="已同步派工和实时作业信息"
|
||||
syncLoading={syncLoading}
|
||||
requestSync={requestSync}
|
||||
onSyncSuccess={getData}
|
||||
exportUrl={`/production-dispatch/${objectType}/production/export`}
|
||||
exportName={`${personnel ? "人员" : "车辆"}生产派工`}
|
||||
getExportParams={() => form.getFieldsValue()}
|
||||
/>
|
||||
)}
|
||||
columns={[
|
||||
{
|
||||
title: "计划号",
|
||||
width: 200,
|
||||
dataIndex: "planNo",
|
||||
render: (_, record) => (
|
||||
<div className={styles.planNo}>
|
||||
<strong>{record.planNo}</strong>
|
||||
<span>{record.sourceNo}</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{ title: "当前审批角色", dataIndex: "currentRole" },
|
||||
{ title: "用车单位", dataIndex: "carUnit" },
|
||||
{ title: "申请用车部门", dataIndex: "applyDept" },
|
||||
{ title: "现场负责部门", dataIndex: "responsibleDept" },
|
||||
{ title: "现场负责人", dataIndex: "responsiblePerson" },
|
||||
{ title: "预到位时间", dataIndex: "expectedArrivalTime" },
|
||||
{ title: "白/夜班", dataIndex: "shift" },
|
||||
{ title: "作业地点", dataIndex: "workPlace" },
|
||||
{ title: "到位地点", dataIndex: "arrivalPlace" },
|
||||
{ title: "作业内容", dataIndex: "workContent" },
|
||||
{ title: "作业过程", dataIndex: "workProcess" },
|
||||
{ title: "作业货名", dataIndex: "cargoName" },
|
||||
{ title: "船名航次", dataIndex: "voyage" },
|
||||
{ title: "人员姓名", dataIndex: "personnel", hidden: !personnel },
|
||||
{ title: "人员ID", dataIndex: "personId", hidden: !personnel },
|
||||
{ title: "申请设备", dataIndex: "requestedEquipment", hidden: personnel },
|
||||
{ title: "兑现设备", dataIndex: "fulfilledEquipment", hidden: personnel },
|
||||
{ title: "车牌号", dataIndex: "licenseNo", hidden: personnel },
|
||||
{ title: "车辆类型", dataIndex: "vehicleType", hidden: personnel },
|
||||
{ title: "司机", dataIndex: "driver", hidden: personnel },
|
||||
{ title: "申请人", dataIndex: "applicant" },
|
||||
{ title: "申请时间", dataIndex: "applyTime" },
|
||||
{
|
||||
title: "审批归属",
|
||||
dataIndex: "approvalOwner",
|
||||
render: (_, record) => (
|
||||
<Tag color={record.approvalOwner === "双控系统审批" ? "blue" : "cyan"}>{record.approvalOwner}</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "审批状态",
|
||||
dataIndex: "approvalStatus",
|
||||
render: (_, record) => <Tag color={statusColor[record.approvalStatus]}>{record.approvalStatus}</Tag>,
|
||||
},
|
||||
{
|
||||
title: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (_, record) => {
|
||||
const canApprove = record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.personnel}`);
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button type="link" onClick={() => openDetailModal(record)}>详情</Button>
|
||||
{canApprove && <Button type="link" onClick={() => openDetailModal(record, true)}>审批</Button>}
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
]}
|
||||
{...tableProps}
|
||||
/>
|
||||
|
||||
{detailModalOpen && (
|
||||
<DispatchDetailModal
|
||||
approvalMode={approvalMode}
|
||||
approvalLoading={approvalLoading}
|
||||
businessType="production"
|
||||
objectType={objectType}
|
||||
record={currentRecord}
|
||||
requestApproval={requestApproval}
|
||||
onClose={closeDetailModal}
|
||||
onSuccess={() => {
|
||||
closeDetailModal();
|
||||
getData();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import CleaningDispatchList from "./CleaningDispatchList";
|
||||
import ProductionDispatchList from "./ProductionDispatchList";
|
||||
|
||||
export default function DispatchList(props) {
|
||||
if (props.businessType === "production") {
|
||||
return <ProductionDispatchList {...props} />;
|
||||
}
|
||||
return <CleaningDispatchList {...props} />;
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
import { message, Spin } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import CesiumMap from "zy-react-library/components/Map/CesiumMap";
|
||||
import { dynamicLoadCss, dynamicLoadJs } from "zy-react-library/utils";
|
||||
import styles from "./index.module.less";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
const CESIUM_SCRIPT_URL = "https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Cesium.js";
|
||||
const CESIUM_STYLE_URL = "https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Widgets/widgets.css";
|
||||
const EMPTY_TRACK_POINTS = [];
|
||||
let cesiumResourcePromise;
|
||||
|
||||
async function loadCesiumResources() {
|
||||
if (window.Cesium) {
|
||||
return;
|
||||
}
|
||||
if (!cesiumResourcePromise) {
|
||||
cesiumResourcePromise = (async () => {
|
||||
if (window?.base?.loadDynamicResource) {
|
||||
await window.base.loadDynamicResource({
|
||||
url: CESIUM_SCRIPT_URL,
|
||||
type: "script",
|
||||
attr: { type: "text/javascript" },
|
||||
});
|
||||
await window.base.loadDynamicResource({
|
||||
url: CESIUM_STYLE_URL,
|
||||
type: "link",
|
||||
attr: { rel: "stylesheet", type: "text/css" },
|
||||
});
|
||||
return;
|
||||
}
|
||||
await dynamicLoadJs(CESIUM_SCRIPT_URL);
|
||||
await dynamicLoadCss(CESIUM_STYLE_URL);
|
||||
})();
|
||||
}
|
||||
await cesiumResourcePromise;
|
||||
}
|
||||
|
||||
export default function DispatchMap(props) {
|
||||
const { latitude, longitude, trackPoints = EMPTY_TRACK_POINTS } = props;
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
let viewer;
|
||||
|
||||
const initMap = async () => {
|
||||
try {
|
||||
await loadCesiumResources();
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const map = new CesiumMap();
|
||||
viewer = map.init().viewer;
|
||||
const centerLongitude = Number(longitude || window.mapLongitude);
|
||||
const centerLatitude = Number(latitude || window.mapLatitude);
|
||||
map.flyTo({ longitude: centerLongitude, latitude: centerLatitude, height: 30000 });
|
||||
|
||||
const hasPosition = longitude !== undefined && longitude !== null && longitude !== ""
|
||||
&& latitude !== undefined && latitude !== null && latitude !== "";
|
||||
if (hasPosition) {
|
||||
map.addMarkPoint({ longitude: Number(longitude), latitude: Number(latitude) });
|
||||
}
|
||||
|
||||
const positions = trackPoints
|
||||
.filter(point => Array.isArray(point) && point.length >= 2)
|
||||
.map(point => [Number(point[0]), Number(point[1])])
|
||||
.filter(point => point.every(Number.isFinite))
|
||||
.map(point => window.Cesium.Cartesian3.fromDegrees(Number(point[0]), Number(point[1])));
|
||||
if (positions.length > 1) {
|
||||
viewer.entities.add({
|
||||
polyline: {
|
||||
positions,
|
||||
width: 4,
|
||||
clampToGround: true,
|
||||
material: window.Cesium.Color.fromCssColorString("#1677ff"),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
catch {
|
||||
message.error("地图加载失败");
|
||||
}
|
||||
finally {
|
||||
if (!cancelled) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initMap();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
if (viewer && !viewer.isDestroyed()) {
|
||||
viewer.destroy();
|
||||
}
|
||||
};
|
||||
}, [latitude, longitude, trackPoints]);
|
||||
|
||||
return (
|
||||
<div className={styles.mapWrapper}>
|
||||
<Spin spinning={loading} tip="地图加载中">
|
||||
<div id="map_container" className={styles.map} />
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
.cesium-viewer-toolbar,
|
||||
.cesium-viewer-fullscreenContainer,
|
||||
.cesium-infoBox-visible {
|
||||
display: none !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
.mapWrapper {
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.map {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 240px;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.planNo {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
|
||||
span {
|
||||
color: #8c8c8c;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import styles from "./index.module.less";
|
||||
|
||||
export default function SummaryMetrics(props) {
|
||||
const { items } = props;
|
||||
|
||||
return (
|
||||
<section className={styles.metrics}>
|
||||
{items.map(item => (
|
||||
<div key={item.label} className={`${styles.metric} ${styles[item.type] || ""}`}>
|
||||
<span>{item.label}</span>
|
||||
<strong>{item.value}</strong>
|
||||
<small>{item.note}</small>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
.metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
padding: 16px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-top: 3px solid #64748b;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
|
||||
span,
|
||||
small {
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #1d2939;
|
||||
font-size: 26px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
small {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.blue {
|
||||
border-top-color: #1677ff;
|
||||
}
|
||||
|
||||
.green {
|
||||
border-top-color: #389e0d;
|
||||
}
|
||||
|
||||
.orange {
|
||||
border-top-color: #d97706;
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, message, Space } from "antd";
|
||||
import ExportIcon from "zy-react-library/components/Icon/ExportIcon";
|
||||
import useDownloadBlob from "zy-react-library/hooks/useDownloadBlob";
|
||||
|
||||
export default function SyncExportActions(props) {
|
||||
const {
|
||||
exportName,
|
||||
exportUrl,
|
||||
getExportParams,
|
||||
onSyncSuccess,
|
||||
requestSync,
|
||||
syncLoading,
|
||||
syncMessage,
|
||||
syncText,
|
||||
} = props;
|
||||
const { loading: exportLoading, downloadBlob } = useDownloadBlob();
|
||||
|
||||
const handleSync = async () => {
|
||||
const { success } = await requestSync();
|
||||
if (success) {
|
||||
message.success(syncMessage);
|
||||
onSyncSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button ghost type="primary" icon={<SyncOutlined />} loading={syncLoading} onClick={handleSync}>
|
||||
{syncText}
|
||||
</Button>
|
||||
<Button
|
||||
ghost
|
||||
type="primary"
|
||||
icon={<ExportIcon />}
|
||||
loading={exportLoading}
|
||||
onClick={() => downloadBlob(exportUrl, { name: exportName, params: getExportParams() })}
|
||||
>
|
||||
导出
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export {};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/**
|
||||
* 全局常量定义
|
||||
*/
|
||||
|
||||
export {};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* 全局上下文定义
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
// 获取antd全局静态方法
|
||||
export const InjectContext = React.createContext({});
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* 全局数据状态管理模块定义
|
||||
*/
|
||||
|
||||
import { defineNamespace } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
export const NS_GLOBAL = defineNamespace("global");
|
||||
export const NS_DEVICE_MANAGEMENT = defineNamespace("deviceManagement");
|
||||
export const NS_PERSONNEL_DISPATCH = defineNamespace("personnelDispatch");
|
||||
export const NS_VEHICLE_DISPATCH = defineNamespace("vehicleDispatch");
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
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";
|
||||
|
||||
require("antd/dist/reset.css");
|
||||
require("zy-react-library/css/common.less");
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
require("~/mock");
|
||||
}
|
||||
|
||||
dayjs.locale("zh-cn");
|
||||
setJJBCommonAntdMessage(message);
|
||||
|
||||
const app = setup();
|
||||
getFileUrlFromServer();
|
||||
window.mapLongitude = "119.69457721306945";
|
||||
window.mapLatitude = "39.940504336846665";
|
||||
window.mapBaiDuKey = "OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr";
|
||||
|
||||
// 非底座环境运行
|
||||
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);
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有内部设备接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const internalDeviceList = [
|
||||
{
|
||||
id: "SB-NB-001",
|
||||
scope: "内部",
|
||||
deviceNo: "SB-NB-001",
|
||||
deviceName: "定位终端PT-3107",
|
||||
deviceType: "定位终端",
|
||||
unit: "流机公司",
|
||||
bindingObject: "冀C-3107",
|
||||
status: "正常",
|
||||
updateTime: "2026-07-24 10:12",
|
||||
gpsNo: "GPS-PT-3107",
|
||||
relatedVehicle: "装载机L-07",
|
||||
location: "东港3号泊位",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
{
|
||||
id: "SB-NB-014",
|
||||
scope: "内部",
|
||||
deviceNo: "SB-NB-014",
|
||||
deviceName: "装载机L-07",
|
||||
deviceType: "车辆",
|
||||
unit: "流机公司",
|
||||
bindingObject: "司机李明",
|
||||
status: "正常",
|
||||
updateTime: "2026-07-24 10:10",
|
||||
gpsNo: "GPS-L-07",
|
||||
relatedVehicle: "冀C-3107",
|
||||
location: "东港3号泊位",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
{
|
||||
id: "SB-NB-022",
|
||||
scope: "内部",
|
||||
deviceNo: "SB-NB-022",
|
||||
deviceName: "清扫车QS-22",
|
||||
deviceType: "车辆",
|
||||
unit: "清扫二队",
|
||||
bindingObject: "东港堆场南路",
|
||||
status: "正常",
|
||||
updateTime: "2026-07-24 09:58",
|
||||
gpsNo: "GPS-QS-22",
|
||||
relatedVehicle: "冀C-QS22",
|
||||
location: "东港堆场南路",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
{
|
||||
id: "SB-NB-031",
|
||||
scope: "内部",
|
||||
deviceNo: "SB-NB-031",
|
||||
deviceName: "牵引车T-09",
|
||||
deviceType: "车辆",
|
||||
unit: "流机公司",
|
||||
bindingObject: "郭涛",
|
||||
status: "正常",
|
||||
updateTime: "2026-07-24 12:03",
|
||||
gpsNo: "GPS-T-09",
|
||||
relatedVehicle: "冀C-6309",
|
||||
location: "东港5号堆场",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.mock(/\/production-dispatch\/device\/internal\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = internalDeviceList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.deviceNo,
|
||||
record.deviceName,
|
||||
record.bindingObject,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["deviceType", "unit", "status"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/device\/internal\/sync$/, "post", () => ({ success: true }));
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有相关方设备接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const partnerDeviceList = [
|
||||
{
|
||||
id: "SB-XG-011",
|
||||
scope: "相关方",
|
||||
deviceNo: "SB-XG-011",
|
||||
deviceName: "相关方定位卡R-008",
|
||||
deviceType: "定位终端",
|
||||
unit: "相关方清扫一队",
|
||||
bindingObject: "张敏",
|
||||
status: "正常",
|
||||
updateTime: "2026-07-24 09:42",
|
||||
gpsNo: "GPS-R-008",
|
||||
relatedVehicle: "-",
|
||||
location: "隔离封闭区2号门",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
{
|
||||
id: "SB-XG-019",
|
||||
scope: "相关方",
|
||||
deviceNo: "SB-XG-019",
|
||||
deviceName: "吸污车QS-08",
|
||||
deviceType: "车辆",
|
||||
unit: "相关方清扫一队",
|
||||
bindingObject: "冀C-QS08",
|
||||
status: "维修",
|
||||
updateTime: "2026-07-24 09:25",
|
||||
gpsNo: "GPS-QS-08",
|
||||
relatedVehicle: "冀C-QS08",
|
||||
location: "隔离封闭区2号门排水沟",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
{
|
||||
id: "SB-XG-027",
|
||||
scope: "相关方",
|
||||
deviceNo: "SB-XG-027",
|
||||
deviceName: "洒水车SW-03",
|
||||
deviceType: "车辆",
|
||||
unit: "相关方清扫二队",
|
||||
bindingObject: "冀C-SW03",
|
||||
status: "停用",
|
||||
updateTime: "2026-07-24 08:18",
|
||||
gpsNo: "GPS-SW-03",
|
||||
relatedVehicle: "冀C-SW03",
|
||||
location: "西港维修点",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.mock(/\/production-dispatch\/device\/partner\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = partnerDeviceList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.deviceNo,
|
||||
record.deviceName,
|
||||
record.bindingObject,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["deviceType", "unit", "status"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/device\/partner\/sync$/, "post", () => ({ success: true }));
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import "./deviceManagement/internalDevice";
|
||||
import "./deviceManagement/partnerDevice";
|
||||
import "./personnelDispatch/productionDispatch";
|
||||
import "./personnelDispatch/cleaningDispatch";
|
||||
import "./vehicleDispatch/productionDispatch";
|
||||
import "./vehicleDispatch/cleaningDispatch";
|
||||
|
||||
// MockJS 1.1.0 不会把 open 后设置的 responseType 传给未命中的原生 XHR,导致 Cesium 无法解码地图瓦片。
|
||||
Object.defineProperty(window.XMLHttpRequest.prototype, "responseType", {
|
||||
configurable: true,
|
||||
get() {
|
||||
return this.custom?.xhr?.responseType || this.custom?.responseType || "";
|
||||
},
|
||||
set(value) {
|
||||
this.custom.responseType = value;
|
||||
if (this.custom.xhr) {
|
||||
this.custom.xhr.responseType = value;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有人员清扫派工接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const cleaningDispatchList = [
|
||||
{
|
||||
id: "QSGD-260724-006",
|
||||
sourceNo: "QSGD-260724-006",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "清扫派工",
|
||||
objectType: "人员",
|
||||
dispatchMode: "临时派工",
|
||||
workDate: "2026-07-24",
|
||||
workSource: "临时清扫",
|
||||
companyName: "秦港股份",
|
||||
workCompany: "相关方清扫一队",
|
||||
workProject: "清扫",
|
||||
workProcess: "吸污",
|
||||
workPlace: "隔离封闭区2号门周边",
|
||||
inspector: "孙晓",
|
||||
cleaningPeople: "张敏、李兵、何强、王磊",
|
||||
markerName: "QS-08",
|
||||
deviceName: "吸污车",
|
||||
description: "临时清扫与吸污作业,作业前后需港务公司现场值守人确认",
|
||||
orderStatus: "待下达",
|
||||
settlementStatus: "未结算",
|
||||
timeout: "否",
|
||||
evaluation: "-",
|
||||
currentRole: "公务公司审核",
|
||||
approvalOwner: "双控系统审批",
|
||||
approvalStatus: "待审",
|
||||
applicant: "港务值守员",
|
||||
applyTime: "2026-07-24 09:05",
|
||||
position: "隔离封闭区2号门",
|
||||
locationTime: "未开始定位",
|
||||
onlineStatus: "离线",
|
||||
trackStatus: "未生成",
|
||||
progress: "20%",
|
||||
accessState: "领取任务并持定位卡后可入区",
|
||||
videoState: "吸污车监控待推送",
|
||||
approvalRecords: [["2026-07-24 09:07", "派工单同步", "已接收", "等待公务公司审核"]],
|
||||
},
|
||||
{
|
||||
id: "QSGD-260724-012",
|
||||
sourceNo: "QSGD-260724-012",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "清扫派工",
|
||||
objectType: "人员",
|
||||
dispatchMode: "计划派工",
|
||||
workDate: "2026-07-24",
|
||||
workSource: "清扫计划",
|
||||
companyName: "秦港股份",
|
||||
workCompany: "清扫二队",
|
||||
workProject: "道路清扫",
|
||||
workProcess: "机扫巡检",
|
||||
workPlace: "东港堆场南路",
|
||||
inspector: "郭涵",
|
||||
cleaningPeople: "王磊、刘雪",
|
||||
markerName: "QS-22",
|
||||
deviceName: "清扫车",
|
||||
description: "道路机扫及现场巡视",
|
||||
orderStatus: "已完成",
|
||||
settlementStatus: "已结算",
|
||||
timeout: "否",
|
||||
evaluation: "满意",
|
||||
currentRole: "已归档",
|
||||
approvalOwner: "派工系统审批",
|
||||
approvalStatus: "已通过",
|
||||
applicant: "清扫计划员",
|
||||
applyTime: "2026-07-24 06:55",
|
||||
position: "东港堆场南路",
|
||||
locationTime: "2026-07-24 09:58:00",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹可回放",
|
||||
progress: "100%",
|
||||
accessState: "任务已结束,人员不可再次入区",
|
||||
videoState: "视频可回放",
|
||||
approvalRecords: [["2026-07-24 07:05", "流机调度员下达", "已下达", "派工系统审批完成后同步"]],
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/cleaning\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = cleaningDispatchList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.id,
|
||||
record.workPlace,
|
||||
record.cleaningPeople,
|
||||
record.deviceName,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["workSource", "workCompany", "orderStatus", "settlementStatus", "timeout"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/cleaning\/sync$/, "post", () => ({ success: true }));
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/cleaning\/approval$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const record = cleaningDispatchList.find(item => item.id === body.id);
|
||||
const canApprove = record
|
||||
&& record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.cleaningPeople}`);
|
||||
|
||||
if (!canApprove) {
|
||||
return { success: false, errMessage: "当前清扫派工单不可审批" };
|
||||
}
|
||||
if (!["PASS", "REJECT"].includes(body.approvalResult)) {
|
||||
return { success: false, errMessage: "请选择审批结果" };
|
||||
}
|
||||
if (body.approvalResult === "REJECT" && !body.rejectReason?.trim()) {
|
||||
return { success: false, errMessage: "请输入驳回原因" };
|
||||
}
|
||||
|
||||
const approved = body.approvalResult === "PASS";
|
||||
record.approvalStatus = approved ? "已通过" : "已驳回";
|
||||
record.rejectReason = approved ? "" : body.rejectReason.trim();
|
||||
const approvalRecord = [
|
||||
new Date().toLocaleString("sv-SE", { hour12: false }).slice(0, 16),
|
||||
record.currentRole,
|
||||
approved ? "通过" : "驳回",
|
||||
approved ? "审批通过" : record.rejectReason,
|
||||
];
|
||||
const processingRecordIndex = record.approvalRecords.findIndex(item => item[2] === "处理中");
|
||||
if (processingRecordIndex >= 0) {
|
||||
record.approvalRecords[processingRecordIndex] = approvalRecord;
|
||||
}
|
||||
else {
|
||||
record.approvalRecords.push(approvalRecord);
|
||||
}
|
||||
|
||||
return { success: true, data: record };
|
||||
});
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有人员生产派工接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const productionDispatchList = [
|
||||
{
|
||||
id: "QG-SC-RY-20260724-001",
|
||||
sourceNo: "PGD-SC-260724-0815",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "人员",
|
||||
dispatchMode: "自动派工",
|
||||
planNo: "JH-DG-0724-015",
|
||||
currentRole: "港务公司计划员审核",
|
||||
carUnit: "杂货公司东港作业部",
|
||||
applyDept: "东港生产调度室",
|
||||
responsibleDept: "东港现场保障组",
|
||||
responsiblePerson: "王海",
|
||||
expectedArrivalTime: "2026-07-24 10:00",
|
||||
shift: "白班",
|
||||
workPlace: "东港3号泊位",
|
||||
arrivalPlace: "3号泊位东侧集结点",
|
||||
workContent: "装卸保障与现场辅助作业",
|
||||
workProcess: "到位确认、作业执行、反馈记录",
|
||||
cargoName: "矿石",
|
||||
voyage: "QHD-0724-A",
|
||||
personnel: "李明、赵强、刘洋、韩涛",
|
||||
personId: "DK-RY-10021、DK-RY-10046、DK-RY-10108、DK-RY-10177",
|
||||
licenseNo: "冀C-3107、冀C-3112",
|
||||
requestedEquipment: "装载机2台、对讲机6部",
|
||||
fulfilledEquipment: "装载机L-07、L-12",
|
||||
applicant: "刘静",
|
||||
applyTime: "2026-07-24 08:15",
|
||||
approvalOwner: "双控系统审批",
|
||||
approvalStatus: "审核中",
|
||||
orderStatus: "待下达",
|
||||
position: "东港3号泊位东侧集结点",
|
||||
longitude: 119.694577,
|
||||
latitude: 39.940504,
|
||||
trackPoints: [
|
||||
[119.6908, 39.9386],
|
||||
[119.6924, 39.9394],
|
||||
[119.694577, 39.940504],
|
||||
],
|
||||
locationTime: "2026-07-24 09:42:16",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹已生成",
|
||||
accessState: "派工有效,可进入隔离封闭区域",
|
||||
videoState: "移动监控已推送",
|
||||
progress: "35%",
|
||||
approvalRecords: [
|
||||
["2026-07-24 08:20", "公务公司审核", "通过", "用工信息完整"],
|
||||
["2026-07-24 09:10", "港务公司计划员审核", "处理中", "等待当前节点确认"],
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "QG-SC-RY-20260724-013",
|
||||
sourceNo: "PGD-SC-260724-1028",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "人员",
|
||||
dispatchMode: "临时派工",
|
||||
planNo: "JH-DG-0724-031",
|
||||
currentRole: "审批角色未配置",
|
||||
carUnit: "东港业务部",
|
||||
applyDept: "东港计划室",
|
||||
responsibleDept: "现场维修配合组",
|
||||
responsiblePerson: "邓凯",
|
||||
expectedArrivalTime: "2026-07-24 13:00",
|
||||
shift: "白班",
|
||||
workPlace: "东港维修区",
|
||||
arrivalPlace: "维修区南门",
|
||||
workContent: "设备检修配合作业",
|
||||
workProcess: "停机确认、维修配合、验收反馈",
|
||||
cargoName: "-",
|
||||
voyage: "-",
|
||||
personnel: "派工人员未匹配",
|
||||
personId: "-",
|
||||
licenseNo: "流机07号装载机",
|
||||
requestedEquipment: "维修工具包A3",
|
||||
fulfilledEquipment: "-",
|
||||
applicant: "陈立",
|
||||
applyTime: "2026-07-24 10:28",
|
||||
approvalOwner: "双控系统审批",
|
||||
approvalStatus: "待审",
|
||||
orderStatus: "待下达",
|
||||
position: "东港维修区",
|
||||
longitude: 119.6819,
|
||||
latitude: 39.9358,
|
||||
trackPoints: [],
|
||||
locationTime: "未开始定位",
|
||||
onlineStatus: "离线",
|
||||
trackStatus: "未生成",
|
||||
accessState: "未完成审批,暂不可入区",
|
||||
videoState: "未推送",
|
||||
progress: "8%",
|
||||
approvalRecords: [["2026-07-24 10:30", "同步校验", "异常", "人员ID未匹配,当前审批角色未配置"]],
|
||||
},
|
||||
{
|
||||
id: "QG-SC-RY-20260724-021",
|
||||
sourceNo: "PGD-SC-260724-1136",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "人员",
|
||||
dispatchMode: "自动派工",
|
||||
planNo: "JH-XG-0724-041",
|
||||
currentRole: "已归档",
|
||||
carUnit: "西港业务部",
|
||||
applyDept: "西港生产计划室",
|
||||
responsibleDept: "西港现场保障组",
|
||||
responsiblePerson: "周强",
|
||||
expectedArrivalTime: "2026-07-24 14:30",
|
||||
shift: "白班",
|
||||
workPlace: "西港主干路",
|
||||
arrivalPlace: "西港2号门",
|
||||
workContent: "短倒转运保障",
|
||||
workProcess: "人员到位、连续作业、结束反馈",
|
||||
cargoName: "煤炭",
|
||||
voyage: "XG-0724-C",
|
||||
personnel: "陈勇、孙凯、马宁",
|
||||
personId: "DK-RY-10203、DK-RY-10211、DK-RY-10245",
|
||||
licenseNo: "冀C-5021、冀C-5022、冀C-5025",
|
||||
requestedEquipment: "对讲机3部",
|
||||
fulfilledEquipment: "对讲机3部",
|
||||
applicant: "周强",
|
||||
applyTime: "2026-07-24 11:36",
|
||||
approvalOwner: "派工系统审批",
|
||||
approvalStatus: "已下达",
|
||||
orderStatus: "作业中",
|
||||
position: "西港主干路北段",
|
||||
longitude: 119.6426,
|
||||
latitude: 39.9284,
|
||||
trackPoints: [
|
||||
[119.6378, 39.9256],
|
||||
[119.6401, 39.9271],
|
||||
[119.6426, 39.9284],
|
||||
],
|
||||
locationTime: "2026-07-24 14:58:41",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹记录中",
|
||||
accessState: "派工有效,可进入隔离封闭区域",
|
||||
videoState: "无移动监控",
|
||||
progress: "68%",
|
||||
approvalRecords: [["2026-07-24 12:04", "流机调度员下达", "已下达", "派工系统审批完成后同步"]],
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.setup({ timeout: "300-600" });
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/production\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = productionDispatchList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.planNo,
|
||||
record.workPlace,
|
||||
record.personnel,
|
||||
record.licenseNo,
|
||||
record.applicant,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["carUnit", "shift", "approvalStatus", "currentRole"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/production\/sync$/, "post", () => ({ success: true }));
|
||||
|
||||
Mock.mock(/\/production-dispatch\/personnel\/production\/approval$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const record = productionDispatchList.find(item => item.id === body.id);
|
||||
const canApprove = record
|
||||
&& record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.personnel}`);
|
||||
|
||||
if (!canApprove) {
|
||||
return { success: false, errMessage: "当前派工单不可审批" };
|
||||
}
|
||||
if (!["PASS", "REJECT"].includes(body.approvalResult)) {
|
||||
return { success: false, errMessage: "请选择审批结果" };
|
||||
}
|
||||
if (body.approvalResult === "REJECT" && !body.rejectReason?.trim()) {
|
||||
return { success: false, errMessage: "请输入驳回原因" };
|
||||
}
|
||||
|
||||
const approved = body.approvalResult === "PASS";
|
||||
record.approvalStatus = approved ? "已通过" : "已驳回";
|
||||
record.rejectReason = approved ? "" : body.rejectReason.trim();
|
||||
const approvalRecord = [
|
||||
new Date().toLocaleString("sv-SE", { hour12: false }).slice(0, 16),
|
||||
record.currentRole,
|
||||
approved ? "通过" : "驳回",
|
||||
approved ? "审批通过" : record.rejectReason,
|
||||
];
|
||||
const processingRecordIndex = record.approvalRecords.findIndex(item => item[2] === "处理中");
|
||||
if (processingRecordIndex >= 0) {
|
||||
record.approvalRecords[processingRecordIndex] = approvalRecord;
|
||||
}
|
||||
else {
|
||||
record.approvalRecords.push(approvalRecord);
|
||||
}
|
||||
|
||||
return { success: true, data: record };
|
||||
});
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有车辆清扫派工接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const cleaningDispatchList = [
|
||||
{
|
||||
id: "QSGD-260724-018",
|
||||
sourceNo: "QSGD-260724-018",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "清扫派工",
|
||||
objectType: "车辆",
|
||||
dispatchMode: "计划派工",
|
||||
workDate: "2026-07-24",
|
||||
workSource: "清扫计划",
|
||||
companyName: "秦港股份",
|
||||
workCompany: "清扫二队",
|
||||
workProject: "道路清扫",
|
||||
workProcess: "机扫",
|
||||
workPlace: "东港堆场南路至5号门",
|
||||
inspector: "郭涵",
|
||||
cleaningPeople: "王磊、刘雪",
|
||||
markerName: "冀C-QS22",
|
||||
deviceName: "清扫车QS-22",
|
||||
description: "按计划完成道路清扫",
|
||||
orderStatus: "作业中",
|
||||
settlementStatus: "未结算",
|
||||
timeout: "否",
|
||||
evaluation: "-",
|
||||
currentRole: "流机调度员下达",
|
||||
approvalOwner: "派工系统审批",
|
||||
approvalStatus: "已下达",
|
||||
applicant: "清扫计划员",
|
||||
applyTime: "2026-07-24 07:20",
|
||||
position: "东港堆场南路",
|
||||
locationTime: "2026-07-24 10:16:29",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹记录中",
|
||||
progress: "74%",
|
||||
accessState: "派工有效,可进入隔离封闭区域",
|
||||
videoState: "移动监控已推送",
|
||||
approvalRecords: [["2026-07-24 07:36", "流机调度员下达", "已下达", "派工系统审批完成后同步"]],
|
||||
},
|
||||
{
|
||||
id: "QSGD-260724-031",
|
||||
sourceNo: "QSGD-260724-031",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "清扫派工",
|
||||
objectType: "车辆",
|
||||
dispatchMode: "临时派工",
|
||||
workDate: "2026-07-24",
|
||||
workSource: "临时清扫",
|
||||
companyName: "秦港股份",
|
||||
workCompany: "相关方清扫一队",
|
||||
workProject: "吸污",
|
||||
workProcess: "吸污",
|
||||
workPlace: "隔离封闭区2号门排水沟",
|
||||
inspector: "孙晓",
|
||||
cleaningPeople: "张敏、李兵",
|
||||
markerName: "冀C-QS08",
|
||||
deviceName: "吸污车QS-08",
|
||||
description: "排水沟吸污,作业后需现场确认",
|
||||
orderStatus: "待下达",
|
||||
settlementStatus: "未结算",
|
||||
timeout: "否",
|
||||
evaluation: "-",
|
||||
currentRole: "港务公司现场值守人确认",
|
||||
approvalOwner: "双控系统审批",
|
||||
approvalStatus: "审核中",
|
||||
applicant: "港务值守员",
|
||||
applyTime: "2026-07-24 10:05",
|
||||
position: "隔离封闭区2号门排水沟",
|
||||
locationTime: "2026-07-24 10:26:18",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹已生成",
|
||||
progress: "28%",
|
||||
accessState: "等待作业前现场确认",
|
||||
videoState: "移动监控已推送",
|
||||
approvalRecords: [
|
||||
["2026-07-24 10:07", "公务公司审核", "通过", "临时清扫申请有效"],
|
||||
["2026-07-24 10:22", "港务公司现场值守人确认", "处理中", "等待作业前确认"],
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/cleaning\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = cleaningDispatchList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.id,
|
||||
record.workPlace,
|
||||
record.cleaningPeople,
|
||||
record.deviceName,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["workSource", "workCompany", "orderStatus", "settlementStatus", "timeout"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/cleaning\/sync$/, "post", () => ({ success: true }));
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/cleaning\/approval$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const record = cleaningDispatchList.find(item => item.id === body.id);
|
||||
const canApprove = record
|
||||
&& record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.cleaningPeople}`);
|
||||
|
||||
if (!canApprove) {
|
||||
return { success: false, errMessage: "当前车辆清扫派工单不可审批" };
|
||||
}
|
||||
if (!["PASS", "REJECT"].includes(body.approvalResult)) {
|
||||
return { success: false, errMessage: "请选择审批结果" };
|
||||
}
|
||||
if (body.approvalResult === "REJECT" && !body.rejectReason?.trim()) {
|
||||
return { success: false, errMessage: "请输入驳回原因" };
|
||||
}
|
||||
|
||||
const approved = body.approvalResult === "PASS";
|
||||
record.approvalStatus = approved ? "已通过" : "已驳回";
|
||||
record.rejectReason = approved ? "" : body.rejectReason.trim();
|
||||
const approvalRecord = [
|
||||
new Date().toLocaleString("sv-SE", { hour12: false }).slice(0, 16),
|
||||
record.currentRole,
|
||||
approved ? "通过" : "驳回",
|
||||
approved ? "审批通过" : record.rejectReason,
|
||||
];
|
||||
const processingRecordIndex = record.approvalRecords.findIndex(item => item[2] === "处理中");
|
||||
if (processingRecordIndex >= 0) {
|
||||
record.approvalRecords[processingRecordIndex] = approvalRecord;
|
||||
}
|
||||
else {
|
||||
record.approvalRecords.push(approvalRecord);
|
||||
}
|
||||
|
||||
return { success: true, data: record };
|
||||
});
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
import Mock from "mockjs";
|
||||
|
||||
// 当前没有车辆生产派工接口文档,以下数据仅用于还原交互原型,接入真实接口后删除本拦截文件。
|
||||
const productionDispatchList = [
|
||||
{
|
||||
id: "QG-SC-CL-20260724-002",
|
||||
sourceNo: "PGD-SC-260724-0832",
|
||||
planNo: "JH-XG-0724-022",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "车辆",
|
||||
dispatchMode: "自动派工",
|
||||
currentRole: "流机调度员下达",
|
||||
carUnit: "西港业务部",
|
||||
applyDept: "西港生产计划室",
|
||||
responsibleDept: "西港现场保障组",
|
||||
responsiblePerson: "李海军",
|
||||
expectedArrivalTime: "2026-07-24 09:30",
|
||||
shift: "白班",
|
||||
workPlace: "西港主干路",
|
||||
arrivalPlace: "西港2号门",
|
||||
workContent: "短倒转运保障",
|
||||
workProcess: "车辆到位、连续作业、结束反馈",
|
||||
cargoName: "煤炭",
|
||||
voyage: "XG-0724-C",
|
||||
requestedEquipment: "自卸车3台",
|
||||
fulfilledEquipment: "自卸车X-21、X-22、X-25",
|
||||
personnel: "陈勇、孙凯、马宁",
|
||||
personId: "DK-RY-10203、DK-RY-10211、DK-RY-10245",
|
||||
licenseNo: "冀C-5021、冀C-5022、冀C-5025",
|
||||
vehicleType: "自卸车",
|
||||
driver: "陈勇、孙凯、马宁",
|
||||
applicant: "周强",
|
||||
applyTime: "2026-07-24 08:32",
|
||||
approvalOwner: "派工系统审批",
|
||||
approvalStatus: "已下达",
|
||||
orderStatus: "作业中",
|
||||
position: "西港主干路北段",
|
||||
locationTime: "2026-07-24 10:24:08",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹记录中",
|
||||
progress: "68%",
|
||||
accessState: "派工有效,可进入隔离封闭区域",
|
||||
videoState: "移动监控已推送",
|
||||
approvalRecords: [["2026-07-24 08:54", "流机调度员下达", "已下达", "派工系统审批完成后同步"]],
|
||||
},
|
||||
{
|
||||
id: "QG-SC-CL-20260724-017",
|
||||
sourceNo: "PGD-SC-260724-1048",
|
||||
planNo: "JH-DG-0724-038",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "车辆",
|
||||
dispatchMode: "临时派工",
|
||||
currentRole: "港务公司业务部长审核",
|
||||
carUnit: "东港业务部",
|
||||
applyDept: "东港生产调度室",
|
||||
responsibleDept: "东港现场保障组",
|
||||
responsiblePerson: "韩冰",
|
||||
expectedArrivalTime: "2026-07-24 12:30",
|
||||
shift: "白班",
|
||||
workPlace: "东港5号堆场",
|
||||
arrivalPlace: "5号堆场西门",
|
||||
workContent: "倒运车辆临时支援",
|
||||
workProcess: "派车确认、安全交底、作业反馈",
|
||||
cargoName: "钢材",
|
||||
voyage: "DG-0724-H",
|
||||
requestedEquipment: "牵引车2台、平板车2台",
|
||||
fulfilledEquipment: "牵引车T-09、T-12",
|
||||
personnel: "郭涛、吴建",
|
||||
personId: "DK-RY-10305、DK-RY-10361",
|
||||
licenseNo: "冀C-6309、冀C-6312",
|
||||
vehicleType: "牵引车",
|
||||
driver: "郭涛、吴建",
|
||||
applicant: "赵一鸣",
|
||||
applyTime: "2026-07-24 10:48",
|
||||
approvalOwner: "双控系统审批",
|
||||
approvalStatus: "审核中",
|
||||
orderStatus: "待下达",
|
||||
position: "东港5号堆场西门",
|
||||
locationTime: "2026-07-24 12:06:22",
|
||||
onlineStatus: "在线",
|
||||
trackStatus: "轨迹已生成",
|
||||
progress: "41%",
|
||||
accessState: "审批中,等待下达后放行",
|
||||
videoState: "移动监控待推送",
|
||||
approvalRecords: [
|
||||
["2026-07-24 10:55", "公务公司审核", "通过", "车辆资质有效"],
|
||||
["2026-07-24 11:40", "港务公司计划员审核", "通过", "作业窗口符合计划"],
|
||||
["2026-07-24 12:02", "港务公司业务部长审核", "处理中", "等待当前节点确认"],
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "QG-SC-CL-20260724-029",
|
||||
sourceNo: "PGD-SC-260724-1510",
|
||||
planNo: "JH-XG-0724-068",
|
||||
sourceSystem: "流机公司智能调度平台",
|
||||
businessType: "生产派工",
|
||||
objectType: "车辆",
|
||||
dispatchMode: "自动派工",
|
||||
currentRole: "已归档",
|
||||
carUnit: "西港业务部",
|
||||
applyDept: "西港生产计划室",
|
||||
responsibleDept: "西港现场保障组",
|
||||
responsiblePerson: "曹俊",
|
||||
expectedArrivalTime: "2026-07-24 16:00",
|
||||
shift: "夜班",
|
||||
workPlace: "西港煤场南路",
|
||||
arrivalPlace: "煤场南路检查口",
|
||||
workContent: "夜班倒运保障",
|
||||
workProcess: "车辆入区、转运、离区确认",
|
||||
cargoName: "煤炭",
|
||||
voyage: "XG-0724-N",
|
||||
requestedEquipment: "自卸车4台",
|
||||
fulfilledEquipment: "自卸车X-31、X-32、X-33、X-36",
|
||||
personnel: "沈旭、李杨、贾鹏、刘帅",
|
||||
personId: "DK-RY-10511、DK-RY-10512、DK-RY-10515、DK-RY-10519",
|
||||
licenseNo: "冀C-5031、冀C-5032、冀C-5033、冀C-5036",
|
||||
vehicleType: "自卸车",
|
||||
driver: "沈旭、李杨、贾鹏、刘帅",
|
||||
applicant: "马琳",
|
||||
applyTime: "2026-07-24 15:10",
|
||||
approvalOwner: "派工系统审批",
|
||||
approvalStatus: "已通过",
|
||||
orderStatus: "待下达",
|
||||
position: "西港煤场南路检查口",
|
||||
locationTime: "未开始定位",
|
||||
onlineStatus: "离线",
|
||||
trackStatus: "未生成",
|
||||
progress: "0%",
|
||||
accessState: "待派工系统下达",
|
||||
videoState: "未推送",
|
||||
approvalRecords: [["2026-07-24 15:22", "流机计划员审核", "已通过", "派工系统审批完成后同步"]],
|
||||
},
|
||||
];
|
||||
|
||||
function getRequestBody(options) {
|
||||
try {
|
||||
return JSON.parse(options.body || "{}");
|
||||
}
|
||||
catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/production\/list$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const keyword = body.keyword?.trim();
|
||||
const filteredList = productionDispatchList.filter((record) => {
|
||||
if (keyword && ![
|
||||
record.planNo,
|
||||
record.workPlace,
|
||||
record.personnel,
|
||||
record.licenseNo,
|
||||
record.applicant,
|
||||
].some(value => value.includes(keyword))) {
|
||||
return false;
|
||||
}
|
||||
return ["carUnit", "shift", "approvalStatus", "currentRole"]
|
||||
.every(key => !body[key] || record[key] === body[key]);
|
||||
});
|
||||
const pageIndex = Number(body.pageIndex || 1);
|
||||
const pageSize = Number(body.pageSize || 20);
|
||||
const start = (pageIndex - 1) * pageSize;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
totalCount: filteredList.length,
|
||||
data: filteredList.slice(start, start + pageSize),
|
||||
};
|
||||
});
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/production\/sync$/, "post", () => ({ success: true }));
|
||||
|
||||
Mock.mock(/\/production-dispatch\/vehicle\/production\/approval$/, "post", (options) => {
|
||||
const body = getRequestBody(options);
|
||||
const record = productionDispatchList.find(item => item.id === body.id);
|
||||
const canApprove = record
|
||||
&& record.approvalOwner === "双控系统审批"
|
||||
&& ["待审", "审核中"].includes(record.approvalStatus)
|
||||
&& !/未配置|未匹配/.test(`${record.currentRole} ${record.personnel}`);
|
||||
|
||||
if (!canApprove) {
|
||||
return { success: false, errMessage: "当前车辆派工单不可审批" };
|
||||
}
|
||||
if (!["PASS", "REJECT"].includes(body.approvalResult)) {
|
||||
return { success: false, errMessage: "请选择审批结果" };
|
||||
}
|
||||
if (body.approvalResult === "REJECT" && !body.rejectReason?.trim()) {
|
||||
return { success: false, errMessage: "请输入驳回原因" };
|
||||
}
|
||||
|
||||
const approved = body.approvalResult === "PASS";
|
||||
record.approvalStatus = approved ? "已通过" : "已驳回";
|
||||
record.rejectReason = approved ? "" : body.rejectReason.trim();
|
||||
const approvalRecord = [
|
||||
new Date().toLocaleString("sv-SE", { hour12: false }).slice(0, 16),
|
||||
record.currentRole,
|
||||
approved ? "通过" : "驳回",
|
||||
approved ? "审批通过" : record.rejectReason,
|
||||
];
|
||||
const processingRecordIndex = record.approvalRecords.findIndex(item => item[2] === "处理中");
|
||||
if (processingRecordIndex >= 0) {
|
||||
record.approvalRecords[processingRecordIndex] = approvalRecord;
|
||||
}
|
||||
else {
|
||||
record.approvalRecords.push(approvalRecord);
|
||||
}
|
||||
|
||||
return { success: true, data: record };
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DeviceManagementList from "~/components/DeviceManagementList";
|
||||
import { NS_DEVICE_MANAGEMENT } from "~/enumerate/namespace";
|
||||
|
||||
function InternalDevice(props) {
|
||||
return (
|
||||
<DeviceManagementList
|
||||
scope="internal"
|
||||
listRequest={props["internalDeviceList"]}
|
||||
requestSync={props["internalDeviceSync"]}
|
||||
syncLoading={props.deviceManagement?.internalDeviceSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_DEVICE_MANAGEMENT], true)(InternalDevice);
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DeviceManagementList from "~/components/DeviceManagementList";
|
||||
import { NS_DEVICE_MANAGEMENT } from "~/enumerate/namespace";
|
||||
|
||||
function PartnerDevice(props) {
|
||||
return (
|
||||
<DeviceManagementList
|
||||
scope="partner"
|
||||
listRequest={props["partnerDeviceList"]}
|
||||
requestSync={props["partnerDeviceSync"]}
|
||||
syncLoading={props.deviceManagement?.partnerDeviceSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_DEVICE_MANAGEMENT], true)(PartnerDevice);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default function DeviceManagement(props) {
|
||||
return props.children;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DispatchList from "~/components/DispatchList";
|
||||
import { NS_PERSONNEL_DISPATCH } from "~/enumerate/namespace";
|
||||
|
||||
function CleaningDispatch(props) {
|
||||
return (
|
||||
<DispatchList
|
||||
businessType="cleaning"
|
||||
objectType="personnel"
|
||||
listRequest={props["cleaningDispatchList"]}
|
||||
requestApproval={props["cleaningDispatchApproval"]}
|
||||
requestSync={props["cleaningDispatchSync"]}
|
||||
approvalLoading={props.personnelDispatch?.cleaningDispatchApprovalLoading}
|
||||
syncLoading={props.personnelDispatch?.cleaningDispatchSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_PERSONNEL_DISPATCH], true)(CleaningDispatch);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DispatchList from "~/components/DispatchList";
|
||||
import { NS_PERSONNEL_DISPATCH } from "~/enumerate/namespace";
|
||||
|
||||
function ProductionDispatch(props) {
|
||||
return (
|
||||
<DispatchList
|
||||
businessType="production"
|
||||
objectType="personnel"
|
||||
listRequest={props["productionDispatchList"]}
|
||||
requestApproval={props["productionDispatchApproval"]}
|
||||
requestSync={props["productionDispatchSync"]}
|
||||
approvalLoading={props.personnelDispatch?.productionDispatchApprovalLoading}
|
||||
syncLoading={props.personnelDispatch?.productionDispatchSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_PERSONNEL_DISPATCH], true)(ProductionDispatch);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default function PersonnelDispatch(props) {
|
||||
return props.children;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DispatchList from "~/components/DispatchList";
|
||||
import { NS_VEHICLE_DISPATCH } from "~/enumerate/namespace";
|
||||
|
||||
function CleaningDispatch(props) {
|
||||
return (
|
||||
<DispatchList
|
||||
businessType="cleaning"
|
||||
objectType="vehicle"
|
||||
listRequest={props["cleaningDispatchList"]}
|
||||
requestApproval={props["cleaningDispatchApproval"]}
|
||||
requestSync={props["cleaningDispatchSync"]}
|
||||
approvalLoading={props.vehicleDispatch?.cleaningDispatchApprovalLoading}
|
||||
syncLoading={props.vehicleDispatch?.cleaningDispatchSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_VEHICLE_DISPATCH], true)(CleaningDispatch);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||
|
||||
import DispatchList from "~/components/DispatchList";
|
||||
import { NS_VEHICLE_DISPATCH } from "~/enumerate/namespace";
|
||||
|
||||
function ProductionDispatch(props) {
|
||||
return (
|
||||
<DispatchList
|
||||
businessType="production"
|
||||
objectType="vehicle"
|
||||
listRequest={props["productionDispatchList"]}
|
||||
requestApproval={props["productionDispatchApproval"]}
|
||||
requestSync={props["productionDispatchSync"]}
|
||||
approvalLoading={props.vehicleDispatch?.productionDispatchApprovalLoading}
|
||||
syncLoading={props.vehicleDispatch?.productionDispatchSyncLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Connect([NS_VEHICLE_DISPATCH], true)(ProductionDispatch);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default function VehicleDispatch(props) {
|
||||
return props.children;
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import { ImportCore } from "@cqsjjb/jjb-common-decorator/module";
|
||||
import { theme as antdTheme, App, ConfigProvider } from "antd";
|
||||
import language from "antd/locale/zh_CN";
|
||||
import React from "react";
|
||||
import { InjectContext } from "~/enumerate/context";
|
||||
|
||||
export default class Container extends React.Component {
|
||||
state = window?.base?.themeConfig || {
|
||||
algorithm: window.process.env.app.antd.algorithm,
|
||||
borderRadius: window.process.env.app.antd.borderRadius,
|
||||
colorPrimary: window.process.env.app.antd.colorPrimary,
|
||||
};
|
||||
|
||||
get token() {
|
||||
const {
|
||||
colorPrimary,
|
||||
borderRadius,
|
||||
} = this.state;
|
||||
return {
|
||||
fontFamily: window.process.env.app.antd.fontFamily,
|
||||
colorPrimary,
|
||||
borderRadius,
|
||||
};
|
||||
}
|
||||
|
||||
get algorithm() {
|
||||
return antdTheme[this.state.algorithm];
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (window.__IN_BASE__) {
|
||||
// eslint-disable-next-line react-web-api/no-leaked-event-listener
|
||||
window.base.addEventListener("EVENT_THEME_CONTROL", (e) => {
|
||||
const config = e.data;
|
||||
this.setState({ [config.field]: config.value });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: this.token,
|
||||
algorithm: this.algorithm,
|
||||
}}
|
||||
locale={language}
|
||||
prefixCls={window.process.env.app.antd["ant-prefix"]}
|
||||
>
|
||||
<App style={{ height: "100%" }}>
|
||||
<AppMiddle {...this.props} />
|
||||
</App>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function AppMiddle(props) {
|
||||
return (
|
||||
<InjectContext.Provider value={App.useApp()}>
|
||||
{process.env.NODE_ENV === "development"
|
||||
? props.children
|
||||
: (
|
||||
<Interceptor>
|
||||
{props.children}
|
||||
</Interceptor>
|
||||
)}
|
||||
</InjectContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
class Interceptor 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(async (res) => {
|
||||
if (res.status) {
|
||||
this.setState({ Component: res.module?.PageCover });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { Component } = this.state;
|
||||
return (Component && process.env.app.appKey && process.env.NODE_ENV === "development")
|
||||
? (
|
||||
<Component appKey={process.env.app.appKey}>
|
||||
{this.props.children}
|
||||
</Component>
|
||||
)
|
||||
: this.props.children;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
export default function () {
|
||||
return (
|
||||
<h1>
|
||||
底座微应用模板,技术文档:
|
||||
<a rel="noreferrer noopener" target="_blank" href="https://www.yuque.com/buhangjiecheshen-ymbtb/qc0093/gxdun1dphetcurko">https://www.yuque.com/buhangjiecheshen-ymbtb/qc0093/gxdun1dphetcurko</a>
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
"use strict";
|
||||
const path = require("node:path");
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, ".", dir);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
context: path.resolve(__dirname, "./"),
|
||||
resolve: {
|
||||
extensions: [".js"],
|
||||
alias: {
|
||||
"~": resolve("src/"),
|
||||
},
|
||||
},
|
||||
};
|
||||
Loading…
Reference in New Issue