HW 4 年 前
コミット
a8efc68327

+ 2 - 1
package.json

@@ -64,7 +64,8 @@
     "react-helmet-async": "^1.0.4",
     "umi": "^3.2.14",
     "umi-request": "^1.0.8",
-    "use-merge-value": "^1.0.1"
+    "use-merge-value": "^1.0.1",
+    "viewerjs": "^1.9.0"
   },
   "devDependencies": {
     "@ant-design/pro-cli": "^2.0.2",

+ 229 - 0
src/components/common/ImgOperation/index.jsx

@@ -0,0 +1,229 @@
+import React,{Component} from 'react';
+import {Icon, message, Spin, Upload,Progress} from 'antd';
+import './index.less';
+import Viewer from 'viewerjs';
+import 'viewerjs/dist/viewer.css';
+import PropTypes from 'prop-types';
+
+// const url1 = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1601012352754&di=d33308119328f5ed987bd90031f98cfa&imgtype=0&src=http%3A%2F%2Fa2.att.hudong.com%2F27%2F81%2F01200000194677136358818023076.jpg';
+// const url2 = 'https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1601001245&di=60b5e1a42beb791524b46d7e3677f1f4&src=http://a2.att.hudong.com/13/86/01300001285722131043860050752.jpg';
+
+const uploadButton = (
+  <div>
+    <Icon type="plus" />
+    <div className="ant-upload-text">点击上传</div>
+  </div>
+);
+
+class ImgList extends Component{
+  constructor(props) {
+    super(props);
+    this.state={
+      seeMore: false,
+      gallery: null,
+      loading: true,
+      imgLoadNum: 0,
+
+      // uploadLoading: false,
+      percent: 0,
+
+      newUploadArr: [],
+      newUploadInforArr: {},
+    }
+    this.imgLoading = this.imgLoading.bind(this);
+    this.beforeUpload = this.beforeUpload.bind(this);
+    this.setTimeOutObj = null;
+  }
+
+  componentDidMount() {
+    this.setTimeOutObj = setTimeout(()=>{
+      this.setState({
+        gallery: new Viewer(document.getElementById(this.props.domId))
+      },()=>{
+        this.setState({
+          loading: false
+        })
+      })
+    },10000)
+  }
+
+  imgLoading(){
+    let num = this.state.imgLoadNum + 1;
+    if(num >= this.props.fileList.length){
+      this.state.gallery && this.state.gallery.destroy();
+      this.setState({
+        gallery: new Viewer(document.getElementById(this.props.domId))
+      },()=>{
+        this.setTimeOutObj && clearTimeout(this.setTimeOutObj);
+        this.setState({
+          loading: false
+        })
+      })
+    }
+    this.setState({
+      imgLoadNum: num
+    })
+  }
+
+  beforeUpload(file) {
+    const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
+    if (!isJPG) {
+      message.error('只能上传图片文件!');
+      return isJPG;
+    }
+    const isLt2M = file.size / 1024 / 1024 < 10;
+    if (!isLt2M) {
+      message.error('图片大小不能超过 10MB!');
+      return isLt2M;
+    }
+    if(isJPG && isLt2M){
+      //用于计算当次选择的图片数量
+      this.state.newUploadArr.push(file)
+      this.setState({
+        newUploadArr:this.state.newUploadArr
+      })
+    }
+    return isJPG && isLt2M;
+  }
+
+  componentWillUnmount() {
+    this.setTimeOutObj && clearTimeout(this.setTimeOutObj);
+  }
+
+  render() {
+    const {fileList} = this.props;
+    if(!fileList || !Array.isArray(fileList)){
+      return null;
+    }
+    return (
+      <div className='ImgListComponent'>
+        <div className='ImgList'>
+          <Spin spinning={Object.keys(this.props.uploadConfig).length !== 0 ? false : (fileList.length === 0 ? false : this.state.loading)} tip="图片加载中...">
+            <Upload
+              {...this.props.uploadConfig}
+              className={Object.keys(this.props.uploadConfig).length !== 0 ? "" : "demandDetailShow-upload" }
+              listType="picture-card"
+              fileList={
+                Object.keys(this.props.uploadConfig).length !== 0 ?
+                  (
+                    fileList.map((v,i)=>{
+                      v.index = i;
+                      // v.url = i%2 ? url1 : url2;
+                      return v
+                    })
+                  ) : (
+                    this.state.seeMore?
+                      fileList.map((v,i)=>{
+                        v.index = i;
+                        // v.url = i%2 ? url1 : url2;
+                        return v
+                      }) :
+                      fileList.map((v,i)=>{
+                        v.index = i;
+                        // v.url = i%2 ? url1 : url2;
+                        return v
+                      }).slice(0,10)
+                  )
+              }
+              onPreview={(file) => {
+                this.state.gallery.view(file.index).show();
+              }}
+              beforeUpload={this.beforeUpload}
+              onChange={(infor)=>{
+                if(infor.file.status){
+                  let newUploadNum = this.state.newUploadArr.length
+                  this.state.gallery && this.state.gallery.destroy();
+                  this.props.onChange(infor);
+                  if(infor.file && infor.file.status === 'error'){
+                    message.error('图片上传失败,请重新上传!');
+                  }
+                  //用于控制进度条
+                  if(infor.file && infor.file.status !== 'removed' && infor.event){
+                    let percent = 0;
+                    this.state.newUploadInforArr[infor.file.uid] = infor.event.percent;
+                    this.setState({
+                      newUploadInforArr:this.state.newUploadInforArr
+                    })
+                    for(let i of Object.values(this.state.newUploadInforArr)){
+                      percent+= i
+                    }
+                    let percentNum = percent/newUploadNum/100;
+                    this.setState({
+                      percent:percentNum
+                    })
+                    if(percentNum <= 1) {
+                      this.props.onUploadState({state:'uploading'});
+                    }
+                    if(percentNum >= 1){
+                      this.setState({
+                        percent: 1,
+                      },()=>{
+                        setTimeout(()=>{
+                          this.props.onUploadState({state:'ok'})
+                          this.state.gallery && this.state.gallery.destroy();
+                          this.setState({
+                            gallery: new Viewer(document.getElementById(this.props.domId))
+                          })
+                          this.setState({
+                            percent: 0,
+                            newUploadArr: [],
+                            newUploadInforArr: {}
+                          })
+                        },1500)
+                      })
+                    }
+                  }else if(infor.file && infor.file.status === 'removed'){
+                    this.state.gallery && this.state.gallery.destroy();
+                    this.setState({
+                      gallery: new Viewer(document.getElementById(this.props.domId))
+                    },()=>{
+                      this.setState({
+                        percent: 0,
+                        newUploadArr: [],
+                        newUploadInforArr: {}
+                      })
+                    })
+                  }
+                }
+              }}
+            >
+              {Object.keys(this.props.uploadConfig).length === 0 ? "" : uploadButton}
+            </Upload>
+          </Spin>
+        </div>
+        {fileList.length > 10 && Object.keys(this.props.uploadConfig).length === 0 ? <div className='seeMore' onClick={()=>{this.setState({seeMore:!this.state.seeMore})}}>
+          {this.state.seeMore ? '收起' : '查看更多'}
+        </div> : <div/>}
+        <ul id={this.props.domId} style={{display:'none',zIndex:-1,}}>
+          {
+            fileList.map((value,index)=>(
+              <li key={index}>
+                <img src={value.url || value.thumbUrl} onLoad={()=>{
+                  this.imgLoading();
+                }}/>
+              </li>
+            ))
+          }
+        </ul>
+      </div>
+    )
+  }
+}
+
+ImgList.propTypes = {
+  domId : PropTypes.string,                            // 如果一个界面有多个该组件,需要传入自定义id名称,用于图片列表显示
+  fileList: PropTypes.array.isRequired,                // 图片文件列表
+  uploadConfig: PropTypes.object,                      // 上传图片配置参数(需要上传图片时需要,存在与否,用于区分是否为上传或者为查看)
+  onChange: PropTypes.func,                            // 选择图片
+  onUploadState: PropTypes.func,                       // 上传图片状态        返回类型: state : ok(上传完成) || uploading(上传中)
+}
+
+ImgList.defaultProps = {
+  domId: 'images',
+  fileList: [],
+  uploadConfig: {},
+  onChange:()=>{},
+  onUploadState:()=>{},
+}
+
+export default ImgList;

+ 105 - 0
src/components/common/ImgOperation/index.less

@@ -0,0 +1,105 @@
+.ImgListComponent{
+  .ImgList{
+    width: 100%;
+    display: flex;
+    flex-flow: row wrap;
+    .fileItem{
+      margin: 0 12px 12px 0;
+      padding: 8px;
+      border-radius: 4px;
+      border: 1px solid #d9d9d9;
+      position: relative;
+      .imgFile{
+        width: 100%;
+        height: 100%;
+        overflow: hidden;
+        border-radius: 4px;
+      }
+    }
+    .flexRowWrap{
+      display: flex;
+      flex-flow: row wrap;
+    }
+    .coveringLayer{
+      display: none;
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      border-radius: 4px;
+      flex-flow: row nowrap;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+
+  .seeMore{
+    padding-right: 20px;
+    color: #58a3ff;
+  }
+  .seeMore:hover{
+    color: #0e77ca;
+    cursor: pointer;
+  }
+  .mask{
+    position:fixed;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 9999999999;
+    background: rgba(0,0,0,.8);
+    display:flex;
+    flex-flow:column;
+    align-items:center;
+    justify-content:center;
+    .progress{
+      color: #FFF;
+    }
+    .promptText{
+      color: #FFF;
+      padding-top: 15px;
+    }
+  }
+}
+.actionBar{
+  position: relative;
+  display: flex;
+  flex-flow: row nowrap;
+  align-items: center;
+}
+.imgModal{
+  position: fixed;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 99999;
+  .floatingLayer{
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 99997;
+    background: rgba(0,0,0,.5);
+  }
+  .ant-modal-content{
+    background:rgba(0,0,0,0) !important;
+  }
+  .ant-modal-content{
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0);
+  }
+}
+.demandDetailShow-upload {
+  .anticon-eye-o {
+    margin-left: -8px;
+  }
+  .anticon-delete {
+    display: none
+  }
+}

+ 21 - 0
src/components/common/Modal/index.jsx

@@ -0,0 +1,21 @@
+import React, { Component } from 'react';
+import { Modal } from 'antd';
+
+class ModalComponent extends Component{
+  constructor(props) {
+    super(props);
+  }
+
+  render() {
+    return (
+      <Modal
+        destroyOnClose   //关闭时销毁 Modal 里的子元素
+        {...this.props}
+      >
+        {this.props.children}
+      </Modal>
+    );
+  }
+}
+
+export default ModalComponent;

+ 40 - 0
src/pages/Order/Billing/components/TableModal/index.jsx

@@ -0,0 +1,40 @@
+import React, { Component } from 'react';
+import { Tabs } from 'antd';
+import Modal from '@/components/common/Modal';
+import NewOrder from './NewOrder';
+
+const { TabPane } = Tabs;
+
+class TableModal extends Component{
+  constructor(props) {
+    super(props);
+    this.state={
+      activeKey: props.defaultActiveKey || '1'
+    }
+  }
+
+  render() {
+    return (
+     <>
+       <Modal
+         {...this.props}
+         footer={null}
+       >
+         <Tabs
+           defaultActiveKey={this.props.defaultActiveKey || '1'}
+           activeKey={this.state.activeKey}
+           onChange={(key)=>this.setState({activeKey: key})}>
+           <TabPane tab="最新订单" key="1">
+            <NewOrder {...this.props}/>
+           </TabPane>
+           <TabPane tab="合同变更发起" key="2">
+             Content of Tab Pane 2
+           </TabPane>
+         </Tabs>
+       </Modal>
+       </>
+    );
+  }
+}
+
+export default TableModal;

+ 3 - 0
src/pages/Order/Billing/components/TableModal/index.less

@@ -0,0 +1,3 @@
+.newOrderDescriptions .ant-descriptions-item-label{
+  padding-top: 5px
+}

+ 95 - 0
src/pages/Order/Billing/components/TableModal/newOrder.jsx

@@ -0,0 +1,95 @@
+/*
+    订单管理->我的订单->开单与签单 最新订单弹出层
+*/
+import React,{Component} from 'react';
+import { Descriptions, message, Button, Form } from 'antd';
+import ImgOperation from '@/components/common/ImgOperation';
+import './index.less';
+
+import Field from '@ant-design/pro-field';
+import ProForm, { ProFormText, ProFormDateRangePicker, ProFormSelect } from '@ant-design/pro-form';
+
+class NewOrder extends Component{
+  constructor(props) {
+    super(props);
+    this.state={
+      stateType: 'edit',    // 是否只读   read: 只读  edit: 编辑
+      plain: false,         // 是否简约
+      fileList: [],
+    };
+  }
+
+  render() {
+    const { stateType, plain, fileList } = this.state;
+    return (
+      <>
+        <Form
+          onFinish={async (values) => {
+            console.log(values);
+            message.success('提交成功!');
+          }}
+          initialValues={{
+            name: '蚂蚁设计有限公司',
+            useMode: 20,
+          }}
+        >
+          <Descriptions
+            column={2}
+            className='newOrderDescriptions'
+            onFinish={async (values) => {
+              console.log(values);
+              message.success('提交成功!');
+            }}
+          >
+            <Descriptions.Item label="文本">
+              <Form.Item  name="name">
+                <Field valueType="text" mode={stateType} plain={plain} />
+              </Form.Item>
+            </Descriptions.Item>
+
+            <Descriptions.Item label="金额">
+              <Form.Item  name="useMode">
+                <Field valueType="money" mode={stateType} plain={plain} />
+              </Form.Item>
+            </Descriptions.Item>
+            <Descriptions.Item label="图片">
+              <Form.Item  name="image">
+                <ImgOperation
+                  domId='newOrder'
+                  uploadConfig={stateType === 'read'? {} :{
+                    action:'/api/admin/outsourceOrg/uploadOutsourceFile',
+                    multiple:true,
+                    data:{ sign: 'order_outsource' },
+                    listType:"picture-card",
+                  }}
+                  onChange={(infor)=>{
+                    this.setState({
+                      fileList: infor.fileList,
+                    });
+                  }}
+                  fileList={fileList}
+                  onUploadState={(v)=>{
+                    // this.setState({
+                    //   loading: v.state === 'uploading'
+                    // })
+                  }}
+                />
+              </Form.Item>
+            </Descriptions.Item>
+          </Descriptions>
+          {stateType === 'edit' &&
+            <div>
+              <Form.Item wrapperCol={{ span: 5, offset: 9 }}>
+                <Button block type="primary" size='large' htmlType="submit">
+                  提交
+                </Button>
+              </Form.Item>
+            </div>
+          }
+        </Form>
+      </>
+    )
+  }
+}
+
+export default NewOrder;

+ 21 - 2
src/pages/Order/Billing/index.jsx

@@ -3,6 +3,7 @@ import DataTable from '@/components/common/DataTable';
 import {Button, Dropdown, Menu, Space, Table, DatePicker} from "antd";
 import {EllipsisOutlined, PlusOutlined} from "@ant-design/icons";
 import { TableDropdown } from '@ant-design/pro-table';
+import TableModal from './components/TableModal';
 
 const { RangePicker } = DatePicker;
 
@@ -134,7 +135,9 @@ class Billing extends Component{
             />,
           ],
         },
-      ]
+      ],
+      tableModal: false,
+      tableRowInfor: {},
     }
   }
 
@@ -164,7 +167,10 @@ class Billing extends Component{
           onRow={record => {
             return {
               onClick: (event) => {
-                console.log(record,event);
+                this.setState({
+                  tableModal: true,
+                  tableRowInfor: record,
+                })
               }, // 点击行
             };
           }}
@@ -207,6 +213,19 @@ class Billing extends Component{
             );
           }}
         />
+        <TableModal
+          centered
+          width={1200}
+          visible={this.state.tableModal}
+          tableRowInfor={this.state.tableRowInfor}
+          onCancel={() => this.setState({
+            tableModal: false,
+            tableRowInfor: {}
+          })}
+          onOk={() => this.setState({
+            tableModal: false,
+            tableRowInfor: {},
+          })}/>
       </div>
     );
   }