水利工程项目

master
wy 2021-12-27 15:40:50 +08:00
parent 28beb7653b
commit 3b9a25a8fb
115 changed files with 44637 additions and 0 deletions

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.\
You will also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you cant go back!**
If you arent satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point youre on your own.
You dont have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldnt feel obligated to use this feature. However we understand that this tool wouldnt be useful if you couldnt customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).

15
craco.config.js Normal file
View File

@ -0,0 +1,15 @@
const CracoAntDesignPlugin = require('craco-antd');
module.exports = {
plugins: [
{
plugin: CracoAntDesignPlugin,
options: {
customizeTheme: {
'@layout-header-height': '48px',
'@layout-header-color': '#fff',
},
},
},
],
};

38372
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

52
package.json Normal file
View File

@ -0,0 +1,52 @@
{
"name": "dy_proj_mgr_web",
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@ant-design/pro-card": "^1.18.6",
"@ant-design/pro-form": "^1.49.6",
"@craco/craco": "^6.4.2",
"@rematch/core": "^2.2.0",
"@types/node": "^12.20.37",
"@types/react": "^17.0.37",
"@types/react-dom": "^17.0.11",
"@types/react-image-gallery": "^1.0.5",
"antd": "^4.17.2",
"craco-antd": "^1.19.0",
"gantt-task-react": "^0.3.7",
"moment": "^2.29.1",
"rc-resize-observer": "^1.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-image-gallery": "^1.2.7",
"react-redux": "^7.2.6",
"react-router": "^6.0.2",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",
"redux": "^4.1.2",
"typescript": "^4.5.2"
},
"scripts": {
"start": "craco start",
"build": "craco build"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -0,0 +1,30 @@
import { Button, Popconfirm } from 'antd'
import React from 'react'
import { CrudContext } from './useCrud'
interface IProps {
crudCtx: CrudContext,
confirm?: boolean,
text?: string
}
const CancelCrud: React.FC<IProps> = ({ crudCtx, confirm, text }) => {
text = text || '返回';
if (confirm) {
return (
<Popconfirm title="是否要放弃表单返回列表" onConfirm={() => crudCtx.goto(null, null)}>
<Button size="small" type="link">{text}</Button>
</Popconfirm>
)
} else {
return (
<Button onClick={() => crudCtx.goto(null, null)} size="small" type="link">{text}</Button>
)
}
}
export default CancelCrud

View File

@ -0,0 +1,13 @@
import React from 'react'
const CenterForm: React.FC = ({ children }) => {
return (
<div style={{ display: 'flex', justifyContent: 'center' }}>
<div style={{ maxWidth: 520 }}>
{children}
</div>
</div>
)
}
export default CenterForm

View File

@ -0,0 +1 @@
export const DEF_INPUT_LEN = 464;

View File

@ -0,0 +1,18 @@
import { Button } from 'antd'
import React from 'react'
type IProps = {
icon?: React.ReactNode;
danger?: boolean;
text?: string;
onClick?: () => void;
};
const OpButton: React.FC<IProps> = ({ icon, danger, text, onClick }) => {
return (
<Button size="small" type="link" icon={icon} danger={danger} onClick={onClick}>{text}</Button>
)
}
export default OpButton

View File

@ -0,0 +1,29 @@
import { useState } from "react";
export type CrudContext = {
mode: string | null;
record: any;
goto: (mode: string | null, r: any) => void;
}
export default function useCrud(params?: {
mode?: string;
record?: any;
}): CrudContext {
const [mode, setMode] = useState<string | null>(params?.mode || null);
const [record, setRecord] = useState(params?.record);
const goto = (mode: string | null, record: any) => {
setRecord(record);
setMode(mode);
}
return {
mode,
record,
goto,
}
}

View File

@ -0,0 +1,116 @@
import { ListProps, TableProps } from 'antd';
import { useState, useRef, useEffect } from 'react';
import { PageResult, SearchOption } from '../../service/def';
type TableState<T> = {
data: T[];
total: number;
loading: boolean;
pageSize: number;
pageNumber: number;
search: { [key: string]: string };
sort?: [string, 'asc' | 'desc'];
}
export type PageTableContext<T> = {
tableProps: TableProps<T>,
listProps?: ListProps<T>,
search: (params?: SearchOption) => void,
refresh: () => void
}
function usePageTable<T>(
service: (params?: SearchOption) => Promise<PageResult<T>>,
options: SearchOption = {}
): PageTableContext<T> {
// 写在一起避免异步之后多次setState导致多次重绘
const [state, setState] = useState<TableState<T>>(() => ({
data: [],
total: 0,
loading: false,
pageSize: options.pageSize ?? 10,
pageNumber: options.pageNumber ?? 1,
sort: options.sort,
search: options.search || {},
}));
const abort = useRef(false);
useEffect(() => {
abort.current = false;
search();
return () => { abort.current = true; }
}, []);
const search = (opt: SearchOption = {}) => {
setState(s => ({ ...s, loading: true }));
const pageParams = {
pageNumber: opt?.pageNumber ?? state.pageNumber,
pageSize: opt?.pageSize ?? state.pageSize,
sort: opt?.sort ?? state.sort,
search: opt?.search ?? state.search,
};
service(pageParams).then((data) => {
if (!abort.current) {
setState({
...pageParams,
data: data.list,
total: data.totalRow,
loading: false,
})
}
});
}
const handleTableChange = (pagination: any, filters: any, sort: any) => {
search({ pageNumber: pagination.current, pageSize: pagination.pageSize, sort });
}
let listProps = undefined;
if (false) {
const handleListChange = (page: number, pageSize: number) => {
search({ pageNumber: page, pageSize: pageSize });
}
listProps = {
dataSource: state.data,
loading: state.loading,
pagination: {
showTotal: (totalRow: any) => `${totalRow}`,
showSizeChanger: true,
showQuickJumper: true,
pageSize: state.pageSize,
current: state.pageNumber,
total: state.total,
pageSizeOptions: ['10', '20', '50', '100'],
onChange: handleListChange
}
}
}
return {
tableProps: {
size: 'small',
bordered: true,
dataSource: state.data,
pagination: {
showTotal: (totalRow: any) => `${totalRow}`,
showSizeChanger: true,
showQuickJumper: true,
pageSize: state.pageSize,
current: state.pageNumber,
total: state.total,
pageSizeOptions: ['10', '20', '50', '100'],
hideOnSinglePage: true,
},
loading: state.loading,
onChange: handleTableChange,
},
listProps,
search: (params?: SearchOption) => search({ ...params, pageNumber: 1 }),
refresh: search,
}
}
export default usePageTable

44
src/index.less Normal file
View File

@ -0,0 +1,44 @@
@import "~react-image-gallery/styles/css/image-gallery.css";
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.flex-grow-1 {
flex-grow: 1;
}
.ant-descriptions-item-container {
border-bottom: 1px dashed #ddd;
padding: 8px;
}
.ant-descriptions-item-label {
font-weight: bold;
}
::-webkit-scrollbar {
width: 4px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #eee;
}
::-webkit-scrollbar-thumb {
background: #00daf9;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #a2e7f0;
}

24
src/index.tsx Normal file
View File

@ -0,0 +1,24 @@
import { ConfigProvider } from 'antd';
import zhCN from 'antd/lib/locale/zh_CN';
import 'moment/locale/zh-cn';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import './index.less';
import { store } from './models/store';
import AppRouters from './views/AppRouters';
ReactDOM.render(
<Provider store={store}>
<BrowserRouter>
<ConfigProvider locale={zhCN}>
<AppRouters />
</ConfigProvider>
</BrowserRouter>
</Provider>,
document.getElementById('root')
);

View File

@ -0,0 +1,11 @@
import React from 'react'
const AppBreadcrumb: React.FC = () => {
return (
<div className="app-breadcrumb">
aaa - aaa
</div>
)
}
export default AppBreadcrumb

View File

@ -0,0 +1,17 @@
import { Menu } from 'antd'
import { UserOutlined, UnlockOutlined, LogoutOutlined } from '@ant-design/icons';
const { SubMenu } = Menu;
const HeaderUser = () => {
return (
<Menu mode="horizontal" theme="dark">
<SubMenu key="pm" icon={<UserOutlined />} title="张三">
<Menu.Item icon={<UnlockOutlined />} key="changepw"></Menu.Item>
<Menu.Item icon={<LogoutOutlined />} key="logout"></Menu.Item>
</SubMenu>
</Menu>
)
}
export default HeaderUser

View File

@ -0,0 +1,62 @@
import React from 'react'
import { Menu } from 'antd';
import { Link } from 'react-router-dom';
import { ProfileOutlined } from '@ant-design/icons';
const { SubMenu, Item } = Menu;
const SiderMenu: React.FC = () => {
return (
<Menu
mode="inline"
theme="light"
>
<SubMenu key="1" icon={<ProfileOutlined />} title="项目管理">
<Item key="1.1" icon={<ProfileOutlined />}><Link to="/proj/log"></Link></Item>
</SubMenu>
<SubMenu key="2" icon={<ProfileOutlined />} title="合同管理">
<Item key="2.1" icon={<ProfileOutlined />}><Link to="/contract/log"></Link></Item>
</SubMenu>
<SubMenu key="3" icon={<ProfileOutlined />} title="供应商管理">
<Item key="3.2" icon={<ProfileOutlined />}><Link to="/supplier/log"></Link></Item>
</SubMenu>
<SubMenu key="4" icon={<ProfileOutlined />} title="招标管理">
<Item key="4.2" icon={<ProfileOutlined />}><Link to="/bid/contractorlog"></Link></Item>
<Item key="4.3" icon={<ProfileOutlined />}><Link to="/bid/log"></Link></Item>
</SubMenu>
<SubMenu key="5" icon={<ProfileOutlined />} title="设计管理">
<Item key="5.1" icon={<ProfileOutlined />}><Link to="/des/pac"></Link></Item>
<Item key="5.2" icon={<ProfileOutlined />}><Link to="/des/assets"></Link></Item>
<Item key="5.4" icon={<ProfileOutlined />}><Link to="/des/change"></Link></Item>
</SubMenu>
<SubMenu key="6" icon={<ProfileOutlined />} title="进度管理">
<Item key="6.1" icon={<ProfileOutlined />}><Link to="/progress/em"></Link></Item>
<Item key="6.2" icon={<ProfileOutlined />}><Link to="/progress/proj"></Link></Item>
</SubMenu>
<SubMenu key="7" icon={<ProfileOutlined />} title="质量管理">
<Item key="7.1" icon={<ProfileOutlined />}></Item>
<Item key="7.2" icon={<ProfileOutlined />}></Item>
<Item key="7.3" icon={<ProfileOutlined />}></Item>
</SubMenu>
<SubMenu key="8" icon={<ProfileOutlined />} title="现场管理">
<Item key="8.1" icon={<ProfileOutlined />}><Link to="/site/log"></Link></Item>
<Item key="8.2" icon={<ProfileOutlined />}><Link to="/site/picres"></Link></Item>
</SubMenu>
<SubMenu key="9" icon={<ProfileOutlined />} title="竣工管理">
<Item key="9.1" icon={<ProfileOutlined />}></Item>
<Item key="9.2" icon={<ProfileOutlined />}></Item>
</SubMenu>
<SubMenu key="10" icon={<ProfileOutlined />} title="资料管理">
<Item key="10.1" icon={<ProfileOutlined />}><Link to="/res/dir"></Link></Item>
<Item key="10.2" icon={<ProfileOutlined />}><Link to="/res/adoc"></Link></Item>
<Item key="10.3" icon={<ProfileOutlined />}><Link to="/res/pdoc"></Link></Item>
</SubMenu>
<SubMenu key="11" icon={<ProfileOutlined />} title="系统设置">
<Item key="11.1" icon={<ProfileOutlined />}><Link to="/sys/user"></Link></Item>
<Item key="11.2" icon={<ProfileOutlined />}><Link to="/sys/role"></Link></Item>
</SubMenu>
</Menu>
)
}
export default SiderMenu

View File

@ -0,0 +1,37 @@
import React, { Suspense } from 'react'
import { Outlet } from 'react-router';
import { Layout } from 'antd';
import HeaderUser from './HeaderUser';
import './style.less';
import SiderMenu from './SiderMenu';
import AppBreadcrumb from './AppBreadcrumb';
const { Header, Content, Sider } = Layout;
const DashboardLayout: React.FC = () => {
return (
<Layout className="app-root">
<Header className="app-header">
<img className="app-icon" src="/assets/icons/项目管理.png" />
<span className="app-title"></span>
<div className="flex-grow-1"></div>
<HeaderUser />
</Header>
<Layout>
<Sider breakpoint="xxl" collapsedWidth={48} className="app-sider">
<SiderMenu />
</Sider>
<Content className="app-content">
<AppBreadcrumb />
<Suspense fallback={null}>
<Outlet />
</Suspense>
</Content>
</Layout>
</Layout>
)
}
export default DashboardLayout

View File

@ -0,0 +1,49 @@
.app-root {
height: 100vh;
}
.app-header {
display: flex;
align-items: center;
padding: 0 24px;
overflow: hidden;
z-index: 20;
.app-icon {
height: 80%;
margin-right: 8px;
}
.app-title {
font-size: 24px;
}
}
.app-sider {
overflow-y: auto;
overflow-x: hidden;
background-color: #fff;
box-shadow: 1px 0px 4px #888888;
z-index: 10;
}
.app-content {
overflow-y: auto;
overflow-x: hidden;
z-index: 0;
}
.app-breadcrumb {
background-color: #fff;
padding: 4px 16px;
color: #888;
position: sticky;
}
.content-root {
padding: 16px 24px;
}
.card-h-margin {
margin-bottom: 12px;
}

27
src/models/auth/index.ts Normal file
View File

@ -0,0 +1,27 @@
import { createModel } from "@rematch/core";
import { RootModel } from "..";
import { LoginUser } from "../../service/def";
import { AuthState } from "../def";
export const auth = createModel<RootModel>()({
state: {
user: null
} as AuthState,
reducers: {
setUser(state, user: LoginUser): AuthState {
return { ...state, user };
},
},
effects: (dispatch) => {
const { auth } = dispatch;
return {
async login(payload: { name: string, pw: string }): Promise<void> {
},
}
},
});

17
src/models/def.ts Normal file
View File

@ -0,0 +1,17 @@
import { Task } from 'gantt-task-react';
import { Schedule, LoginUser } from "../service/def";
export type AuthState = {
user: LoginUser | null;
}
export type ProgressState = {
tasks?: Task[];
scheduleMap: { [key: string]: Schedule };
scheduleCrud?: {
mode: 'mod' | 'new';
record: Schedule;
}
}

13
src/models/index.ts Normal file
View File

@ -0,0 +1,13 @@
import { Models } from "@rematch/core"
import { auth } from "./auth";
import { progress } from "./progress";
export interface RootModel extends Models<RootModel> {
auth: typeof auth;
progress: typeof progress;
}
export const models: RootModel = {
auth,
progress,
};

34
src/models/progress/_.ts Normal file
View File

@ -0,0 +1,34 @@
import { Task } from 'gantt-task-react';
import { Schedule } from "../../service/def";
export function _fillTask(data: Schedule[], parentProject: string | undefined, res: Task[], scheduleMap: { [key: string]: Schedule }) {
for (const o of data) {
const isfolder = Array.isArray(o.children);
const milestone = o.stm1.getTime() === o.etm1.getTime();
const id = '' + o.id
const cur: Task = {
start: o.stm1,
end: o.etm1,
name: o.name,
id,
progress: o.progress,
type: isfolder ? "project" : (milestone ? 'milestone' : 'task'),
hideChildren: false,
project: parentProject
};
res.push(cur);
scheduleMap[o.id] = o;
if (o.children) {
_fillTask(o.children, id, res, scheduleMap);
}
}
}

View File

@ -0,0 +1,50 @@
import { createModel } from "@rematch/core";
import { Task } from 'gantt-task-react';
import { RootModel } from "..";
import { Schedule } from "../../service/def";
import { ProgressState } from "../def";
import { _fillTask } from './_';
export const progress = createModel<RootModel>()({
state: {
scheduleMap: {},
tasks: undefined,
} as ProgressState,
reducers: {
setTasks(state, tasks?: Task[]): ProgressState {
return { ...state, tasks };
},
setScheduleMap(state, scheduleMap: { [key: string]: Schedule }): ProgressState {
return { ...state, scheduleMap };
},
setScheduleCrud(state, crudCtx?: {
mode: 'mod' | 'new';
record: Schedule;
}): ProgressState {
return {
...state,
scheduleCrud: crudCtx
}
}
},
effects: (dispatch) => {
const { progress } = dispatch;
return {
async loadSchedules(payload: Schedule[]) {
const list: Task[] = [];
const scheduleMap: { [key: string]: Schedule } = {};
_fillTask(payload, undefined, list, scheduleMap);
progress.setScheduleMap(scheduleMap);
progress.setTasks(list);
},
}
},
});

10
src/models/store.ts Normal file
View File

@ -0,0 +1,10 @@
import { init, RematchDispatch, RematchRootState } from '@rematch/core'
import { models, RootModel } from './index'
export const store = init({
models,
})
export type Store = typeof store
export type Dispatch = RematchDispatch<RootModel>
export type RootState = RematchRootState<RootModel>

1
src/react-app-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="react-scripts" />

365
src/service/def.ts Normal file
View File

@ -0,0 +1,365 @@
export type PageResult<T> = {
list: T[];
totalRow: number;
}
export type SearchOption = {
pageSize?: number;
pageNumber?: number;
search?: { [key: string]: string };
sort?: [string, 'asc' | 'desc'];
}
export type LoginUser = {
name: string;
token: string;
}
export type User = {
id: number;
user: string;
name: string;
phone: string;
createtime: Date;
roles: string[];
}
export type Menu = {
code: string;
name: string;
type: 'menu' | 'action';
children?: Menu[];
}
export type Role = {
name: string;
desc?: string;
}
export type ProjectLog = {
code: string;
name: string;
status: '筹备阶段' | '已开工' | '已竣工';
planstm: Date;
proprietor?: string;
operator?: string;
projadmin: string;
projadmin2: string;
jldw: string;
sjdw: string;
zbwj: string[];
tbwj: string[];
zbtzs: string[];
contracts: string[];
}
export type ProjectInfo = ProjectLog & {
desc: string;
planetm: Date;
stm?: Date;
etm?: Date;
district: string;
type: '水电站项目' | '排涝站项目' | '小型农田水利工程' | '水库、大坝工程' | '堤防、河道工程' | '灌区工程' | '水利枢纽工程' | '农村安全饮水工程' | '引水隧洞工程';
investment: number;
scale: '大型' | '中型' | '小型',
ws: string,
lat: number;
lng: number;
overall?: string;
attachments?: string[];
}
export type ProjectResource = {
id: number;
code: string;
startcond: string;
requirement?: string;
endtm: Date;
attachments?: string[];
}
export type ContractLog = {
code: string;
name: string;
type: '施工合同' | '采购合同';
proprietor?: string;
signtm: Date;
status: '终止' | '执行中';
}
export type ContractSign = ContractLog & {
}
export type ContractQuantityCat = {
contractcode: string;
itemcode: string;
name: string;
parentitem?: string;
tasktype: string;
projtype: '原始工程量清单';
desc?: string;
}
export type ContractQuantityItem = ContractQuantityCat & {
chargetype: '同时计入当前和原始金额';
sum: number;
sumunit: '立方米';
unitprice: number;
priceunit: '人民币';
estimate: string;
}
export type ContractQuantityNode = (
ContractQuantityCat & { children: ContractQuantityNode[] }
) | ContractQuantityItem;
export type SupplierLog = {
id: number;
name: string;
type: '物资供应商' | '服务供应商';
orgcode: string;
nature: '国有企业' | '国有控股企业' | '外资企业' | '合资企业' | '私营企业';
regcapital: number;
creditlevel: 'A' | 'B' | 'C';
contactor: string;
contactorphone: string;
}
export type SupplierInfo = {
id: number;
name: string;
type: '物资供应商' | '服务供应商';
orgcode: string;
nature: '国有企业' | '国有控股企业' | '外资企业' | '合资企业' | '私营企业';
regcapital: number;
creditlevel: 'A' | 'B' | 'C';
contactor: string;
contactorphone: string;
contactorcode: string;
bankname: string;
bankcountname: string;
bankcountcode: string;
}
export type ContractorLog = {
id: number;
name: string;
type: '承包商';
orgcode: string;
nature: '国有企业';
regcapital: number;
contactor: string;
contactorphone: string;
}
export type ContractorInfo = {
id: number;
name: string;
name2: string;
type: '承包商';
orgcode: string;
regcapital: number;
fax: string;
contactor: string;
contactorphone: string;
fddbr: string;
fddbrcode: string;
jsfzr: string;
jsfzrcode: string;
wtdlr: string;
wtdlrcode: string;
sqr: string;
sqrcode: string;
sqrphone: string;
}
export type ContractorAchivement = {
id: number;
contractorid: number;
projname: string;
projcode: string;
signtm: Date;
contractsum: number;
settlesum: number;
etm: Date;
org?: string;
settletm: Date;
personel: string;
}
export type ContractorPersonel = {
id: number;
contractorid: number;
name: string;
sex: '男' | '女';
nativeplace: string;
code: string;
zc: string;
gw: string;
zgzs: string;
ldht: string;
remark?: string;
}
export type BidLog = {
id: number;
projname: string;
name: string;
code: string;
department: string;
method: string;
type: string;
status: string;
tm: Date;
etm: Date;
packdesc?: string;
range?: string;
sum: number;
};
export type DesignPackage = {
id: number;
proj: string;
descontract?: string;
constructcontract?: string;
code: string;
name: string;
imgnum: number;
status: '设计' | '评审' | '完成';
evalmethod: '在线评审' | '线下评审',
evaltm: Date;
evaldonetm?: Date;
pubtm: Date;
pubdonetm?: Date;
desorg: string;
desperonel: string;
}
export type DesignAssetsVersion = {
id: number;
name: string;
version: string;
tm: Date;
remark?: string;
attachments: string[];
}
export type DesignAssets = {
id: number;
packid: number;
packname?: string;
code: string;
type: '科研试验成果类';
name: string;
no: string;
keyword?: string[];
despersonel: string;
committer?: string;
remark?: string;
version?: string;
}
export type DesignChangeLog = {
id: number;
descontract: string;
no?: string;
name: string;
reason: string;
reason2?: string;
affectlv: '小' | '一般' | '大' | '很大';
affectproc?: string;
affectinvest?: string;
stm1: Date;
stm2?: Date;
etm1: Date;
etm2?: Date;
remark?: string;
}
export type EngineeringMemorabilia = {
id: number;
proj: string;
name: string;
tm: Date;
creator?: string;
desc: string;
}
export type ProjProgressLog = {
id: number;
status: '未开工' | '已开工' | '已完工';
projname: string;
proprietor: string;
projadmin: string;
stm: Date;
etm: Date;
period: string;
}
export type ScheduleProps = {
wbs: true,
level: '单项工程',
status: '未开工' | '已开工' | '已完工',
phase: '[C]项目实时阶段',
} | {
task: true;
type: string;
schedule: string;
calendar: string;
org?: string;
personel?: string;
};
export type Schedule = {
id: string;
name: string;
stm1: Date;
etm1: Date;
stm2?: Date;
etm2?: Date;
progress: number;
props: ScheduleProps;
remark?: string;
_indent: number;
children?: Schedule[] | undefined; // undefine为task否则就是wbs
}
export type DirectoryDef = {
code: string;
name: string;
remark?: string;
children: DirectoryDef[];
}
export type DocTypeDef = {
code: string;
name: string;
remark?: string;
}

17
src/utils/renutil.ts Normal file
View File

@ -0,0 +1,17 @@
import moment from "moment";
export function renYYYYMMDD(val: any) {
const tm = moment(val);
if (!tm.isValid()) {
return '-';
}
return tm.format('YYYY-MM-DD');
}
export function renDigitFixed2(val: any) {
if (typeof val !== 'number') {
return '-';
}
return val.toFixed(2);
}

39
src/utils/useRequest.ts Normal file
View File

@ -0,0 +1,39 @@
import { useState, useEffect, useRef, useReducer } from "react";
const useRequest = <DataType = any>(p: (parame?: any) => Promise<DataType>): { data?: DataType, error?: any, loading: boolean, refresh: () => void } => {
const [data, setData] = useState<DataType | undefined>()
const [error, setError] = useState<any>();
const [loading, setLoading] = useState(false);
const abort = useRef(false);
const [_, refresh] = useReducer(s => s + 1, 0);
useEffect(() => {
const doFetch = async () => {
setLoading(true);
abort.current = false;
try {
const data = await p();
if (!abort.current) {
setData(data);
}
} catch (e) {
if (!abort.current) {
setError(e);
}
} finally {
if (!abort.current) {
setLoading(false);
}
}
};
doFetch();
return () => {
abort.current = true;
};
}, [_]); // eslint-disable-line
return { data, error, loading, refresh };
};
export default useRequest;

24
src/utils/utils.ts Normal file
View File

@ -0,0 +1,24 @@
export const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
export const clientHeight = () => {
return (document.getElementById('root')?.clientHeight || 1024)
- (document.getElementsByClassName('app-header')[0]?.clientHeight || 0)
- (document.getElementsByClassName('app-breadcrumb')[0]?.clientHeight || 0);
}
export const demoDate = (day: number): Date => {
const ret = new Date(Date.now() + day * 24 * 1000 * 60 * 60);
ret.setHours(0);
ret.setMilliseconds(0);
ret.setMinutes(0);
ret.setSeconds(0);
return ret;
}

95
src/views/AppRouters.tsx Normal file
View File

@ -0,0 +1,95 @@
import React from 'react';
import { Navigate, useRoutes } from 'react-router';
import DashboardLayout from '../layouts/DashboardLayout';
import Login from './auth/Login';
import Role from './auth/Role';
import UserPage from './auth/User';
import BidLogPage from './bid/BidLog';
import ContractorLogPage from './bid/ContractorLog';
import ContractLogPage from './contract/ContractLog';
import DesignAssetsPage from './design/DesignAssets';
import DesignChangeLogPage from './design/DesignChange';
import DesignPackagePage from './design/DesignPackage';
import Error404 from './errors/Error404';
import EngineeringMemorabiliaPage from './progress/EngineeringMemorabilia';
import ProjProgressLogPage from './progress/ProjProgress';
import ProjectLogPage from './project/ProjectLog';
import AdministrativeDocPage from './res/AdministrativeDoc';
import DirectoryDefPage from './res/DirectoryDef';
import ProjDocPage from './res/ProjDoc';
import ConstructionLog from './site/ConstructionLog';
import PicResources from './site/PicResources';
import SupplierLogPage from './supplier/SupplierLog';
const AppRouters: React.FC = () => {
let element = useRoutes([
{ path: '/login', element: <Login /> },
{
path: '/proj', element: <DashboardLayout />, children: [
{ path: 'log', element: <ProjectLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/contract', element: <DashboardLayout />, children: [
{ path: 'log', element: <ContractLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/site', element: <DashboardLayout />, children: [
{ path: 'log', element: <ConstructionLog /> },
{ path: 'picres', element: <PicResources /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/supplier', element: <DashboardLayout />, children: [
{ path: 'log', element: <SupplierLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/bid', element: <DashboardLayout />, children: [
{ path: 'log', element: <BidLogPage /> },
{ path: 'contractorlog', element: <ContractorLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/des', element: <DashboardLayout />, children: [
{ path: 'pac', element: <DesignPackagePage /> },
{ path: 'assets', element: <DesignAssetsPage /> },
{ path: 'change', element: <DesignChangeLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/progress', element: <DashboardLayout />, children: [
{ path: 'em', element: <EngineeringMemorabiliaPage /> },
{ path: 'proj', element: <ProjProgressLogPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/res', element: <DashboardLayout />, children: [
{ path: 'dir', element: <DirectoryDefPage /> },
{ path: 'adoc', element: <AdministrativeDocPage /> },
{ path: 'pdoc', element: <ProjDocPage /> },
{ path: '*', element: <Error404 /> },
]
},
{
path: '/sys', element: <DashboardLayout />, children: [
{ path: 'user', element: <UserPage /> },
{ path: 'role', element: <Role /> },
{ path: '*', element: <Error404 /> },
]
},
{ path: '/', element: <Navigate to="/proj/log" /> },
]);
return element;
}
export default AppRouters

View File

@ -0,0 +1,11 @@
import React from 'react'
const Login: React.FC = () => {
return (
<div>
Login
</div>
)
}
export default Login

View File

@ -0,0 +1,25 @@
import ProForm, { ProFormCheckbox, ProFormText } from '@ant-design/pro-form'
import { Col, Form, Row, Tree } from 'antd'
import Checkbox from 'antd/lib/checkbox/Checkbox'
import React, { useState } from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import MenuSelect from './MenuSelect'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<ProFormText name="user" label="角色名" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="描述" width={DEF_INPUT_LEN} />
<Form.Item name="权限" label="权限">
<MenuSelect />
</Form.Item>
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,48 @@
import { DeleteOutlined, PlusOutlined, ProfileOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, Input, Select, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { Role } from '../../../service/def';
type IProps = {
pagerCtx: PageTableContext<Role>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<Role>>(() => [
{ title: '角色', key: 'name', dataIndex: 'name' },
{ title: '描述', key: 'desc', dataIndex: 'desc' },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="name" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,77 @@
import { Tree } from 'antd'
import React, { useState } from 'react'
const treeData = [
{
title: '项目台账', key: '项目台账', children: [
{ title: '会签', key: '项目台账-会签' },
{ title: '编辑', key: '项目台账-编辑' },
{ title: '删除', key: '项目台账-删除' },
{
title: '开工条件', key: '项目台账-开工条件', children: [
{ title: '新增', key: '项目台账-开工条件-新增' },
{ title: '删除', key: '项目台账-开工条件-删除' },
]
},
],
},
{
title: '合同台账', key: '合同台账', children: [
{ title: '新增', key: '合同台账-新增' },
{ title: '删除', key: '合同台账-删除' },
{ title: '工程量', key: '合同台账-工程量' },
{ title: '评价', key: '合同台账-评价' },
],
},
{ title: '承包商台账', key: '承包商台账', },
{ title: '供应商台账', key: '供应商台账', },
];
const MenuSelect: React.FC<{
value?: string[];
onChange?: (value: string[]) => void;
}> = ({ value, onChange }) => {
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
const [checkedKeys, setCheckedKeys] = useState<React.Key[] | { checked: React.Key[]; halfChecked: React.Key[]; }>([]);
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
const onExpand = (expandedKeysValue: React.Key[]) => {
console.log('onExpand', expandedKeysValue);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
setExpandedKeys(expandedKeysValue);
setAutoExpandParent(false);
};
const onCheck = (checked: React.Key[] | { checked: React.Key[]; halfChecked: React.Key[]; }, info: any) => {
console.log('onCheck', checked);
setCheckedKeys(checked);
};
const onSelect = (selectedKeysValue: React.Key[], info: any) => {
console.log('onSelect', info);
setSelectedKeys(selectedKeysValue);
};
return (
<div style={{ border: '1px solid #d9d9d9', padding: 16, height: 300, overflowY: 'auto' }}>
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={treeData}
/>
</div>
)
}
export default MenuSelect

View File

@ -0,0 +1,57 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { PageResult, Role } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(): Promise<PageResult<Role>> {
return {
list: [
{
name: '管理员',
desc: '全部权限',
},
{
name: '查看用户',
desc: 'xxxxxxxxxxxx',
},
{
name: '财务',
desc: 'xxxxxxxxxxxx',
},
{
name: '项目经理',
desc: 'xxxxxxxxxxxx',
},
],
totalRow: 4
};
}
const RolePage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<Role>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增角色" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default RolePage

View File

@ -0,0 +1,36 @@
import ProForm, { ProFormCheckbox, ProFormText } from '@ant-design/pro-form'
import { Col, Row } from 'antd'
import Checkbox from 'antd/lib/checkbox/Checkbox'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<ProFormText name="user" label="登录名" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="姓名" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="phone" label="联系电话" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormCheckbox.Group
label="角色"
rules={[{ required: true }]}
>
<Row>
{
['查看', '管理员', '财务', '项目经理', '工程师', 'test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8', 'test9'].map(s => (
<Col key={s} span={8}>
<Checkbox value={s}>{s}</Checkbox>
</Col>
))
}
</Row>
</ProFormCheckbox.Group>
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,55 @@
import { DeleteOutlined, PlusOutlined, ProfileOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, DatePicker, Input, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import OpButton from '../../../components/crud/OpButton';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { User } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<User>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<User>>(() => [
{ title: '编号', key: 'id', dataIndex: 'id' },
{ title: '登录名', key: 'user', dataIndex: 'user' },
{ title: '姓名', key: 'name', dataIndex: 'name' },
{ title: '联系电话', key: 'phone', dataIndex: 'phone' },
{ title: '创建时间', key: 'createtime', dataIndex: 'createtime', align: 'center', render: renYYYYMMDD },
{ title: '角色', key: 'roles', render: rec => rec.roles.map((r: string) => <OpButton key={r} text={r} />) },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>:<Input /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,65 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { PageResult, User } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(): Promise<PageResult<User>> {
return {
list: [
{
id: 1,
user: 'admin',
name: '管理员',
phone: '13266666666',
roles: ['管理员'],
createtime: demoDate(-3),
},
{
id: 2,
user: 'test',
name: '查看用户',
phone: '13266666661',
roles: ['查看'],
createtime: demoDate(-2),
},
{
id: 3,
user: 'aaa',
name: 'bbb',
phone: '13266666662',
roles: ['项目经理', '财务'],
createtime: demoDate(-1),
},
],
totalRow: 3
};
}
const UserPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<User>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增用户" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default UserPage

View File

@ -0,0 +1,42 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormSelect name="projid" label="项目" />
<ProForm.Group>
<ProFormText name="code" label="招标编号" width="sm" rules={[{ required: true }]} />
<ProFormText name="department" label="招标部门" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="name" label="招标名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormSelect name="type" label="招标类别" width="sm" rules={[{ required: true }]} />
<ProFormSelect name="method" label="招标方式" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="regcapital" label="招标日期" width="sm" rules={[{ required: true }]} />
<ProFormSelect name="status" label="状态" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormDatePicker name="fax" label="合同期限" width="sm" />
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormText name="packdesc" label="表包名称" width={DEF_INPUT_LEN} />
<ProFormText name="rage" label="招标范围" width={DEF_INPUT_LEN} />
<ProFormDigit name="sum" label="计划金额(万元)" width="sm" />
<ProFormTextArea name="招标公告" label="招标公告" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,60 @@
import { DeleteOutlined, PlusOutlined, ProfileOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, DatePicker, Input, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import OpButton from '../../../components/crud/OpButton';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { BidLog } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<BidLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<BidLog>>(() => [
{ title: '项目名称', key: 'projname', dataIndex: 'projname' },
{ title: '招标编号', key: 'code', dataIndex: 'code' },
{ title: '招标名称', key: 'name', dataIndex: 'name' },
{ title: '招标日期', key: 'tm', dataIndex: 'tm', render: renYYYYMMDD },
{ title: '招标部门', key: 'department', dataIndex: 'department' },
{ title: '招标方式', key: 'method', dataIndex: 'method' },
{ title: '合同期限', key: 'etm', dataIndex: 'etm', render: renYYYYMMDD },
{ title: '状态', key: 'status', dataIndex: 'status' },
{
title: '操作', key: '_', render: rec => (
<Space>
<OpButton icon={<ProfileOutlined />} onClick={() => crudCtx.goto('info', rec)} />
<OpButton icon={<DeleteOutlined />} danger />
<OpButton text='中标结果' onClick={() => crudCtx.goto('setresult', rec)} />
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /><Button size="small" type="link"></Button></Space>
<Space>:<Input /></Space>
<Space>:<DatePicker.RangePicker /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,64 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { BidLog, PageResult } from '../../../service/def';
import DataForm from './DataForm';
import ResultDataForm from '../BidResult/DataForm';
import DataTable from './DataTable';
async function demofind(): Promise<PageResult<BidLog>> {
return {
list: [
{
id: 1,
projname: "test项目",
name: "中铁15局集团有限公司",
code: '44444444',
department: 'A部门',
method: 'B方式',
type: '工程分标',
status: '采购中',
tm: new Date(),
etm: new Date(Date.now() + 1000 * 24 * 60 * 60 * 100),
sum: 23.4,
packdesc: 'dsafefgege',
range: 'asfaegbuesgu',
}
],
totalRow: 1
};
}
const BidLogPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<BidLog>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增招标信息" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
crud.mode === 'setresult' ? (
<Card key="setresult" title="中标结果登记" extra={<CancelCrud crudCtx={crud} confirm />} >
<ResultDataForm crudCtx={crud} />
</Card>
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default BidLogPage

View File

@ -0,0 +1,46 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton } from '@ant-design/pro-form'
import { Typography } from 'antd'
import moment from 'moment'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
const DataForm: React.FC<{
crudCtx: CrudContext
}> = ({ crudCtx }) => {
const record = crudCtx.record || {};
console.log('1', record);
return (
<CenterForm>
<ProForm initialValues={{
name: record.name,
tm: moment(record.tm),
code: record.code,
}}>
<ProFormText name="name" label="招标名称" width={DEF_INPUT_LEN} disabled />
<ProFormText name="code" label="招标编码" width={DEF_INPUT_LEN} disabled />
<ProForm.Group>
<ProFormDatePicker name="tm" label="招标日期" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="_1" label="开标日期" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="_2" label="中标公司" width={DEF_INPUT_LEN} />
<ProFormUploadButton name="_3" label="中标通知书" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
<ProFormUploadButton name="_4" label="投标文件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,48 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormText } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../../components/crud/useCrud'
import { PageTableContext } from '../../../../components/crud/usePageTable'
import { ContractorAchivement } from '../../../../service/def'
type IProps = {
pageCtx: PageTableContext<ContractorAchivement>;
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
const record = crudCtx.record;
return (
<CenterForm>
<ProForm
initialValues={record}
>
<ProFormText name="projname" label="项目名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormText name="projcode" label="合同编号" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="signtm" label="签订时间" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit name="contractsum" label="合同金额(万元)" width="sm" rules={[{ required: true }]} />
<ProFormDigit name="settlesum" label="结算金额(万元)" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="etm" label="合同期限" width="sm" />
<ProFormDatePicker name="settletm" label="实际履约期限" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="org" label="所属单位" width="sm" />
<ProFormText name="personel" label="现场负责人" width="sm" />
</ProForm.Group>
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,94 @@
import { DeleteOutlined, PlusCircleOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Col, Modal, Row, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import useCrud, { CrudContext } from '../../../../components/crud/useCrud';
import usePageTable from '../../../../components/crud/usePageTable';
import { ContractorAchivement, ContractorLog, PageResult } from '../../../../service/def';
import { renDigitFixed2, renYYYYMMDD } from '../../../../utils/renutil';
import DataForm from './DataForm';
type IProps = {
crudCtx: CrudContext;
}
async function demofind(contractorid: number): Promise<PageResult<ContractorAchivement>> {
return {
list: [
{
id: 1,
contractorid,
projcode: 'xxxx',
projname: 'assdfse',
signtm: new Date(),
contractsum: 123,
settlesum: 21,
etm: new Date(),
org: 'aaaa',
settletm: new Date(),
personel: 'xcz'
}
],
totalRow: 1
};
}
const AchivementList: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const parentRecord: ContractorLog = parentCrud.record || {};
const crud = useCrud();
const pager = usePageTable<ContractorAchivement>(() => demofind(parentRecord.id));
const columns = useMemo<ColumnsType<ContractorAchivement>>(() => [
{ title: '项目名称', key: 'projname', dataIndex: 'projname' },
{ title: '所属单位', key: 'org', dataIndex: 'org' },
{ title: '签订时间', key: 'signtm', dataIndex: 'signtm', render: renYYYYMMDD },
{ title: '合同编号', key: 'projcode', dataIndex: 'projcode' },
{ title: '合同金额(万元)', key: 'contractsum', dataIndex: 'contractsum', align: 'right', render: renDigitFixed2 },
{ title: '结算金额(万元)', key: 'settlesum', dataIndex: 'settlesum', align: 'right', render: renDigitFixed2 },
{ title: '合同期限', key: 'stm', dataIndex: 'etm', render: renYYYYMMDD },
{ title: '履约期限', key: 'settletm', dataIndex: 'settletm', render: renYYYYMMDD },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" onClick={() => crud.goto('mod', rec)} />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<>
<Table
rowKey="id"
columns={columns}
{...pager.tableProps}
/>
<div className="card-h-margin" />
<Row>
<Col flex="1 1 auto"></Col>
<Col flex="0 1 auto">
<Button icon={<PlusCircleOutlined />} onClick={() => crud.goto('new', null)}></Button>
</Col>
</Row>
{
crud.mode === 'mod' || crud.mode === 'new' ? (
<Modal maskClosable={false} visible footer={null} title={crud.record?.projname ?? '新增企业业绩'} onCancel={() => crud.goto(null, null)}>
<DataForm crudCtx={crud} pageCtx={pager} />
</Modal>
) : null
}
</>
)
}
export default AchivementList

View File

@ -0,0 +1,55 @@
import ProForm, { ProFormRadio, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../../components/crud/useCrud'
import { PageTableContext } from '../../../../components/crud/usePageTable'
import { ContractorPersonel } from '../../../../service/def'
type IProps = {
pageCtx: PageTableContext<ContractorPersonel>;
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
const record = crudCtx.record;
return (
<CenterForm>
<ProForm
initialValues={record}
>
<ProForm.Group>
<ProFormText name="name" label="姓名" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormRadio.Group
label="是否符合要求"
radioType="button"
options={['男', '女']}
required
rules={[{ required: true }]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText name="nativeplace" label="籍贯" width="sm" />
<ProFormText name="code" label="身份证号" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="zc" label="职称" width="sm" />
<ProFormText name="gw" label="岗位" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="zgzs" label="资格证书编号" width="sm" />
<ProFormText name="ldht" label="劳动合同备案号" width="sm" />
</ProForm.Group>
<ProFormTextArea name="remark" label="备注" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,90 @@
import { DeleteOutlined, PlusCircleOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Col, Modal, Row, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import useCrud, { CrudContext } from '../../../../components/crud/useCrud';
import usePageTable from '../../../../components/crud/usePageTable';
import { ContractorLog, ContractorPersonel, PageResult } from '../../../../service/def';
import DataForm from './DataForm';
type IProps = {
crudCtx: CrudContext;
}
async function demofind(contractorid: number): Promise<PageResult<ContractorPersonel>> {
return {
list: [
{
id: 1,
contractorid,
name: '张三',
sex: '男',
nativeplace: '湖北',
code: '420100214978419875',
zc: 'cccsafa',
gw: 'dafef',
zgzs: '3r23523563535',
ldht: '2352564362343',
}
],
totalRow: 1
};
}
const PersonelList: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const parentRecord: ContractorLog = parentCrud.record || {};
const crud = useCrud();
const pager = usePageTable<ContractorPersonel>(() => demofind(parentRecord.id));
const columns = useMemo<ColumnsType<ContractorPersonel>>(() => [
{ title: '姓名', key: 'name', dataIndex: 'name' },
{ title: '性别', key: 'sex', dataIndex: 'sex' },
{ title: '籍贯', key: 'nativeplace', dataIndex: 'nativeplace' },
{ title: '身份证号', key: 'code', dataIndex: 'code' },
{ title: '职称', key: 'zc', dataIndex: 'zc' },
{ title: '岗位', key: 'gw', dataIndex: 'gw' },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" onClick={() => crud.goto('mod', rec)} />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<>
<Table
rowKey="id"
columns={columns}
{...pager.tableProps}
/>
<div className="card-h-margin" />
<Row>
<Col flex="1 1 auto"></Col>
<Col flex="0 1 auto">
<Button icon={<PlusCircleOutlined />} onClick={() => crud.goto('new', null)}></Button>
</Col>
</Row>
{
crud.mode === 'mod' || crud.mode === 'new' ? (
<Modal visible footer={null} title={crud.record?.projname ?? '新增人员信息'} onCancel={() => crud.goto(null, null)}>
<DataForm crudCtx={crud} pageCtx={pager} />
</Modal>
) : null
}
</>
)
}
export default PersonelList

View File

@ -0,0 +1,52 @@
import ProCard from '@ant-design/pro-card';
import { Card, Descriptions } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import { CrudContext } from '../../../components/crud/useCrud';
import { ContractorInfo } from '../../../service/def';
import AchivementList from './Achivements';
import PersonelList from './Personel';
type IProps = {
crudCtx: CrudContext;
}
const ContractorAchievement: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const record: ContractorInfo = parentCrud.record || {};
return (
<>
<Card
title={record.name}
extra={<CancelCrud crudCtx={parentCrud} />}
>
<Descriptions>
<Descriptions.Item label="企业名称">{record.name}</Descriptions.Item>
<Descriptions.Item label="组织机构代码">{record.orgcode || '-'}</Descriptions.Item>
<Descriptions.Item label="企业简称">{record.name2 || '-'}</Descriptions.Item>
<Descriptions.Item label="企业类型">{record.type}</Descriptions.Item>
<Descriptions.Item label="注册资本">{record.regcapital}</Descriptions.Item>
<Descriptions.Item label="传真">{record.fax}</Descriptions.Item>
</Descriptions>
</Card>
<div className="card-h-margin" />
<ProCard
tabs={{ type: 'card', }}
headerBordered
>
<ProCard.TabPane key="tab1" tab="主要业绩台账">
<AchivementList crudCtx={parentCrud} />
</ProCard.TabPane>
<ProCard.TabPane key="tab2" tab="主要管理人员一览">
<PersonelList crudCtx={parentCrud} />
</ProCard.TabPane>
<ProCard.TabPane key="tab3" tab="主要技术人员一览">
<PersonelList crudCtx={parentCrud} />
</ProCard.TabPane>
</ProCard>
</>
)
}
export default ContractorAchievement

View File

@ -0,0 +1,56 @@
import ProForm, { ProFormDigit, ProFormSelect, ProFormText } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProForm.Group>
<ProFormText name="orgcode" label="组织机构代码" width="sm" rules={[{ required: true }]} />
<ProFormText name="name2" label="企业简称" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="name" label="企业名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormSelect name="type" label="企业类型" width="sm" rules={[{ required: true }]} options={['物资供应商']} />
<ProFormDigit name="regcapital" label="注册资本(万元)" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="fax" label="传真" width="sm" rules={[{ required: true }]} />
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProForm.Group>
<ProFormText name="fddbr" label="法定代表人" width="sm" rules={[{ required: true }]} />
<ProFormText name="fddbrcode" label="身份证号" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="jsfzr" label="技术负责人" width="sm" />
<ProFormText name="jsfzrcode" label="身份证号" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="wtdlr" label="委托代理人" width="sm" />
<ProFormText name="wtdlrcode" label="身份证号" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="contactor" label="企业联系人" width="sm" />
<ProFormText name="contactorphone" label="联系电话" width="sm" />
</ProForm.Group>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProForm.Group>
<ProFormText name="sqr" label="授权人姓名" width="sm" rules={[{ required: true }]} />
<ProFormText name="sqrphone" label="联系方式" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="sqrcode" label="身份证号" width="sm" rules={[{ required: true }]} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,55 @@
import { DeleteOutlined, PlusOutlined, ProfileOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, Input, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { ContractorLog } from '../../../service/def';
type IProps = {
pagerCtx: PageTableContext<ContractorLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<ContractorLog>>(() => [
{ title: '序号', key: 'id', dataIndex: 'id' },
{ title: '企业名称', key: 'name', dataIndex: 'name' },
{ title: '供应商类型', key: 'type', dataIndex: 'type' },
{ title: '组织机构代码', key: 'orgcode', dataIndex: 'orgcode' },
{ title: '企业性质', key: 'nature', dataIndex: 'nature' },
{ title: '注册资本', key: 'regcapital', dataIndex: 'regcapital' },
{ title: '联系人', key: 'contactor', dataIndex: 'contactor' },
{ title: '联系电话', key: 'contactorphone', dataIndex: 'contactorphone' },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" onClick={() => crudCtx.goto('info', rec)} />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>:<Input /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,57 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { ContractorLog, PageResult } from '../../../service/def';
import ContractorAchievement from '../ContractorAchievement';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(): Promise<PageResult<ContractorLog>> {
return {
list: [
{
id: 1,
orgcode: "21378644",
name: "中铁15局集团有限公司",
type: '承包商',
nature: '国有企业',
regcapital: 1,
contactor: '张三',
contactorphone: '13566667777',
}
],
totalRow: 1
};
}
const ContractorLogPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<ContractorLog>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="承包商登记" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
crud.mode === 'info' ? (
<ContractorAchievement crudCtx={crud} />
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default ContractorLogPage

View File

@ -0,0 +1,11 @@
import React from 'react'
const CompleteResPage = () => {
return (
<div>
</div>
)
}
export default CompleteResPage

View File

@ -0,0 +1,52 @@
import ProForm, { ProFormDigit, ProFormRadio, ProFormText, ProFormTextArea, ProFormUploadButton } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
type IProps = {
crudCtx: CrudContext
}
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
const record = crudCtx.record || {};
return (
<CenterForm>
<ProForm
initialValues={{
name: record.name
}}
onFinish={async (values) => {
console.log(values);
}}
>
<ProFormText name="name" label="名称" width={DEF_INPUT_LEN} disabled />
<Typography.Title type="secondary" level={5}></Typography.Title>
<ProFormDigit name="完成比例" label="完成比例(%)" width="sm" min={0} max={100} rules={[{ required: true }]} />
<ProFormRadio.Group
label="是否符合要求"
radioType="button"
options={['是', '否']}
required
rules={[{ required: true }]}
/>
<ProFormTextArea name="desc" label="合同总结内容" width={DEF_INPUT_LEN} />
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,23 @@
import { Card } from 'antd'
import React from 'react'
import CancelCrud from '../../../components/crud/CancelCrud'
import CenterForm from '../../../components/crud/CenterForm'
import { CrudContext } from '../../../components/crud/useCrud'
import DataForm from './DataForm'
type IProps = {
crudCtx: CrudContext
}
const ContractEvaluate: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
return (
<Card title="合同评价" extra={<CancelCrud crudCtx={parentCrud} />}>
<CenterForm>
<DataForm crudCtx={parentCrud} />
</CenterForm>
</Card>
)
}
export default ContractEvaluate

View File

@ -0,0 +1,65 @@
import { DeleteOutlined, InfoCircleOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, DatePicker, Input, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { ContractLog } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<ContractLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<ContractLog>>(() => [
{ title: '合同编号', key: 'code', dataIndex: 'code' },
{ title: '合同名称', key: 'name', dataIndex: 'name' },
{ title: '合同类型', key: 'type', dataIndex: 'type' },
{ title: '业主', key: 'proprietor', dataIndex: 'proprietor' },
{ title: '签订日期', key: 'signtm', dataIndex: 'signtm', align: 'center', render: renYYYYMMDD },
{ title: '状态', key: 'status', dataIndex: 'status', align: 'center' },
{
title: '操作', key: '_', render: (rec: ContractLog) => (
<Space>
<Button icon={<InfoCircleOutlined />} size='small' type="link" onClick={() => crudCtx.goto('mod', rec)} />
<Button icon={<DeleteOutlined />} size='small' type="link" danger />
{
rec.type === '施工合同' ? (
<Button type="link" size='small' onClick={() => crudCtx.goto('gcl', rec)}></Button>
) : null
}
{
rec.status === '执行中' ? (
<Button type="link" size='small' onClick={() => crudCtx.goto('eval', rec)}></Button>
) : null
}
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>:<Input /></Space>
<Space>:<DatePicker.RangePicker /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="code" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,67 @@
import ProForm, { ProFormDatePicker, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
import { PageTableContext } from '../../../components/crud/usePageTable'
import { ContractLog } from '../../../service/def'
type IProps = {
pagerCtx: PageTableContext<ContractLog>;
crudCtx: CrudContext
}
const ModForm: React.FC<IProps> = ({ crudCtx }) => {
const record: ContractLog = crudCtx.record || {};
return (
<CenterForm>
<ProForm
initialValues={{
code: record.code,
name: record.name,
status: record.status,
type: record.type,
signtm: record.signtm,
}}
onFinish={async (values) => {
console.log(values);
}}
>
<ProFormText name="code" label="合同编号" width={DEF_INPUT_LEN} disabled />
<ProFormText name="name" label="合同名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormSelect name="type" label="合同类型" width="sm" disabled options={['施工合同', '采购合同']} />
<ProFormSelect name="status" label="当前状态" width="sm" rules={[{ required: true }]} options={['执行中', '终止']} />
</ProForm.Group>
{
record.type === '施工合同' ? (
<ProFormSelect name="工程阶段" label="工程阶段" width="sm" rules={[{ required: true }]} options={['[C]项目实施阶段']} />
) : null
}
<ProForm.Group>
<ProFormDatePicker name="signtm" label="签订时间" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="生效时间" label="生效时间" width="sm" />
</ProForm.Group>
{
record.type === '施工合同' ? (
<ProFormDatePicker name="计划完工时间" label="计划完工时间" width="sm" />
) : null
}
<ProForm.Group>
<ProFormText name="管理部门" label="管理部门" width="sm" rules={[{ required: true }]} />
<ProFormText name="负责人" label="负责人" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormTextArea name="备注" label="备注" width={DEF_INPUT_LEN} />
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</ProForm>
</CenterForm>
)
}
export default ModForm;

View File

@ -0,0 +1,82 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormInstance, ProFormMoney, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton, StepsForm } from '@ant-design/pro-form'
import { message } from 'antd'
import React, { useRef } from 'react'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { waitTime } from '../../../utils/utils'
const SignForm: React.FC = () => {
const formRef = useRef<ProFormInstance>();
return (
<StepsForm
formRef={formRef}
onFinish={async () => {
await waitTime(1000);
message.success('提交成功');
}}
>
<StepsForm.StepForm
name="1"
title="合同基本信息"
onFinish={async () => {
console.log(formRef.current?.getFieldsValue());
await waitTime(500);
return true;
}}
>
<ProFormText name="code" label="合同编号" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="合同名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="主办部门" label="主办部门" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormSelect name="项目名称" label="项目名称" width={DEF_INPUT_LEN} options={['aaa', 'bbbb']} rules={[{ required: true }]} />
<ProFormRadio.Group
label="合同类型"
radioType="button"
options={['施工合同', '采购合同']}
rules={[{ required: true }]}
/>
<ProFormText name="经办人" label="经办人" width="sm" />
<ProFormText name="合同工期" label="合同工期" width="sm" />
<ProFormTextArea name="合同摘要" label="合同摘要" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormDigit name="打印份数" label="打印份数" width="sm" />
<ProFormDatePicker name="打印时间" label="打印时间" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit name="正本份数" label="正本份数" width="sm" />
<ProFormDigit name="副本份数" label="副本份数" width="sm" />
</ProForm.Group>
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</StepsForm.StepForm>
<StepsForm.StepForm
name="2"
title="签约单位基本信息"
>
<ProFormText name="签约单位(乙方)" label="签约单位(乙方)" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="签约单位地址" label="签约单位地址" width={DEF_INPUT_LEN} />
<ProFormText name="签约单位法人" label="签约单位法人" width="sm" />
<ProFormText name="邮编" label="邮编" width="sm" />
<ProForm.Group>
<ProFormText name="联系人" label="联系人" width="sm" />
<ProFormText name="联系人电话" label="联系人电话" width="sm" />
</ProForm.Group>
</StepsForm.StepForm>
<StepsForm.StepForm
name="3"
title="签约金额信息"
>
<ProFormMoney name="合同金额" label="合同金额" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="付款时间约定" label="付款时间约定" width={DEF_INPUT_LEN} />
<ProFormText name="付款方式约定" label="付款方式约定" width={DEF_INPUT_LEN} />
<ProFormText name="开户行" label="开户行" width={DEF_INPUT_LEN} />
<ProFormText name="帐户名" label="帐户名" width={DEF_INPUT_LEN} />
<ProFormText name="帐号" label="帐号" width={DEF_INPUT_LEN} />
</StepsForm.StepForm>
</StepsForm>
)
}
export default SignForm;

View File

@ -0,0 +1,77 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { ContractLog, PageResult } from '../../../service/def';
import ContractEvaluate from '../ContractEvaluate';
import ContractQuantity from '../ContractQuantity';
import DataTable from './DataTable';
import ModForm from './ModForm';
import SignForm from './SignForm';
async function demofind(): Promise<PageResult<ContractLog>> {
return {
list: [
{
code: "11111",
name: "test合同",
type: '施工合同',
proprietor: 'xxxxxxxxxxx',
signtm: new Date(),
status: '执行中',
},
{
code: "22222",
name: "test合同2",
type: '采购合同',
proprietor: 'xxxxxxxxxxx',
signtm: new Date(),
status: '终止',
},
],
totalRow: 2
};
}
const ContractLogPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<ContractLog>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="合同会签" extra={<CancelCrud crudCtx={crud} confirm />} >
<SignForm />
</Card>
) : null
}
{
crud.mode === 'mod' ? (
<Card key="mod" title={crud.record?.name || '-'} extra={<CancelCrud crudCtx={crud} />} >
<ModForm crudCtx={crud} pagerCtx={pager} />
</Card>
) : null
}
{
crud.mode === 'gcl' ? (
<ContractQuantity crudCtx={crud} />
) : null
}
{
crud.mode === 'eval' ? (
<ContractEvaluate crudCtx={crud} />
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default ContractLogPage

View File

@ -0,0 +1,50 @@
import ProForm, { ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
import { ContractQuantityItem } from '../../../service/def'
type IProps = {
crudCtx: CrudContext
}
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
const record: ContractQuantityItem = crudCtx.record || {};
return (
<CenterForm>
<ProForm
initialValues={record}
onFinish={async (values) => {
console.log(values);
}}
>
<ProForm.Group>
<ProFormText name="itemcode" label="编码" width="sm" disabled />
<ProFormText name="name" label="名称" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormSelect name="tasktype" label="任务类型" width="sm" options={[record.tasktype]} />
<ProFormSelect name="chargetype" label="费用科目" width="sm" options={[record.chargetype || '-']} />
<ProForm.Group>
<ProFormDigit name="sum" label="数量" width="sm" />
<ProFormSelect name="sumunit" label="(单位)" width="sm" options={['立方米']} />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit name="unitprice" label="单价" width="sm" />
<ProFormSelect name="priceunit" label="(单位)" width="sm" options={['人民币(元)']} />
</ProForm.Group>
<ProFormText name="estimate" label="概算" width={DEF_INPUT_LEN} />
<ProFormTextArea name="desc" label="项目特征" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,128 @@
import { DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons';
import ProCard from '@ant-design/pro-card';
import { Button, Card, Col, Row, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import CenterForm from '../../../components/crud/CenterForm';
import useCrud, { CrudContext } from '../../../components/crud/useCrud';
import { ContractQuantityNode, ProjectLog } from '../../../service/def';
import useRequest from '../../../utils/useRequest';
import DataForm from './DataForm';
type IProps = {
crudCtx: CrudContext
}
async function demodata(contractcode: string): Promise<ContractQuantityNode[]> {
return [{
contractcode,
itemcode: '1.1',
name: '[1.1]挡水工程',
tasktype: '',
projtype: '原始工程量清单',
children: []
}, {
contractcode,
itemcode: '1.2',
name: '[1.2]泄洪工程',
tasktype: '',
projtype: '原始工程量清单',
children: [{
contractcode,
itemcode: '1.2.1',
name: '[1.2.1]上坝址表孔溢洪洞',
tasktype: '',
projtype: '原始工程量清单',
children: [{
contractcode,
itemcode: '1.2.1.1',
name: '[1.2.1.1]1#表孔溢洪洞',
tasktype: '',
projtype: '原始工程量清单',
children: [{
contractcode,
itemcode: '1.2.1.1.1',
name: '[1.2.1.1.1]进口段',
tasktype: '',
projtype: '原始工程量清单',
children: [{
contractcode,
itemcode: '1.2.1.1.1.1',
name: '[1.2.1.1.1.1]石明挖方',
tasktype: '[0202]石明挖方',
projtype: '原始工程量清单',
chargetype: '同时计入当前和原始金额',
sum: 89306,
sumunit: '立方米',
unitprice: 41.51,
priceunit: '人民币',
estimate: '[111223422]石明挖方',
}]
}]
}]
}]
}];
}
const ContractQuantity: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const parentRecord: ProjectLog = parentCrud.record || {};
let { data, loading } = useRequest(() => demodata(parentRecord.code));
const columns = useMemo<ColumnsType<ContractQuantityNode>>(() => [
{ title: '名称', key: 'name', dataIndex: 'name', width: '50%' },
{ title: '任务类型', key: 'tasktype', dataIndex: 'tasktype', width: '25%' },
{ title: '项目类型', key: 'projtype', dataIndex: 'projtype', width: '25%' },
], []);
const crud = useCrud();
const record = crud.record;
return (
<Row gutter={[16, 16]}>
<Col span={14}>
<ProCard
title="工程量清单"
extra={<CancelCrud crudCtx={parentCrud} />}
>
<Table
rowKey="itemcode"
dataSource={data}
loading={loading}
columns={columns}
size="small"
bordered
pagination={false}
rowSelection={{
type: 'radio',
onSelect: (r) => {
crud.goto('mod', r)
}
}}
/>
</ProCard>
</Col>
<Col span={10}>
<Card title="明细信息" extra={
<Space>
{Array.isArray(crud.record?.children) ? <Button type="link" icon={<PlusCircleOutlined />} size="small"></Button> : null}
<Button type="link" size="small" icon={<DeleteOutlined />}></Button>
</Space>
}>
{
crud.record ? (
<CenterForm key={record.itemcode}>
<DataForm crudCtx={crud} />
</CenterForm>
) : null
}
</Card>
</Col>
</Row>
)
}
export default ContractQuantity

View File

@ -0,0 +1,30 @@
import ProForm, { ProFormDatePicker, ProFormText, ProFormTextArea, ProFormUploadButton } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<ProFormText name="name" label="成果版本" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormText name="name" label="版本号" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="tm" label="提交时间" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormTextArea name="name" label="备注" width={DEF_INPUT_LEN} />
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,34 @@
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignAssetsVersion } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<DesignAssetsVersion>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<DesignAssetsVersion>>(() => [
{ title: '成果版本', key: 'name', dataIndex: 'name' },
{ title: '版本号', key: 'version', dataIndex: 'version' },
{ title: '提交时间', key: 'tm', dataIndex: 'tm', render: renYYYYMMDD },
{ title: '备注', key: 'remark', dataIndex: 'remark' },
{ title: '附件', key: 'attachments', dataIndex: 'attachments', render: (val: string[]) => <Space>{val.map(v => <Button key={v} size="small" type="link">{v}</Button>)}</Space> },
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,78 @@
import { Button, Card, Descriptions, Modal, Space } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud, { CrudContext } from '../../../components/crud/useCrud';
import usePageTable, { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignAssets, DesignAssetsVersion, PageResult } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from '../AssetsVersion/DataForm';
import DataTable from '../AssetsVersion/DataTable';
type IProps = {
pagerCtx: PageTableContext<DesignAssets>;
crudCtx: CrudContext;
};
async function demofind(): Promise<PageResult<DesignAssetsVersion>> {
return {
list: [
{ id: 1, name: 'asdefsdfs', version: '0.1', tm: demoDate(1), attachments: ['aaaa.0.1.docx', 'aaaa.0.1.pdf'], remark: 'first commit' },
{ id: 2, name: 'asdefsdfs', version: '0.2', tm: demoDate(2), attachments: ['aaaa.0.2.docx', 'aaaa.0.2.pdf'] },
{ id: 3, name: 'asdefsdfs', version: '0.3', tm: demoDate(3), attachments: ['aaaa.0.3.docx', 'aaaa.0.3.pdf'] },
{ id: 4, name: 'asdefsdfs', version: '0.4', tm: demoDate(4), attachments: ['aaaa.0.4.docx', 'aaaa.0.4.pdf'] },
{ id: 5, name: 'asdefsdfs', version: '0.5', tm: demoDate(5), attachments: ['aaaa.0.5.docx', 'aaaa.0.5.pdf'] },
{ id: 6, name: 'asdefsdfs', version: '0.6', tm: demoDate(6), attachments: ['aaaa.0.6.docx', 'aaaa.0.6.pdf'] },
{ id: 7, name: 'asdefsdfs', version: '0.7', tm: demoDate(7), attachments: ['aaaa.0.7.docx', 'aaaa.0.7.pdf'] },
{ id: 8, name: 'asdefsdfs', version: '0.8', tm: demoDate(8), attachments: ['aaaa.0.8.docx', 'aaaa.0.8.pdf'] },
],
totalRow: 1
};
}
const AssetsVersionList: React.FC<IProps> = ({ crudCtx }) => {
const record: DesignAssets = crudCtx.record;
const pager = usePageTable<DesignAssetsVersion>(demofind);
const crud = useCrud();
return (
<>
<Card title={record.name} extra={<CancelCrud crudCtx={crudCtx} text="返回成果列表" />}>
<Descriptions>
<Descriptions.Item label="设计任务包">{record.packname}</Descriptions.Item>
<Descriptions.Item label="成果编号">{record.no}</Descriptions.Item>
<Descriptions.Item label="成果类型">{record.no}</Descriptions.Item>
<Descriptions.Item label="图号">{record.no}</Descriptions.Item>
<Descriptions.Item label="设计人">{record.no}</Descriptions.Item>
<Descriptions.Item label="提交人">{record.no}</Descriptions.Item>
<Descriptions.Item label="备注" span={3}>{record.no}</Descriptions.Item>
<Descriptions.Item label="关键字" span={3}>{record.keyword ? <Space>{record.keyword.map(o => <span key={o}>{o}</span>)}</Space> : null}</Descriptions.Item>
</Descriptions>
</Card>
<div className="card-h-margin" />
<Card
title="版本列表"
extra={(
<Button type="link" size="small" onClick={() => crud.goto('new', null)}></Button>
)}
>
<DataTable pagerCtx={pager} crudCtx={crud} />
</Card>
{
crud.mode === 'new' ? (
<Modal maskClosable={false} visible footer={null} title={crud.record?.projname ?? '提交成果'} onCancel={() => crud.goto(null, null)}>
<DataForm />
</Modal>
) : null
}
</>
)
}
export default AssetsVersionList

View File

@ -0,0 +1,49 @@
import ProForm, { ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React, { useMemo } from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
import { DesignAssets } from '../../../service/def'
type IProps = {
crudContext: CrudContext;
}
const DataForm: React.FC<IProps> = ({ crudContext }) => {
const record: DesignAssets | null = crudContext.record ?? null;
const initDemoVals = useMemo(() => ({
projs: ['test项目'],
packs: [record?.packname || 'test设计包'],
}), [])
return (
<CenterForm>
<ProForm initialValues={record || {}}>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormSelect name="proj" width={DEF_INPUT_LEN} label="项目" options={initDemoVals.projs} />
<ProFormSelect name="packname" width={DEF_INPUT_LEN} label="任务包" options={initDemoVals.packs} />
<ProForm.Group>
<ProFormText name="code" label="成果编号" width="sm" rules={[{ required: true }]} />
<ProFormSelect name="type" label="成果类型" width="sm" rules={[{ required: true }]} options={['科研试验成果类']} />
</ProForm.Group>
<ProFormText name="no" label="图号" width="sm" rules={[{ required: true }]} />
<ProFormText name="name" label="成果名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="keyword" label="关键字" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormText name="desperosnel" label="设计人" width="sm" />
<ProFormText name="commiter" label="提交人" width="sm" />
</ProForm.Group>
<ProFormTextArea name="remark" label="备注" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,49 @@
import { DeleteOutlined, EyeOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import OpButton from '../../../components/crud/OpButton';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignAssets } from '../../../service/def';
type IProps = {
pagerCtx: PageTableContext<DesignAssets>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<DesignAssets>>(() => [
{ title: '设计任务包', key: 'packname', dataIndex: 'packname' },
{ title: '成果编号', key: 'code', dataIndex: 'code' },
{ title: '类型', key: 'type', dataIndex: 'type' },
{ title: '图号', key: 'no', dataIndex: 'no' },
{ title: '设计人', key: 'despersonel', dataIndex: 'despersonel' },
{
title: '当前版本', key: 'version', render: rec => (
<Space>{rec.version}<Button type="link" size="small" icon={<EyeOutlined />} onClick={() => crudCtx.goto('versionList', rec)}></Button></Space>
)
},
{
title: '操作', key: 'op', render: rec => (
<Space>
<OpButton icon={<ProfileOutlined />} onClick={() => crudCtx.goto('mod', rec)} />
<OpButton icon={<DeleteOutlined />} danger />
<OpButton text="评审" onClick={() => crudCtx.goto('eval', rec)} />
</Space>
)
}
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,21 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignAssets } from '../../../service/def';
type IProps = {
pagerCtx: PageTableContext<DesignAssets>;
crudCtx: CrudContext;
};
const EvalForm: React.FC<IProps> = ({ crudCtx }) => {
return (
<Card title="评审" extra={<CancelCrud crudCtx={crudCtx} />}>
</Card>
)
}
export default EvalForm

View File

@ -0,0 +1,149 @@
import { PlusOutlined } from '@ant-design/icons';
import { Button, Card, Col, Input, Row, Space, Tree } from 'antd';
import React, { useState } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { DesignAssets, PageResult, SearchOption } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import AssetsVersionList from './AssetsVersionList';
import DataForm from './DataForm';
import DataTable from './DataTable';
import EvalForm from './EvalForm';
async function demofind(params?: SearchOption): Promise<PageResult<DesignAssets>> {
if (!params || !params.search?.packname) {
return { list: [], totalRow: 0 };
}
return {
list: [
{
id: 1,
packid: 1,
packname: params.search.packname,
code: 'ATS.GJFGJ-04',
type: '科研试验成果类',
name: '深空放空排沙泄洪洞设计',
no: 'ATS.GJFGJ-04',
keyword: ['a', 'adfasf', 'afeferf'],
despersonel: 'sdaff',
version: '1.6',
},
{
id: 2,
packid: 2,
packname: params.search.packname,
code: 'sdasfafe',
type: '科研试验成果类',
name: 'cccccccc',
no: 'ATS.GJFGJ-04',
keyword: ['a', 'adfasf', 'afeferf'],
despersonel: 'sdaff',
version: '0.6',
}
],
totalRow: 1
};
}
const treeData = [
{
title: '溪水砂场项目',
key: '溪水砂场项目',
selectable: false,
children: [
{ title: '任务包1', key: '溪水砂场项目-任务包1' },
{ title: '任务包2', key: '溪水砂场项目-任务包2' },
],
},
{
title: '项目2',
key: '项目2',
selectable: false,
children: [
],
},
];
const DesignAssetsPage: React.FC = () => {
const [packname, setPackname] = useState<string | undefined>();
const crud = useCrud();
const pager = usePageTable<DesignAssets>(demofind);
const record = crud.record;
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增招标信息" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm crudContext={crud} />
</Card>
) : null
}
{
crud.mode === 'mod' ? (
<Card key="mod" title={record.name} extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm crudContext={crud} />
</Card>
) : null
}
{
crud.mode === 'versionList' ? (
<AssetsVersionList crudCtx={crud} pagerCtx={pager} />
) : null
}
{
crud.mode === 'eval' ? (
<EvalForm crudCtx={crud} pagerCtx={pager} />
) : null
}
{
!crud.mode ? (
<Row gutter={16}>
<Col span={6}>
<Card style={{ minHeight: 800 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Input.Search />
<Tree.DirectoryTree
defaultExpandAll
treeData={treeData}
multiple={false}
onSelect={(selkeys) => {
const packname = selkeys?.[0] as string;
setPackname(packname);
pager.search({ search: { packname } })
}}
/>
</Space>
</Card>
</Col>
<Col span={18}>
<Card
title={packname ? `设计成果列表(${packname})` : '(选择设计任务包查看包成果信息)'}
extra={packname ? (
<Button type="link" size="small" icon={<PlusOutlined />}
onClick={() => crud.goto('new', {})}></Button>) : null}
>
<DataTable crudCtx={crud} pagerCtx={pager} />
</Card>
</Col>
</Row>
) : null
}
</div>
)
}
export default DesignAssetsPage

View File

@ -0,0 +1,41 @@
import ProForm, { ProFormDatePicker, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm: React.FC = () => {
return (
<CenterForm>
<ProForm>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormSelect name="descontract" width={DEF_INPUT_LEN} label="设计合同" />
<ProForm.Group>
<ProFormText name="no" label="变更单号" width="sm" />
<ProFormText name="name" label="名称" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="imgnum" label="变更原因" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormTextArea name="status" label="具体原因" width={DEF_INPUT_LEN} />
<ProFormRadio.Group name="allectlv" label="影响程度" radioType="button" rules={[{ required: true }]} options={['小', '一般', '大', '很大']} />
<ProFormTextArea name="affectproc" label="进度影响" width={DEF_INPUT_LEN} />
<ProFormTextArea name="affextinvest" label="投资影响" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormDatePicker name="stm1" label="计划开始时间" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="etm1" label="计划提交时间" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="stm2" label="实际开始时间" width="sm" />
<ProFormDatePicker name="etm2" label="实际提交时间" width="sm" />
</ProForm.Group>
<ProFormTextArea name="remark" label="备注" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,43 @@
import { DeleteOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignChangeLog } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<DesignChangeLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<DesignChangeLog>>(() => [
{ title: '变更名称', key: 'name', dataIndex: 'name' },
{ title: '变更单号', key: 'no', dataIndex: 'no' },
{ title: '变更原因', key: 'reason', dataIndex: 'reason' },
{ title: '影响程度', key: 'affectlv', dataIndex: 'affectlv', align: 'center' },
{ title: '计划开始时间', key: 'stm1', dataIndex: 'etm1', align: 'center', render: renYYYYMMDD },
{ title: '计划提交时间', key: 'etm1', dataIndex: 'stm1', align: 'center', render: renYYYYMMDD },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,113 @@
import { PlusOutlined } from '@ant-design/icons';
import { Button, Card, Col, Input, Row, Space, Tree } from 'antd';
import React, { useState } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { DesignChangeLog, PageResult, SearchOption } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(params?: SearchOption): Promise<PageResult<DesignChangeLog>> {
if (!params || !params.search?.descontract) {
return { list: [], totalRow: 0 };
}
return {
list: [
{
id: 1,
descontract: params.search!.descontract,
no: '00005',
name: '导流洞设计变更',
reason: '业主变更',
affectlv: '一般',
stm1: demoDate(10),
etm1: demoDate(120),
}
],
totalRow: 1
};
}
const treeData = [
{
title: '溪水砂场项目',
key: '溪水砂场项目',
selectable: false,
children: [
{ title: '设计合同1', key: '溪水砂场项目-设计合同1', isLeaf: true },
{ title: '设计合同2', key: '溪水砂场项目-设计合同2', isLeaf: true },
],
},
{
title: '项目2',
key: '项目2',
selectable: false,
children: [
{ title: '设计合同1', key: '项目2-设计合同1', isLeaf: true },
],
},
];
const DesignChangeLogPage: React.FC = () => {
const [descontract, setDescontract] = useState<string | undefined>();
const crud = useCrud();
const pager = usePageTable<DesignChangeLog>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增变更信息" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
!crud.mode ? (
<Row gutter={16}>
<Col span={6}>
<Card style={{ minHeight: 800 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Input.Search />
<Tree.DirectoryTree
defaultExpandAll
treeData={treeData}
multiple={false}
onSelect={(selkeys) => {
const descontract = selkeys?.[0] as string;
setDescontract(descontract);
pager.search({ search: { descontract } })
}}
/>
</Space>
</Card>
</Col>
<Col span={18}>
<Card
title={descontract ? `设计变更列表(${descontract})` : '(选择设计合同查看设计变更信息)'}
extra={descontract ? (
<Button type="link" size="small" icon={<PlusOutlined />}
onClick={() => crud.goto('new', {})}></Button>) : null}
>
<DataTable crudCtx={crud} pagerCtx={pager} />
</Card>
</Col>
</Row>
) : null
}
</div>
)
}
export default DesignChangeLogPage

View File

@ -0,0 +1,47 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormRadio, ProFormSelect, ProFormText } from '@ant-design/pro-form'
import { Typography } from 'antd'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
const DataForm: React.FC<{
crudCtx: CrudContext
}> = ({ crudCtx }) => {
const record = crudCtx.record || {};
return (
<CenterForm>
<ProForm initialValues={record}>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormSelect name="proj" width={DEF_INPUT_LEN} label="项目" disabled={record.proj} rules={[{ required: true }]} />
<ProFormSelect name="descontract" width={DEF_INPUT_LEN} label="设计合同" />
<ProForm.Group>
<ProFormText name="code" label="编码" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
</ProForm.Group>
<ProFormDigit name="imgnum" label="图纸张数" width="sm" rules={[{ required: true }]} />
<ProFormRadio.Group name="status" label="状态" radioType="button" rules={[{ required: true }]} options={['设计', '评审', '完成']} />
<ProFormRadio.Group name="evalmethod" label="评审方式" radioType="button" rules={[{ required: true }]} options={['在线评审', '线下评审']} />
<ProForm.Group>
<ProFormDatePicker name="evaltm" label="计划评审时间" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="evaldonetm" label="实际评审时间" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="pubtm" label="计划发布时间" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="pubdonetm" label="实际发布时间" width="sm" />
</ProForm.Group>
<Typography.Title level={5} type="secondary"></Typography.Title>
<ProFormText name="desorg" label="设计单位" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="despersonel" label="设计人" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormSelect name="desorg" label="施工合同" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,43 @@
import { DeleteOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { DesignPackage } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<DesignPackage>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<DesignPackage>>(() => [
{ title: '任务包名称', key: 'name', dataIndex: 'name' },
{ title: '任务包编码', key: 'code', dataIndex: 'code' },
{ title: '图纸数', key: 'imgnum', dataIndex: 'imgnum' },
{ title: '设计单位', key: 'desorg', dataIndex: 'desorg' },
{ title: '状态', key: 'status', dataIndex: 'status' },
{ title: '计划评审时间', key: 'evaltm', dataIndex: 'evaltm', render: renYYYYMMDD },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,125 @@
import { PlusOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Card, Col, Input, Menu, Row, Space, Tree } from 'antd';
import React, { useState } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { DesignPackage, PageResult, SearchOption } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(params?: SearchOption): Promise<PageResult<DesignPackage>> {
if (!params || !params.search?.proj) {
return { list: [], totalRow: 0 };
}
return {
list: [
{
id: 1,
proj: params.search!.proj,
constructcontract: '合同asfef',
code: '254235',
name: 'asfef',
imgnum: 3,
status: '设计',
evalmethod: '线下评审',
evaltm: demoDate(100),
pubtm: demoDate(120),
desorg: 'asdaef',
desperonel: '张三',
}
],
totalRow: 1
};
}
const treeData = [
{
title: '溪水砂场项目',
key: '溪水砂场项目',
},
{
title: '项目2',
key: '项目2',
},
{
title: '项目3',
key: '项目3',
},
{
title: '项目4',
key: '项目4',
},
{
title: '项目5',
key: '项目5',
},
];
const DesignPackagePage: React.FC = () => {
const [proj, setProj] = useState<string | undefined>();
const crud = useCrud();
const pager = usePageTable<DesignPackage>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增招标信息" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm crudCtx={crud} />
</Card>
) : null
}
{
!crud.mode ? (
<Row gutter={16}>
<Col span={6}>
<Card style={{ minHeight: 800 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Input.Search />
<Menu
mode="inline"
theme="light"
onSelect={(props) => {
const proj = props.key;
setProj(proj);
pager.search({ search: { proj } })
}}
>
{
treeData.map(o => (
<Menu.Item key={o.key} icon={<ProfileOutlined />}>{o.title}</Menu.Item>
))
}
</Menu>
</Space>
</Card>
</Col>
<Col span={18}>
<Card
title={proj ? `设计任务包列表(${proj})` : '(选择项目查看设计包信息)'}
extra={proj ? (
<Button type="link" size="small" icon={<PlusOutlined />}
onClick={() => crud.goto('new', { proj })}></Button>) : null}
>
<DataTable crudCtx={crud} pagerCtx={pager} />
</Card>
</Col>
</Row>
) : null
}
</div>
)
}
export default DesignPackagePage

View File

@ -0,0 +1,11 @@
import React from 'react'
const Error404: React.FC = () => {
return (
<div>
404
</div>
)
}
export default Error404

View File

@ -0,0 +1,28 @@
import ProForm, { ProFormDatePicker, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
type IProps = {
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
return (
<CenterForm>
<ProForm initialValues={crudCtx.record || {}}>
<ProFormSelect name="proj" width={DEF_INPUT_LEN} disabled label="项目" />
<ProFormText name="name" label="大事记" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormDatePicker name="tm" label="时间" width="sm" rules={[{ required: true }]} />
<ProFormTextArea name="remark" label="详情" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,41 @@
import { DeleteOutlined, ProfileOutlined } from '@ant-design/icons';
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { EngineeringMemorabilia } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<EngineeringMemorabilia>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<EngineeringMemorabilia>>(() => [
{ title: '事记名称', key: 'name', dataIndex: 'name' },
{ title: '时间', key: 'tm', dataIndex: 'tm', align: 'center', render: renYYYYMMDD },
{ title: '事记名称', key: 'creator', dataIndex: 'creator' },
{ title: '详情', key: 'desc', dataIndex: 'desc' },
{
title: '操作', key: '_', render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,34 @@
import { Timeline, Typography } from 'antd'
import React from 'react'
import { CrudContext } from '../../../components/crud/useCrud'
import { PageTableContext } from '../../../components/crud/usePageTable'
import { EngineeringMemorabilia } from '../../../service/def'
import { renYYYYMMDD } from '../../../utils/renutil'
type IProps = {
pagerCtx: PageTableContext<EngineeringMemorabilia>;
crudCtx: CrudContext
}
const TimelineView: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const demodata = pagerCtx?.tableProps?.dataSource || [];
return (
<Timeline mode="alternate">
{
demodata.map(o => (
<Timeline.Item
key={o.id}
label={renYYYYMMDD(o.tm)}
>
<Typography.Title level={5}>{o.name}</Typography.Title>
<Typography.Text type="secondary">{o.desc}</Typography.Text>
</Timeline.Item>
))
}
</Timeline>
)
}
export default TimelineView

View File

@ -0,0 +1,149 @@
import { PicCenterOutlined, PlusOutlined, ProfileOutlined } from '@ant-design/icons';
import { Card, Col, Input, Menu, Row, Space } from 'antd';
import React, { useState } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import OpButton from '../../../components/crud/OpButton';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { EngineeringMemorabilia, PageResult, SearchOption } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
import DataTable from './DataTable';
import TimelineView from './TimelineView';
async function demofind(params?: SearchOption): Promise<PageResult<EngineeringMemorabilia>> {
if (!params || !params.search?.proj) {
return { list: [], totalRow: 0 };
}
return {
list: [
{
id: 1,
name: '2#引水洞施工完毕',
proj: params.search!.proj,
tm: demoDate(0),
creator: 'admin',
desc: 'skhlaeiulfagnlruighlufadsknfaweipurhpogarg',
},
{
id: 2,
name: '1#引水洞施工完毕',
proj: params.search!.proj,
tm: demoDate(2),
creator: 'admin',
desc: 'skhlaeiulfagnlruighlufadsknfaweipurhpogarg',
},
{
id: 3,
name: '大坝主体开始施工',
proj: params.search!.proj,
tm: demoDate(10),
creator: 'admin',
desc: 'skhlaeiulfagnlruighlufadsknfaweipurhpogarg',
},
],
totalRow: 1
};
}
const treeData = [
{
title: '溪水砂场项目',
key: '溪水砂场项目',
},
{
title: '项目2',
key: '项目2',
},
{
title: '项目3',
key: '项目3',
},
{
title: '项目4',
key: '项目4',
},
{
title: '项目5',
key: '项目5',
},
];
const EngineeringMemorabiliaPage: React.FC = () => {
const [proj, setProj] = useState<string | undefined>();
const crud = useCrud();
const pager = usePageTable<EngineeringMemorabilia>(demofind);
const [mode, setMode] = useState('表格');
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增项目大事记" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm crudCtx={crud} />
</Card>
) : null
}
{
!crud.mode ? (
<Row gutter={16}>
<Col span={6}>
<Card style={{ minHeight: 800 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Input.Search />
<Menu
mode="inline"
theme="light"
onSelect={(props) => {
const proj = props.key;
setProj(proj);
pager.search({ search: { proj } })
}}
>
{
treeData.map(o => (
<Menu.Item key={o.key} icon={<ProfileOutlined />}>{o.title}</Menu.Item>
))
}
</Menu>
</Space>
</Card>
</Col>
<Col span={18}>
<Card
title={proj ? `大事记列表(${proj})` : '(选择项目查看项目大事记)'}
extra={proj ? (
<Space>
<OpButton icon={<PicCenterOutlined />} onClick={() => setMode(mode === '表格' ? '时间轴' : '表格')} text={mode} />
<OpButton icon={<PlusOutlined />} onClick={() => crud.goto('new', { proj })} text="新建" />
</Space>
) : null}
>
{
mode === '表格' ? (
<DataTable crudCtx={crud} pagerCtx={pager} />
) : (
<TimelineView crudCtx={crud} pagerCtx={pager} />
)
}
</Card>
</Col>
</Row>
) : null
}
</div>
)
}
export default EngineeringMemorabiliaPage

View File

@ -0,0 +1,41 @@
import ProForm, { ProFormDatePicker, ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
type IProps = {
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
let record = crudCtx.record || {};
record = {
...record,
...record.props
}
return (
<CenterForm>
<ProForm initialValues={record}>
<ProFormSelect name="projname" label="项目名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="projadmin" label="项目经理" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormDatePicker name="stm" label="计划开工日期" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="etm" label="计划完工日期" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="工期" label="工期" width='sm' />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,66 @@
import { DeleteOutlined, InfoCircleOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, DatePicker, Input, Select, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import OpButton from '../../../components/crud/OpButton';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { ProjProgressLog } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<ProjProgressLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<ProjProgressLog>>(() => [
{ title: '项目名称', key: 'projname', dataIndex: 'projname' },
{ title: '项目状态', key: 'status', dataIndex: 'status' },
{ title: '业主', key: 'proprietor', dataIndex: 'proprietor' },
{ title: '项目经理', key: 'projadmin', dataIndex: 'projadmin' },
{ title: '计划开工日期', key: 'stm', dataIndex: 'stm', align: 'center', render: renYYYYMMDD },
{ title: '计划完工日期', key: 'etm', dataIndex: 'etm', align: 'center', render: renYYYYMMDD },
{
title: '操作', key: '_', render: (rec: ProjProgressLog) => (
<Space>
<OpButton text='详细计划' onClick={() => crudCtx.goto('wbs', rec)} />
<OpButton text='进度甘特图' onClick={() => crudCtx.goto('gantt', rec)} />
<OpButton icon={<DeleteOutlined />} danger />
</Space>
)
}
], []);
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>:<Input /></Space>
<Space>
:
<Select style={{ width: 120 }}>
<Select.Option value="未开工"></Select.Option>
<Select.Option value="已开工"></Select.Option>
<Select.Option value="已完工"></Select.Option>
</Select>
</Space>
<Space>:<DatePicker.RangePicker /></Space>
<Space>:<DatePicker.RangePicker /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table rowKey="code" columns={columns} {...pagerCtx.tableProps} />
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,80 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { PageResult, ProjProgressLog } from '../../../service/def';
import { demoDate } from '../../../utils/utils';
import ProjectSchedule from '../Schedule/ProjectSchedule';
import WbsCard from '../Wbs/WbsCard';
import DataTable from './DataTable';
import DataForm from './DataForm';
async function demofind(): Promise<PageResult<ProjProgressLog>> {
return {
list: [
{
id: 1,
projname: "test合同",
proprietor: 'xxxxxxxxxxx',
stm: demoDate(10),
etm: demoDate(100),
status: '未开工',
projadmin: 'xxx',
period: '',
},
{
id: 2,
projname: "test合同2",
proprietor: 'xxxxxxxxxxx',
stm: demoDate(-10),
etm: demoDate(200),
status: '已开工',
projadmin: 'zzzz',
period: '',
},
],
totalRow: 2
};
}
const ProjProgressLogPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<ProjProgressLog>(demofind);
const record = crud.record || {};
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="新增项目计划" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm crudCtx={crud} />
</Card>
) : null
}
{
crud.mode === 'wbs' ? (
<Card key="wbs" title={`项目详细计划(${record.projname})`} extra={<CancelCrud crudCtx={crud} />} >
<WbsCard crudCtx={crud} />
</Card>
) : null
}
{
crud.mode === 'gantt' ? (
<Card key="gantt" title="进度甘特图(${record.projname})" extra={<CancelCrud crudCtx={crud} />} >
<ProjectSchedule crudCtx={crud} />
</Card>
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default ProjProgressLogPage

View File

@ -0,0 +1,50 @@
import ProForm, { ProFormDigit, ProFormText } from '@ant-design/pro-form'
import React from 'react'
import { useSelector } from 'react-redux'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { RootState } from '../../../models/store'
const DataForm: React.FC = () => {
const crud = useSelector((s: RootState) => s.progress.scheduleCrud)!;
let initVal: any = crud.mode === 'new' ? {
_parent: crud.record.name
} : {
...crud.record,
...crud.record.props
};
return (
<CenterForm>
<ProForm initialValues={initVal}>
{
initVal?._parent ? (
<ProFormText name="_parent" label="所属WBS" readonly width={DEF_INPUT_LEN} />
) : null
}
<ProForm.Group>
<ProFormText name="id" label="作业编码" width="sm" rules={[{ required: true }]} />
<ProFormText name="name" label="作业名称" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="type" label="作业类型" width="sm" rules={[{ required: true }]} />
<ProFormText name="schedule" label="工期类型" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormText name="calendar" label="作业日历" width="sm" rules={[{ required: true }]} />
<ProFormDigit name="progress" label="完成百分比" min={0} max={100} width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="org" label="责任单位" width={DEF_INPUT_LEN} />
<ProFormText name="personels" label="责任人" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,253 @@
import { Card, Modal, Radio, Space } from 'antd';
import { Gantt, Task, ViewMode } from 'gantt-task-react';
import "gantt-task-react/dist/index.css";
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import CancelCrud from '../../../components/crud/CancelCrud';
import { CrudContext } from '../../../components/crud/useCrud';
import { Dispatch, RootState } from '../../../models/store';
import { Schedule, ScheduleProps } from '../../../service/def';
import useRequest from '../../../utils/useRequest';
import { demoDate } from '../../../utils/utils';
import { TaskListHeader } from './components/task-list-header';
import { TaskListTable } from './components/task-list-table';
import DataForm from './DataForm';
type IProps = {
crudCtx: CrudContext;
}
let id = 1;
const wbsProps: ScheduleProps = { wbs: true, level: '单项工程', status: '未开工', phase: '[C]项目实时阶段', };
const taskProps: ScheduleProps = { task: true, type: 'xxxxx', calendar: 'xxxxx', schedule: 'xxxxxx' };
async function demodata(): Promise<Schedule[]> {
return [{
id: `${id++}`,
name: '工程里程碑',
stm1: demoDate(2),
etm1: demoDate(100),
props: wbsProps,
progress: 77,
_indent: 1,
children: [
{
id: `${id++}`,
name: '正式开工',
stm1: demoDate(2),
etm1: demoDate(2),
_indent: 2,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: '完成导流洞施工',
stm1: demoDate(20),
etm1: demoDate(20),
_indent: 2,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: '开始下闸蓄水',
stm1: demoDate(50),
etm1: demoDate(50),
_indent: 2,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: '完工',
stm1: demoDate(100),
etm1: demoDate(100),
_indent: 2,
props: taskProps,
progress: 77,
},
]
}, {
id: `${id++}`,
name: '设计任务',
stm1: demoDate(2),
etm1: demoDate(10),
props: wbsProps,
_indent: 1,
progress: 77,
children: [
{
id: `${id++}`,
name: '详细设计',
stm1: demoDate(2),
etm1: demoDate(8),
_indent: 2,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: '评审',
stm1: demoDate(8),
etm1: demoDate(10),
_indent: 2,
props: taskProps,
progress: 77,
},
]
}, {
id: `${id++}`,
name: '采购任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: [
{
id: `${id++}`,
name: '详细设计',
stm1: demoDate(11),
etm1: demoDate(20),
props: wbsProps,
_indent: 2,
progress: 77,
children: [
{
id: `${id++}`,
name: 'asfgiywefb',
stm1: demoDate(11),
etm1: demoDate(13),
_indent: 3,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: 'asfaefuijkbsdv',
stm1: demoDate(13),
etm1: demoDate(15),
_indent: 3,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: 'asfkugasvuig',
stm1: demoDate(15),
etm1: demoDate(17),
_indent: 3,
props: taskProps,
progress: 77,
},
{
id: `${id++}`,
name: 'asfaefrgwg',
stm1: demoDate(17),
etm1: demoDate(20),
_indent: 3,
props: taskProps,
progress: 77,
},
]
},
{
id: `${id++}`,
name: '评审',
stm1: demoDate(23),
etm1: demoDate(40),
_indent: 2,
props: taskProps,
progress: 77,
},
]
}, {
id: `${id++}`,
name: '施工任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: []
}, {
id: `${id++}`,
name: '管理任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: []
}];
}
const VIEWWMODEOPTIONS = [
{ label: '日', value: ViewMode.Day },
{ label: '周', value: ViewMode.Week },
{ label: '月', value: ViewMode.Month },
];
const ProjectSchedule: React.FC<IProps> = ({ crudCtx }) => {
const { data } = useRequest(demodata);
const dispatch = useDispatch<Dispatch>();
const tasks = useSelector((s: RootState) => s.progress.tasks);
const crud = useSelector((s: RootState) => s.progress.scheduleCrud);
const [viewMode, setViewmode] = useState<ViewMode>(ViewMode.Day);
useEffect(() => {
if (data) {
dispatch.progress.loadSchedules(data);
}
}, [data]);
const onExpanderClick = (task: Task) => {
console.log(task);
dispatch.progress.setTasks(tasks?.map(o => o.id === task.id ? task : o));
}
return (
<Card
title="test项目"
extra={
<Space>
<Radio.Group options={VIEWWMODEOPTIONS} optionType="button" buttonStyle="solid" onChange={(e) => setViewmode(e.target.value)} value={viewMode} />
<CancelCrud crudCtx={crudCtx} text="返回项目列表" />
</Space>
}
bodyStyle={{ padding: 0 }}
>
{
tasks?.length ? (
<Gantt
viewMode={viewMode}
tasks={tasks}
TaskListHeader={TaskListHeader}
TaskListTable={TaskListTable}
onExpanderClick={onExpanderClick}
/>
) : null
}
{
crud ? (
<Modal
visible
footer={null}
title={crud.mode === 'new' ? '新增进度' : crud.record.name}
onCancel={() => dispatch.progress.setScheduleCrud(undefined)}>
<DataForm />
</Modal>
) : null
}
</Card>
)
}
export default ProjectSchedule

View File

@ -0,0 +1,23 @@
.ganttTable {
display: table;
border-bottom: #e6e4e4 1px solid;
border-top: #e6e4e4 1px solid;
}
.ganttTable_Header {
display: table-row;
list-style: none;
}
.ganttTable_HeaderSeparator {
border-right: 1px solid rgb(196, 196, 196);
opacity: 1;
margin-left: -2px;
}
.ganttTable_HeaderItem {
display: table-cell;
vertical-align: -webkit-baseline-middle;
vertical-align: middle;
text-align: center;
}

View File

@ -0,0 +1,82 @@
import React from "react";
import styles from "./task-list-header.module.css";
export const TaskListHeader: React.FC<{
headerHeight: number;
rowWidth: string;
fontFamily: string;
fontSize: string;
}> = ({ headerHeight, fontFamily, fontSize, rowWidth }) => {
return (
<div
className={styles.ganttTable}
style={{
fontFamily: fontFamily,
fontSize: fontSize,
}}
>
<div
className={styles.ganttTable_Header}
style={{
height: headerHeight - 2,
}}
>
<div
className={styles.ganttTable_HeaderItem}
style={{
minWidth: 280,
}}
>
&nbsp;
</div>
<div
className={styles.ganttTable_HeaderSeparator}
style={{
height: headerHeight * 0.5,
marginTop: headerHeight * 0.2,
}}
/>
<div
className={styles.ganttTable_HeaderItem}
style={{
minWidth: 140,
}}
>
&nbsp;
</div>
<div
className={styles.ganttTable_HeaderSeparator}
style={{
height: headerHeight * 0.5,
marginTop: headerHeight * 0.25,
}}
/>
<div
className={styles.ganttTable_HeaderItem}
style={{
minWidth: 140,
}}
>
&nbsp;
</div>
<div
className={styles.ganttTable_HeaderSeparator}
style={{
height: headerHeight * 0.5,
marginTop: headerHeight * 0.25,
}}
/>
<div
className={styles.ganttTable_HeaderItem}
style={{
minWidth: 50,
}}
>
&nbsp;
</div>
</div>
</div>
);
};

View File

@ -0,0 +1,44 @@
.taskListWrapper {
display: table;
}
.taskListTableRow {
display: table-row;
text-overflow: ellipsis;
}
.taskListTableRow:nth-of-type(even) {
background-color: #f5f5f5;
}
.taskListCell {
display: table-cell;
vertical-align: middle;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.taskListNameWrapper {
display: flex;
}
.taskListExpander {
color: rgb(86 86 86);
font-size: 0.6rem;
padding: 0.15rem 0.2rem 0rem 0.2rem;
user-select: none;
cursor: pointer;
}
.taskListEmptyExpander {
font-size: 0.6rem;
padding-left: 1rem;
user-select: none;
}
.ganttTable_CellSeparator {
border-right: 1px solid rgb(196, 196, 196);
opacity: 1;
margin-left: -2px;
}

View File

@ -0,0 +1,150 @@
import { FileOutlined, FolderOpenFilled, FolderOutlined, PlusCircleOutlined, ProfileOutlined } from "@ant-design/icons";
import { Space } from "antd";
import { Task } from 'gantt-task-react';
import React, { useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import OpButton from "../../../../components/crud/OpButton";
import { Dispatch, RootState } from "../../../../models/store";
import { Schedule } from "../../../../service/def";
import { renYYYYMMDD } from "../../../../utils/renutil";
import styles from "./task-list-table.module.css";
const localeDateStringCache: { [key: string]: string } = {};
const toLocaleDateStringFactory = (locale: string) => (
date: Date,
dateTimeOptions: Intl.DateTimeFormatOptions
) => {
const key = date.toString();
let lds = localeDateStringCache[key];
if (!lds) {
lds = renYYYYMMDD(date);
localeDateStringCache[key] = lds;
}
return lds;
};
const dateTimeOptions: Intl.DateTimeFormatOptions = {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
};
export const TaskListTable: React.FC<{
rowHeight: number;
rowWidth: string;
fontFamily: string;
fontSize: string;
locale: string;
tasks: Task[];
selectedTaskId: string;
setSelectedTask: (taskId: string) => void;
onExpanderClick: (task: Task) => void;
}> = ({
rowHeight,
tasks,
fontFamily,
fontSize,
locale,
onExpanderClick,
}) => {
const toLocaleDateString = useMemo(() => toLocaleDateStringFactory(locale), [
locale,
]);
const scheduleMap = useSelector((s: RootState) => s.progress.scheduleMap);
const dispatch = useDispatch<Dispatch>();
return (
<div
className={styles.taskListWrapper}
style={{
fontFamily: fontFamily,
fontSize: fontSize,
}}
>
{tasks.map(t => {
const schedule: Schedule | undefined = scheduleMap[t.id];
let indent = (schedule?._indent ?? 0) * 16;
let expanderSymbol = <FileOutlined />;
if (t.hideChildren === false) {
expanderSymbol = <FolderOpenFilled onClick={() => onExpanderClick(t)} />;
} else if (t.hideChildren === true) {
expanderSymbol = <FolderOutlined onClick={() => onExpanderClick(t)} />;
}
return (
<div
className={styles.taskListTableRow}
style={{ height: rowHeight }}
key={`${t.id}row`}
>
<div
className={styles.taskListCell}
style={{
minWidth: 280,
maxWidth: 280,
paddingLeft: indent
}}
title={t.name}
>
<Space>
{expanderSymbol}
{t.name}
</Space>
</div>
<div
className={styles.taskListCell}
style={{
minWidth: 140,
maxWidth: 140,
textAlign: 'center',
}}
>
&nbsp;{toLocaleDateString(t.start, dateTimeOptions)}
</div>
<div
className={styles.taskListCell}
style={{
minWidth: 140,
maxWidth: 140,
textAlign: 'center'
}}
>
&nbsp;{toLocaleDateString(t.end, dateTimeOptions)}
</div>
<div
className={styles.taskListCell}
style={{
minWidth: 50,
maxWidth: 50,
textAlign: 'center'
}}
>
{
schedule?.children ? (
<OpButton
icon={<PlusCircleOutlined />}
onClick={() => dispatch.progress.setScheduleCrud({ mode: 'new', record: schedule })}
/>
) : (
<OpButton
icon={<ProfileOutlined />}
onClick={() => dispatch.progress.setScheduleCrud({ mode: 'mod', record: schedule })}
/>
)
}
</div>
</div>
);
})}
</div>
);
};

View File

@ -0,0 +1,15 @@
import React from 'react';
import useCrud from '../../../components/crud/useCrud';
import ProjectSchedule from './ProjectSchedule';
const SchedulePage = () => {
const crud = useCrud();
return (
<div className="content-root">
<ProjectSchedule crudCtx={crud} />
</div>
)
}
export default SchedulePage

View File

@ -0,0 +1,41 @@
import ProForm, { ProFormSelect, ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
type IProps = {
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
let record = crudCtx.record || {};
record = {
...record,
...record.props
}
return (
<CenterForm>
<ProForm initialValues={record}>
<ProFormText name="id" label="编号" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormSelect name="level" label="任务等级" width={DEF_INPUT_LEN} rules={[{ required: true }]} options={['单项工程']} />
<ProForm.Group>
<ProFormSelect name="status" label="当前状态" width="sm" rules={[{ required: true }]} options={['未开工', '已开工', '已完工']} />
<ProFormSelect name="phase" label="所属阶段" width="sm" rules={[{ required: true }]} options={['[C]项目实时阶段']} />
</ProForm.Group>
<ProFormText name="建筑结构" label="建筑结构" width={DEF_INPUT_LEN} />
<ProFormTextArea name="remark" label="备注" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,162 @@
import { DeleteOutlined, FolderFilled, FolderOpenFilled, FolderOutlined, PlusCircleOutlined } from '@ant-design/icons';
import { Card, Col, Row, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import CenterForm from '../../../components/crud/CenterForm';
import OpButton from '../../../components/crud/OpButton';
import useCrud, { CrudContext } from '../../../components/crud/useCrud';
import { Schedule, ScheduleProps } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
import useRequest from '../../../utils/useRequest';
import { demoDate } from '../../../utils/utils';
import DataForm from './DataForm';
type IProps = {
crudCtx: CrudContext;
}
let id = 1;
const wbsProps: ScheduleProps = { wbs: true, level: '单项工程', status: '未开工', phase: '[C]项目实时阶段', };
async function demodata(): Promise<Schedule[]> {
return [{
id: `${id++}`,
name: '工程里程碑',
stm1: demoDate(2),
etm1: demoDate(100),
props: wbsProps,
progress: 77,
_indent: 1,
children: [
]
}, {
id: `${id++}`,
name: '设计任务',
stm1: demoDate(2),
etm1: demoDate(10),
props: wbsProps,
_indent: 1,
progress: 77,
children: [
{
id: `${id++}`,
name: '详细设计',
stm1: demoDate(11),
etm1: demoDate(20),
props: wbsProps,
_indent: 2,
progress: 77,
children: [
]
}
]
}, {
id: `${id++}`,
name: '采购任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: []
}, {
id: `${id++}`,
name: '施工任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: []
}, {
id: `${id++}`,
name: '管理任务',
stm1: demoDate(11),
etm1: demoDate(40),
props: wbsProps,
_indent: 1,
progress: 77,
children: []
}];
}
const WbsCard: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const { data, loading } = useRequest(demodata);
const columns = useMemo<ColumnsType<Schedule>>(() => ([
{ title: '编码名称', key: 'name', dataIndex: 'name' },
{ title: '计划开始时间', align: 'center', key: 'stm1', dataIndex: 'stm1', render: renYYYYMMDD },
{ title: '计划结束时间', align: 'center', key: 'etm1', dataIndex: 'etm1', render: renYYYYMMDD },
]), []);
const crud = useCrud();
const record = crud.record;
console.log(record);
return (
<Row gutter={16}>
<Col span={12}>
<Card title="WBS定义(Test项目)" extra={<CancelCrud crudCtx={parentCrud} text="返回项目列表" />}>
<Table
rowKey="id"
loading={loading}
dataSource={data}
columns={columns}
size="small"
bordered
pagination={false}
rowSelection={{
type: 'radio',
onSelect: (r) => {
crud.goto('mod', r)
}
}}
expandable={{
expandIcon: ({ expanded, onExpand, record }) => {
return !record?.children?.length ? (
<FolderOutlined style={{ marginRight: 8 }} />
) : (
expanded ? (
<FolderOpenFilled style={{ marginRight: 8 }} onClick={e => onExpand(record, e)} />
) : (
<FolderFilled style={{ marginRight: 8 }} onClick={e => onExpand(record, e)} />
)
);
}
}}
/>
</Card>
</Col>
<Col span={12}>
<Card title="WBS信息" extra={
<Space>
{Array.isArray(crud.record?.children) ? <OpButton icon={<PlusCircleOutlined />} text="新增" /> : null}
<OpButton icon={<DeleteOutlined />} text="删除" />
</Space>
}>
{
crud.record ? (
<CenterForm key={record.id}>
<DataForm crudCtx={crud} />
</CenterForm>
) : null
}
</Card>
</Col>
</Row>
)
}
export default WbsCard

View File

@ -0,0 +1,15 @@
import React from 'react';
import useCrud from '../../../components/crud/useCrud';
import WbsCard from './WbsCard';
const WbsPage = () => {
const crud = useCrud();
return (
<div className="content-root">
<WbsCard crudCtx={crud} />
</div>
)
}
export default WbsPage

View File

@ -0,0 +1,103 @@
import ProForm, { ProFormDatePicker, ProFormDigit, ProFormInstance, ProFormRadio, ProFormSelect, ProFormText, ProFormTextArea, ProFormUploadButton, StepsForm } from '@ant-design/pro-form'
import { message } from 'antd'
import React, { useRef } from 'react'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { waitTime } from '../../../utils/utils'
const DataForm: React.FC = () => {
const formRef = useRef<ProFormInstance>();
return (
<StepsForm
formRef={formRef}
onFinish={async () => {
await waitTime(1000);
message.success('提交成功');
}}
>
<StepsForm.StepForm
name="1"
title="基本信息"
onFinish={async () => {
console.log(formRef.current?.getFieldsValue());
await waitTime(500);
return true;
}}
>
<ProFormText name="code" label="项目编号" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="项目名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormRadio.Group
label="项目状态"
radioType="button"
options={['筹备阶段', '已开工', '已竣工']}
rules={[{ required: true }]}
/>
<ProFormText name="proprietor" label="业主单位" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormDatePicker name="planstm" label="计划开工" width="sm" rules={[{ required: true }]} />
<ProFormDatePicker name="planetm" label="计划建成" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="stm" label="实际开工" width="sm" />
<ProFormDatePicker name="etm" label="建成时间" width="sm" />
</ProForm.Group>
</StepsForm.StepForm>
<StepsForm.StepForm
name="2"
title="工程概述"
>
<ProFormText name="district" label="国家地区" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormSelect name="type" label="项目类型" width="sm" options={['水电站项目', '排涝站项目', '小型农田水利工程', '水库、大坝工程', '堤防、河道工程', '灌区工程', '水利枢纽工程', '农村安全饮水工程', '引水隧洞工程']} />
<ProFormDigit name="investment" label="总投资(万元)" min={0} width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormSelect name="scale" label="项目规模" width="sm" options={['大型', '中型', '小型']} />
<ProFormText name="ws" label="所在流域" width="sm" />
</ProForm.Group>
<ProForm.Group>
<ProFormDigit name="lng" label="经度" width="sm" rules={[{ required: true }]} />
<ProFormDigit name="lat" label="纬度" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormTextArea name="overall" label="工程概况" width={DEF_INPUT_LEN} />
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</StepsForm.StepForm>
<StepsForm.StepForm
name="3"
title="项目前期资料"
>
<ProFormUploadButton name="abwj" label="招标文件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
<ProFormUploadButton name="tbwj" label="投标文件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
<ProFormUploadButton name="zbtzs" label="中标通知书" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
<ProFormUploadButton name="yzht" label="业主合同" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</StepsForm.StepForm>
<StepsForm.StepForm
name="4"
title="项目信息管理"
>
<ProFormText name="projadmin" label="项目经理" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="projadmin2" label="现场项目经理" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="jsfzr" label="技术负责人" width={DEF_INPUT_LEN} />
<ProFormText name="jldw" label="监理单位" width={DEF_INPUT_LEN} />
<ProFormText name="sjsw" label="设计单位" width={DEF_INPUT_LEN} />
</StepsForm.StepForm>
</StepsForm>
)
}
export default DataForm;

View File

@ -0,0 +1,74 @@
import { DeleteOutlined, PlusOutlined, ProfileOutlined, SearchOutlined } from '@ant-design/icons';
import { Button, Card, DatePicker, Input, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import OpButton from '../../../components/crud/OpButton';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { ProjectLog } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<ProjectLog>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<ProjectLog>>(() => [
{ title: '项目名称', key: 'name', dataIndex: 'name', fixed: 'left', width: 240 },
{ title: '项目编号', key: 'code', dataIndex: 'code', width: 240 },
{ title: '项目状态', key: 'status', dataIndex: 'status', align: 'center', width: 120 },
{ title: '开始时间', key: 'planstm', dataIndex: 'planstm', align: 'center', width: 160, render: renYYYYMMDD },
{ title: '业主单位', key: 'proprietor', dataIndex: 'proprietor', width: 240 },
{ title: '项目经理', key: 'projadmin', dataIndex: 'projadmin', width: 120 },
{ title: '现场项目经理', key: 'projadmin2', dataIndex: 'projadmin2', width: 120 },
{ title: '技术负责人', key: 'jsfzr', dataIndex: 'jsfzr', width: 120 },
{ title: '监理单位', key: 'jldw', dataIndex: 'jldw', width: 240 },
{ title: '设计单位', key: 'sjdw', dataIndex: 'sjdw', width: 240 },
{ title: '招标文件', key: 'zbwj', dataIndex: 'zbwj', width: 480, render: val => <span>{val.map((o: string) => <span style={{ marginRight: 8 }} key={o} >{o}</span>)}</span> },
{ title: '投标文件', key: 'tbwj', dataIndex: 'tbwj', width: 480, render: val => <span>{val.map((o: string) => <span style={{ marginRight: 8 }} key={o} >{o}</span>)}</span> },
{ title: '中标通知书', key: 'zbtzs', dataIndex: 'zbtzs', width: 480, render: val => <span>{val.map((o: string) => <span key={o} style={{ marginRight: 8 }}>{o}</span>)}</span> },
{ title: '合同', key: 'contracts', dataIndex: 'contracts', width: 480, render: val => <span>{val.map((o: string) => <span key={o} style={{ marginRight: 8 }}>{o}</span>)}</span> },
{
title: '操作', key: '_', width: 120, render: rec => (
<Space>
<Button icon={<ProfileOutlined />} type="link" onClick={() => crudCtx.goto('res', rec)} />
<Button icon={<DeleteOutlined />} type="link" danger />
</Space>
)
}
], []);
const width = useMemo(() => columns.reduce((total: number, cur) => total + (cur.width as number), 0), [columns])
return (
<>
<Card>
<Space size="large" wrap>
<Space>:<Input /></Space>
<Space>:<Input /></Space>
<Space>:<DatePicker.RangePicker /></Space>
<Space>
<Button icon={<SearchOutlined />} type="primary"></Button>
<Button icon={<PlusOutlined />} onClick={() => crudCtx.goto('new', {})}></Button>
</Space>
</Space>
</Card>
<div className="card-h-margin" />
<Card>
<Table
rowKey="code"
columns={columns}
{...pagerCtx.tableProps}
scroll={{
x: width
}}
/>
</Card>
</>
)
}
export default DataTable

View File

@ -0,0 +1,64 @@
import { Card } from 'antd';
import React from 'react';
import CancelCrud from '../../../components/crud/CancelCrud';
import useCrud from '../../../components/crud/useCrud';
import usePageTable from '../../../components/crud/usePageTable';
import { PageResult, ProjectLog } from '../../../service/def';
import ProjectResources from '../ProjectResources';
import DataForm from './DataForm';
import DataTable from './DataTable';
async function demofind(): Promise<PageResult<ProjectLog>> {
return {
list: [
{
code: "FJXCGL",
name: "test项目",
status: '已开工',
planstm: new Date(),
proprietor: 'xxx',
operator: 'xxx',
projadmin: '张三',
projadmin2: '李四',
jldw: 'xxxxxxxxx公司',
sjdw: 'aaaaaaaaa公司',
zbwj: ['招标文件文件1.doc', '招标文件文件2.doc'],
tbwj: ['投标文件文件1.doc', '投标文件文件2.doc'],
zbtzs: ['中标通知书1.doc', '中标通知书2.doc'],
contracts: ['XXXXXXX合同1.doc', 'XXXXXXX合同2.doc'],
}
],
totalRow: 1
};
}
const ProjectLogPage: React.FC = () => {
const crud = useCrud();
const pager = usePageTable<ProjectLog>(demofind);
return (
<div className="content-root">
{
crud.mode === 'new' ? (
<Card key="new" title="立项" extra={<CancelCrud crudCtx={crud} confirm />} >
<DataForm />
</Card>
) : null
}
{
crud.mode === 'res' ? (
<ProjectResources crudCtx={crud} pagerCtx={pager} />
) : null
}
{
!crud.mode ? <DataTable crudCtx={crud} pagerCtx={pager} /> : null
}
</div>
)
}
export default ProjectLogPage

View File

@ -0,0 +1,42 @@
import ProForm, { ProFormDatePicker, ProFormText, ProFormUploadButton } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
import { PageTableContext } from '../../../components/crud/usePageTable'
import { ProjectResource } from '../../../service/def'
type IProps = {
pagerCtx: PageTableContext<ProjectResource>;
crudCtx: CrudContext
}
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
const record = crudCtx.record;
return (
<CenterForm>
<ProForm
initialValues={{
code: record.code,
name: record.name,
}}
onFinish={async (values) => {
console.log(values);
}}
>
<ProFormText name="code" label="项目编号" disabled width={DEF_INPUT_LEN} />
<ProFormText name="name" label="项目名称" disabled width={DEF_INPUT_LEN} />
<ProFormText name="startcond" label="开工条件" width={DEF_INPUT_LEN} />
<ProFormDatePicker name="endtm" label="达成时间" width="sm" />
<ProFormUploadButton name="attachments" label="附件" fieldProps={{
beforeUpload: file => false,
listType: 'picture-card',
}} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

View File

@ -0,0 +1,40 @@
import { DeleteOutlined } from '@ant-design/icons';
import { Button, Space, Table } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import React, { useMemo } from 'react';
import { CrudContext } from '../../../components/crud/useCrud';
import { PageTableContext } from '../../../components/crud/usePageTable';
import { ProjectResource } from '../../../service/def';
import { renYYYYMMDD } from '../../../utils/renutil';
type IProps = {
pagerCtx: PageTableContext<ProjectResource>;
crudCtx: CrudContext
}
const DataTable: React.FC<IProps> = ({ pagerCtx, crudCtx }) => {
const columns = useMemo<ColumnsType<ProjectResource>>(() => [
{ title: '开工条件', key: 'startcond', dataIndex: 'startcond' },
{ title: '相关要求', key: 'requirement', dataIndex: 'requirement' },
{ title: '达成时间', key: 'endtm', dataIndex: 'endtm', align: 'center', render: renYYYYMMDD },
{
title: '相关附件', key: 'attachments', dataIndex: 'attachments', render: (val: string[]) => (
<Space>{val.map(s => <Button key={s} type="link" size="small">{s}</Button>)}</Space>
)
},
{
title: '操作', key: '_', render: rec => (
<>
<Button icon={<DeleteOutlined />} type="link" danger />
</>
)
}
], []);
return (
<Table rowKey="id" columns={columns} {...pagerCtx.tableProps} />
)
}
export default DataTable

View File

@ -0,0 +1,25 @@
import { Descriptions, Rate } from 'antd'
import React from 'react'
import { ProjectLog } from '../../../../service/def'
import { renYYYYMMDD } from '../../../../utils/renutil'
interface IProps {
record: ProjectLog;
}
const InfoCard: React.FC<IProps> = ({ record }) => {
return (
<Descriptions column={2}>
<Descriptions.Item label="业主单位">{record.proprietor}</Descriptions.Item>
<Descriptions.Item label="项目经理">-</Descriptions.Item>
<Descriptions.Item label="项目状态">{record.status}</Descriptions.Item>
<Descriptions.Item label="项目等级"><Rate style={{ lineHeight: 1 }} value={1} disabled /></Descriptions.Item>
<Descriptions.Item label="计划开工时间">{renYYYYMMDD(record.planstm)}</Descriptions.Item>
<Descriptions.Item label="计划完工时间">-</Descriptions.Item>
<Descriptions.Item label="实际开工时间">-</Descriptions.Item>
<Descriptions.Item label="实际完工时间">-</Descriptions.Item>
</Descriptions>
)
}
export default React.memo(InfoCard);

View File

@ -0,0 +1,82 @@
import { Button, Card } from 'antd'
import React from 'react'
import CancelCrud from '../../../components/crud/CancelCrud'
import useCrud, { CrudContext } from '../../../components/crud/useCrud'
import usePageTable, { PageTableContext } from '../../../components/crud/usePageTable'
import { PageResult, ProjectLog, ProjectResource } from '../../../service/def'
import InfoCard from './components/InfoCard'
import DataForm from './DataForm'
import DataTable from './DataTable'
async function demofind(): Promise<PageResult<ProjectResource>> {
return {
list: [
{
id: 1,
code: "FJXCGL",
startcond: '条件aaaa',
requirement: 'ddddd',
endtm: new Date(),
attachments: ['a.pdf', 'b.pdf']
},
{
id: 2,
code: "FJXCGL",
startcond: '条件bbbb',
requirement: 'dddasda',
endtm: new Date(),
attachments: ['aaaa.docx', 'aaa.dwg']
},
],
totalRow: 2
};
}
type IProps = {
pagerCtx: PageTableContext<ProjectLog>;
crudCtx: CrudContext
}
const ProjectResources: React.FC<IProps> = ({ crudCtx: parentCrud }) => {
const record: ProjectLog = parentCrud.record || {};
const crud = useCrud();
const pager = usePageTable<ProjectResource>(demofind);
return (
<>
<Card title={record.name} extra={<CancelCrud crudCtx={parentCrud} />}>
<InfoCard record={parentCrud.record} />
</Card>
<div className="card-h-margin" />
<Card
title="开工条件"
extra={
crud.mode === 'new' ? (
<CancelCrud crudCtx={crud} text="列表" confirm />
) : (
<Button size="small" type="link" onClick={() => crud.goto('new', record)}></Button>
)
}
>
{
crud.mode === 'new' ? (
<DataForm crudCtx={crud} pagerCtx={pager} />
) : (
<DataTable crudCtx={crud} pagerCtx={pager} />
)
}
</Card>
</>
)
}
export default ProjectResources

View File

@ -0,0 +1,33 @@
import ProForm, { ProFormCheckbox, ProFormDatePicker, ProFormSelect, ProFormText } from '@ant-design/pro-form'
import React from 'react'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
const DataForm = () => {
return (
<ProForm>
<ProFormText name="type" label="发文类型" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProForm.Group>
<ProFormText name="_1" label="现文号" width="sm" rules={[{ required: true }]} />
<ProFormText name="version" label="版次" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="title" label="文件标题" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="_2" label="发文单位" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="keywords" label="关键词" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormText name="pages" label="文件页数" width="sm" rules={[{ required: true }]} />
<ProFormText name="cnt" label="实物份数" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProForm.Group>
<ProFormDatePicker name="regtm" label="登记日期" width="sm" rules={[{ required: true }]} />
</ProForm.Group>
<ProFormText name="remark" label="备注" width={DEF_INPUT_LEN} />
<ProForm.Group>
<ProFormCheckbox name="_3" ></ProFormCheckbox>
<ProFormCheckbox name="_4" ></ProFormCheckbox>
<ProFormCheckbox name="_5" ></ProFormCheckbox>
</ProForm.Group>
</ProForm>
)
}
export default DataForm

View File

@ -0,0 +1,34 @@
import { PlusOutlined } from '@ant-design/icons';
import { Button, Card } from 'antd'
import React from 'react'
import CancelCrud from '../../../components/crud/CancelCrud';
import CenterForm from '../../../components/crud/CenterForm';
import useCrud from '../../../components/crud/useCrud'
import DataForm from './DataForm';
const AdministrativeDocPage = () => {
const crud = useCrud();
return (
<div className="content-root">
{
!crud.mode ? (
<Card>
<Button icon={<PlusOutlined />} onClick={() => crud.goto('new', null)} ></Button>
</Card>
) : null
}
{
crud.mode === 'new' ? (
<Card title="新增行政公文" extra={<CancelCrud crudCtx={crud} />}>
<CenterForm>
<DataForm />
</CenterForm>
</Card>
) : null
}
</div>
)
}
export default AdministrativeDocPage

View File

@ -0,0 +1,34 @@
import ProForm, { ProFormText, ProFormTextArea } from '@ant-design/pro-form'
import React from 'react'
import CenterForm from '../../../components/crud/CenterForm'
import { DEF_INPUT_LEN } from '../../../components/crud/FormLayoutProps'
import { CrudContext } from '../../../components/crud/useCrud'
type IProps = {
crudCtx: CrudContext;
};
const DataForm: React.FC<IProps> = ({ crudCtx }) => {
let record = crudCtx.record || {};
let initVal = crudCtx.mode === 'new' ? ({
_parent: record.name,
}) : record;
return (
<CenterForm>
<ProForm initialValues={initVal}>
{
initVal._parent ? (<ProFormText name="_parent" label="所属目录" width={DEF_INPUT_LEN} disabled />) : null
}
<ProFormText name="code" label="编号" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormText name="name" label="名称" width={DEF_INPUT_LEN} rules={[{ required: true }]} />
<ProFormTextArea name="remark" label="备注" width={DEF_INPUT_LEN} />
</ProForm>
</CenterForm>
)
}
export default DataForm;

Some files were not shown because too many files have changed in this diff Show More