From ed818fbca1a913065a6a3c2c767714efe5b18685 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期一, 17 八月 2020 11:21:22 +0800
Subject: [PATCH] 2020-08-17

---
 src/tabviews/zshare/calendar/index.jsx                                            |   26 +++---
 src/templates/calendarconfig/tabcomponent/tabform/index.jsx                       |   12 +-
 src/tabviews/subtabtable/index.jsx                                                |   45 ++++++++++-
 src/tabviews/zshare/topSearch/index.jsx                                           |   30 ++++---
 src/templates/zshare/formconfig.jsx                                               |   15 ++-
 src/templates/sharecomponent/datasourcecomponent/verifycard/settingform/index.jsx |    8 +-
 src/templates/calendarconfig/index.jsx                                            |   44 +++++------
 src/templates/sharecomponent/datasourcecomponent/verifycard/utils.jsx             |   12 +++
 src/tabviews/calendar/index.jsx                                                   |   14 +--
 9 files changed, 125 insertions(+), 81 deletions(-)

diff --git a/src/tabviews/calendar/index.jsx b/src/tabviews/calendar/index.jsx
index c059ce8..4052a90 100644
--- a/src/tabviews/calendar/index.jsx
+++ b/src/tabviews/calendar/index.jsx
@@ -432,7 +432,6 @@
     })
   }
 
-
   handleviewconfig = (e) => {
     e.stopPropagation()
 
@@ -537,19 +536,12 @@
 
   triggerDate = (item) => {
     const { config } = this.state
-    let time = ''
 
     if (!config.tab) return
-
-    if (item.time.length === 6) {
-      time = item.time.substr(0, 4) + '-' + item.time.substr(4, 2)
-    } else {
-      time = item.time.substr(0, 4) + '-' + item.time.substr(4, 2) + '-' + item.time.substr(6, 2)
-    }
     
     this.setState({
       visible: true,
-      triggerTime: time
+      triggerTime: item.time.substr(0, 4) + '-' + item.time.substr(4, 2) + '-' + item.time.substr(6, 2)
     })
   }
 
@@ -561,7 +553,7 @@
   }
 
   render() {
-    const { BID, searchlist, loadingview, viewlost, config, loading, data } = this.state
+    const { BID, searchlist, loadingview, viewlost, config, loading, data, triggerTime } = this.state
 
     return (
       <div className="calendar-page" id={this.state.ContainerId}>
@@ -615,6 +607,8 @@
           destroyOnClose
         >
           {config.tab ? <SubTabTable
+            BID={triggerTime}
+            Tab={config.tab}
             SupMenuID={this.props.MenuID}
             MenuID={config.tab.linkTab}
             refreshSupView={this.loadmaindata}
diff --git a/src/tabviews/subtabtable/index.jsx b/src/tabviews/subtabtable/index.jsx
index a8bb511..2478210 100644
--- a/src/tabviews/subtabtable/index.jsx
+++ b/src/tabviews/subtabtable/index.jsx
@@ -27,9 +27,11 @@
 class SubTabModalTable extends Component {
   static propTpyes = {
     type: PropTypes.any,             // 绫诲瀷锛宑alendar闇�鐗规畩澶勭悊
+    Tab: PropTypes.any,              // 鏃ュ巻鏍囩淇℃伅
     BID: PropTypes.string,           // 涓婄骇鏁版嵁ID
     BData: PropTypes.any,            // 涓婄骇鏁版嵁
     MenuID: PropTypes.string,        // 鑿滃崟Id
+    mainSearch: PropTypes.any,       // 涓昏〃鎼滅储鏉′欢
     SupMenuID: PropTypes.string,     // 涓婄骇鑿滃崟Id
     refreshSupView: PropTypes.any,   // 鍒锋柊涓婄骇鑿滃崟
     closeModalView: PropTypes.any    // 鍏抽棴妯℃�佹
@@ -138,7 +140,7 @@
 
       // 浠呮敮鎸乪xec銆乸rompt銆乸op 涓夌绫诲瀷鎸夐挳
       if (type === 'calendar') {
-        config.action = config.action.filter(item => ['exec', 'prompt', 'pop', 'tab'].includes(item.OpenType))
+        config.action = config.action.filter(item => ['exec', 'prompt', 'pop', 'tab', 'excelIn', 'excelOut'].includes(item.OpenType))
       } else {
         config.action = config.action.filter(item => ['exec', 'prompt', 'pop'].includes(item.OpenType))
       }
@@ -359,9 +361,15 @@
    * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙�
    */
   getCustomParam = () => {
+    const { mainSearch } = this.props
     const { pageIndex, pageSize, orderBy, search, setting } = this.state
 
-    let _search = Utils.formatCustomMainSearch(search)
+    let searches = search
+    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      searches = [...mainSearch, ...search]
+    }
+
+    let _search = Utils.formatCustomMainSearch(searches)
 
     let param = {
       OrderCol: orderBy || setting.order,
@@ -402,9 +410,15 @@
    * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
    */
   getDefaultParam = () => {
+    const { mainSearch } = this.props
     const { arr_field, pageIndex, pageSize, orderBy, search, setting } = this.state
 
-    let _search = Utils.joinMainSearchkey(search)
+    let searches = search
+    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      searches = [...mainSearch, ...search]
+    }
+
+    let _search = Utils.joinMainSearchkey(searches)
     _search = _search ? 'where ' + _search : ''
 
     let param = {
@@ -435,7 +449,7 @@
 
     let regoptions = null
     if (setting.queryType === 'statistics' || param.custom_script) {
-      let allSearch = Utils.getAllSearchOptions(search)
+      let allSearch = Utils.getAllSearchOptions(searches)
 
       regoptions = allSearch.map(item => {
         return {
@@ -589,7 +603,7 @@
    * @description 鎸夐挳鎿嶄綔瀹屾垚鍚庯紙鎴愬姛鎴栧け璐ワ級锛岄〉闈㈠埛鏂帮紝閲嶇疆椤电爜鍙婇�夋嫨椤�
    */
   refreshbyaction = (position) => {
-    if (position === 'grid') {
+    if (position === 'grid' || position === 'maingrid') {
       this.reloadtable()
       this.props.refreshSupView()
     } else if (position === 'view') {
@@ -612,6 +626,26 @@
         data: record
       }
     })
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  getexceloutparam = () => {
+    const { Tab, mainSearch } = this.props
+    const { arr_field, orderBy, search, setting} = this.state
+
+    let searches = search
+    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      searches = [...mainSearch, ...search]
+    }
+
+    return {
+      arr_field: arr_field,
+      orderBy: orderBy || setting.order,
+      search: searches,
+      menuName: Tab.label
+    }
   }
 
   /**
@@ -682,6 +716,7 @@
                       logcolumns={this.state.logcolumns}
                       operations={config.gridBtn.operations || []}
                       refreshdata={this.refreshbyaction}
+                      getexceloutparam={this.getexceloutparam}
                     />
                   </div>
                   <SubTable
diff --git a/src/tabviews/zshare/calendar/index.jsx b/src/tabviews/zshare/calendar/index.jsx
index 8ac9028..000050d 100644
--- a/src/tabviews/zshare/calendar/index.jsx
+++ b/src/tabviews/zshare/calendar/index.jsx
@@ -49,7 +49,7 @@
     let level = _levels[0]
     let monthlist = null
 
-    if (_levels.includes('month')) {
+    if (_levels.includes('month') || _levels.includes('year')) {
       monthlist = datelist.filter(item => item.month === moment().format('MM'))[0]
     }
 
@@ -67,7 +67,7 @@
       let datelist = this.mountdata(this.state.datelist, nextProps.data || [])
       let monthlist = null
 
-      if (this.state.levels.includes('month')) {
+      if (this.state.levels.includes('month') || this.state.levels.includes('year')) {
         monthlist = datelist.filter(item => item.month === this.state.selectMonth)[0]
       }
 
@@ -115,9 +115,9 @@
       })
     })
 
-    if (datalist.length === 0) return datelist
-
-    datalist.sort((a, b) => a.level - b.level)
+    if (datalist.length > 0) {
+      datalist.sort((a, b) => a.level - b.level)
+    }
 
     let styles = [
       {background: '#d0021b', color: '#ffffff'},
@@ -131,6 +131,7 @@
     ]
 
     return datelist.map(month => {
+      month.subData = []
       datalist.forEach(item => {
         if (item.startMonth <= month.time && item.endMonth >= month.time) {
           month.subData.push(item)
@@ -143,6 +144,7 @@
         week.sublist = week.sublist.map(day => {
           if (!day) return null
 
+          day.subData = []
           datalist.forEach(item => {
             if (item.start <= day.time && item.end >= day.time) {
               day.subData.push(item)
@@ -152,13 +154,10 @@
           if (day.subData[0]) {
             day.style = styles[day.subData[0].level - 1] || null
           }
-
           return day
         })
-
         return week
       })
-
       return month
     })
   }
@@ -218,7 +217,7 @@
     let datelist = this.getDateList(value)
     let monthlist = null
 
-    if (levels.includes('month')) {
+    if (levels.includes('month') || levels.includes('year')) {
       monthlist = datelist.filter(item => item.month === selectMonth)[0]
     }
     
@@ -227,9 +226,9 @@
 
       this.setState({ selectYear: value, datelist, monthlist })
     } else {
-      this.setState({ selectYear: value, datelist, monthlist })
-
-      this.props.changeDate(value)
+      this.setState({ selectYear: value, datelist, monthlist }, () => {
+        this.props.changeDate(value)
+      })
     }
   }
 
@@ -237,6 +236,7 @@
     const { datelist } = this.state
 
     this.setState({
+      level: 'month',
       selectMonth: value,
       monthlist: datelist.filter(item => item.month === value)[0]
     })
@@ -357,7 +357,7 @@
           {level === 'year' && monthlist ? <Row className="year-calendar">
             {datelist.map(item => (
               <Col span={8} key={item.month}>
-                <div className="year-wrap" style={item.style || null} onClick={() => this.triggerDay(item)}>
+                <div className="year-wrap" style={item.style || null} onClick={() => this.monthChange(item.month)}>
                   <div className="header" style={item.style ? null : {color: '#1890ff'}}>
                     {item.label}
                   </div>
diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx
index 3889b5e..ab365b4 100644
--- a/src/tabviews/zshare/topSearch/index.jsx
+++ b/src/tabviews/zshare/topSearch/index.jsx
@@ -523,18 +523,22 @@
     // 鍥炶溅鎴栫偣鍑绘悳绱�
     e.preventDefault()
     this.props.form.validateFields((err, values) => {
-      values = this.addHideFieldValue(values)
-      let searches = this.getFieldsValues(values)
-      this.props.refreshdata(searches)
+      if (!err) {
+        values = this.addHideFieldValue(values)
+        let searches = this.getFieldsValues(values)
+        this.props.refreshdata(searches)
+      }
     })
   }
 
   searchChange = () => {
     this.setState({}, () => {
       this.props.form.validateFields((err, values) => {
-        values = this.addHideFieldValue(values)
-        let searches = this.getFieldsValues(values)
-        this.props.refreshdata(searches)
+        if (!err) {
+          values = this.addHideFieldValue(values)
+          let searches = this.getFieldsValues(values)
+          this.props.refreshdata(searches)
+        }
       })
     })
   }
@@ -559,12 +563,14 @@
     this.setState({searchlist}, () => {
       this.props.form.resetFields()
       this.props.form.validateFields((err, values) => {
-        // 寮傛鑾峰彇鏇存柊鍚庣殑鏃堕棿缁�
-        this.setState({}, () => {
-          values = this.addHideFieldValue(values)
-          let searches = this.getFieldsValues(values)
-          this.props.refreshdata(searches)
-        })
+        if (!err) {
+          // 寮傛鑾峰彇鏇存柊鍚庣殑鏃堕棿缁�
+          this.setState({}, () => {
+            values = this.addHideFieldValue(values)
+            let searches = this.getFieldsValues(values)
+            this.props.refreshdata(searches)
+          })
+        }
       })
     })
   }
diff --git a/src/templates/calendarconfig/index.jsx b/src/templates/calendarconfig/index.jsx
index 7edfa86..2b46ea7 100644
--- a/src/templates/calendarconfig/index.jsx
+++ b/src/templates/calendarconfig/index.jsx
@@ -59,7 +59,6 @@
     pasteContent: null,      // 绮樿创鍐呭
     openEdition: '',         // 缂栬緫鐗堟湰鏍囪锛岄槻姝㈠浜烘搷浣�
     mockdata: [],            // 娴嬭瘯鏁版嵁
-    mockloading: false       // 鏁版嵁鍔犺浇涓�
   }
 
   /**
@@ -122,14 +121,14 @@
 
   getMockData = (year) => {
     let msgs = [
-      {color: 'red', remark: '鏈嶅姟鍣ㄥ紓甯革紝璇疯仈绯昏繍缁翠汉鍛橈紒'},
-      {color: 'orange', remark: '绯荤粺寮傚父锛岃鍙婃椂澶勭悊锛�'},
-      {color: 'yellow', remark: '鎮ㄧ殑璁㈠崟寮傚父锛岃鑱旂郴瀹㈡湇锛�'},
-      {color: 'green', remark: '鎮ㄧ殑璁㈠崟宸插畬鎴愩��'},
+      {color: 'red', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭紒'},
+      {color: 'orange', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭紒'},
+      {color: 'yellow', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭紒'},
+      {color: 'green', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭��'},
       {color: 'cyan', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭��'},
-      {color: 'blue', remark: '浠诲姟鏈畬鎴愶紝璇锋敞鎰忓悗缁伐浣溿��'},
-      {color: 'purple', remark: '鎮ㄦ湁鏂扮殑浠诲姟绛夊緟澶勭悊锛�'},
-      {color: 'gray', remark: '鎮ㄦ湁涓�灏佹湭璇婚偖浠躲��'}
+      {color: 'blue', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭紒'},
+      {color: 'purple', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭��'},
+      {color: 'gray', remark: '鎮ㄦ湁涓�鏉℃柊鐨勬秷鎭��'}
     ]
     let mockdata = []
 
@@ -693,15 +692,15 @@
    * @description 鏍¢獙閰嶇疆淇℃伅鐨勫悎娉曟��
    */
   verifyconfig = (config) => {
-    let hasKey = false
+    // let hasKey = false
     let cols = []
     config.columns.forEach(col => {
       if (col.field) {
         cols.push(col.field)
       }
-      if (config.setting.primaryKey === col.field) {
-        hasKey = true
-      }
+      // if (config.setting.primaryKey === col.field) {
+      //   hasKey = true
+      // }
     })
 
     let calvaild = true
@@ -717,10 +716,10 @@
 
     if (config.setting.interType === 'inner' && !config.setting.innerFunc && config.setting.default !== 'false' && !config.setting.dataresource) {
       return '鑿滃崟灏氭湭璁剧疆鏁版嵁婧愶紝涓嶅彲鍚敤锛�'
-    } else if (!config.setting.primaryKey) {
-      return '鑿滃崟灏氭湭璁剧疆涓婚敭锛屼笉鍙惎鐢紒'
-    } else if (!hasKey) {
-      return '鏄剧ず鍒椾腑涓嶅瓨鍦ㄤ富閿瓧娈碉紝涓嶅彲鍚敤锛�'
+    // } else if (!config.setting.primaryKey) {
+    //   return '鑿滃崟灏氭湭璁剧疆涓婚敭锛屼笉鍙惎鐢紒'
+    // } else if (!hasKey) {
+    //   return '鏄剧ず鍒椾腑涓嶅瓨鍦ㄤ富閿瓧娈碉紝涓嶅彲鍚敤锛�'
     } else if (!calvaild) {
       return '鏃ュ巻鍏宠仈瀛楁鏈缃紝涓嶅彲鍚敤锛�'
     } else {
@@ -791,16 +790,13 @@
 
   // 骞村垏鎹㈡椂閲嶆柊鐢熸垚鏁版嵁
   changeDate = (year) => {
-    this.setState({mockloading: true}, () => {
-      this.setState({
-        mockloading: false,
-        mockdata: this.getMockData(year)
-      })
+    this.setState({
+      mockdata: this.getMockData(year)
     })
   }
 
   render () {
-    const { activeKey, config, tabviews, mockdata, mockloading } = this.state
+    const { activeKey, config, tabviews, mockdata } = this.state
 
     return (
       <div className="model-calendar-board">
@@ -873,8 +869,8 @@
                 <TabComponent config={config} updateConfig={this.updateconfig} tabviews={tabviews} setSubConfig={this.setSubConfig} />
                 <CalComponent config={config} updateConfig={this.updateconfig} />
                 <CalendarComponent calendar={{
-                  levels: config.calendar.levels, startfield: 'start', endfield: 'end', colorfield: 'color', remarkfield: 'remark'
-                }} loading={mockloading} data={mockdata} changeDate={this.changeDate}/>
+                  levels: config.calendar.levels, startfield: 'start', endfield: 'end', colorfield: 'color', remarkfield: 'remark', refresh: config.calendar.refresh
+                }} data={mockdata} changeDate={this.changeDate}/>
               </div>
             </Card>
           </div>
diff --git a/src/templates/calendarconfig/tabcomponent/tabform/index.jsx b/src/templates/calendarconfig/tabcomponent/tabform/index.jsx
index f751d42..2d8b397 100644
--- a/src/templates/calendarconfig/tabcomponent/tabform/index.jsx
+++ b/src/templates/calendarconfig/tabcomponent/tabform/index.jsx
@@ -100,7 +100,7 @@
           })
         }
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} key={index}>
             <Form.Item label={
               item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
@@ -127,7 +127,7 @@
         )
       } else if (item.type === 'number') {
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} key={index}>
             <Form.Item label={
               item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
@@ -149,7 +149,7 @@
         )
       } else if (item.type === 'select') { // 涓嬫媺鎼滅储
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} key={index}>
             <Form.Item label={item.label}>
               {getFieldDecorator(item.key, {
                 initialValue: item.initVal,
@@ -177,7 +177,7 @@
         )
       } else if (item.type === 'mutilselect') {
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} key={index}>
             <Form.Item label={
               item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
@@ -203,7 +203,7 @@
         )
       } else if (item.type === 'radio') {
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} key={index}>
             <Form.Item label={item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
                 <Icon type="question-circle" />
@@ -264,7 +264,7 @@
       },
       wrapperCol: {
         xs: { span: 24 },
-        sm: { span: 16 }
+        sm: { span: 12 }
       }
     }
     return (
diff --git a/src/templates/sharecomponent/datasourcecomponent/verifycard/settingform/index.jsx b/src/templates/sharecomponent/datasourcecomponent/verifycard/settingform/index.jsx
index bac9dbf..50ac783 100644
--- a/src/templates/sharecomponent/datasourcecomponent/verifycard/settingform/index.jsx
+++ b/src/templates/sharecomponent/datasourcecomponent/verifycard/settingform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon, notification } from 'antd'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -121,7 +121,7 @@
   }
 
   render() {
-    const { columns, setting } = this.props
+    const { setting } = this.props
     const { getFieldDecorator } = this.props.form
     const { interType } = this.state
 
@@ -231,7 +231,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            <Col span={8}>
+            {/* <Col span={8}>
               <Form.Item label="涓婚敭">
                 {getFieldDecorator('primaryKey', {
                   initialValue: setting.primaryKey || ''
@@ -245,7 +245,7 @@
                   </Select>
                 )}
               </Form.Item>
-            </Col>
+            </Col> */}
             {interType === 'inner' ? <Col span={8}>
               <Form.Item label="榛樿sql">
                 {getFieldDecorator('execute', {
diff --git a/src/templates/sharecomponent/datasourcecomponent/verifycard/utils.jsx b/src/templates/sharecomponent/datasourcecomponent/verifycard/utils.jsx
index 483ccf1..8d04983 100644
--- a/src/templates/sharecomponent/datasourcecomponent/verifycard/utils.jsx
+++ b/src/templates/sharecomponent/datasourcecomponent/verifycard/utils.jsx
@@ -47,6 +47,18 @@
     })
     let _search = ''
 
+    // 鏃ュ巻涓殑骞翠唤鏇挎崲
+    if (setting.queryType === 'statistics' || _customScript) {
+      _regoptions.push({
+        reg: new RegExp('@calendarDate@', 'ig'),
+        value: `1970-01-01 00:00:00.000`
+      })
+      _regoptions.push({
+        reg: new RegExp('@calendarDate1@', 'ig'),
+        value: `2030-12-31 23:59:59.999`
+      })
+    }
+
     if (setting.queryType === 'statistics' && _dataresource) {
       _regoptions.forEach(item => {
         _dataresource = _dataresource.replace(item.reg, item.value)
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index db38fbd..d695cae 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -986,9 +986,9 @@
     }, {
       value: 'equaltab',
       text: Formdict['header.form.refresh.equaltab']
-    }, {
-      value: 'mainline',
-      text: Formdict['header.form.refresh.mainline']
+    // }, {
+    //   value: 'mainline',
+    //   text: Formdict['header.form.refresh.mainline']
     })
   }
 
@@ -2506,7 +2506,7 @@
         value: 'line-chart',
         text: 'line-chart'
       }],
-      forbid: type === 'CalendarPage',
+      forbid: type === 'CalendarPage'
     },
     {
       type: 'select',
@@ -2515,7 +2515,7 @@
       initVal: supMenu,
       required: false,
       options: menus,
-      forbid: type === 'CalendarPage',
+      forbid: type === 'CalendarPage'
     },
     {
       type: 'mutilselect',
@@ -2525,7 +2525,7 @@
       initVal: equalTab,
       required: false,
       options: equalTabs,
-      forbid: type === 'CalendarPage',
+      forbid: type === 'CalendarPage'
     },
     {
       type: 'text',
@@ -2533,7 +2533,8 @@
       label: '澶栭敭',
       tooltip: '澶栭敭鏃ㄥ湪鏍囩椤典腑鎵ц榛樿鍑芥暟锛堟坊鍔狅級鏃讹紝鏇挎崲BID瀛楁',
       initVal: card.foreignKey || '',
-      required: false
+      required: false,
+      forbid: type === 'CalendarPage'
     },
     {
       type: 'number',

--
Gitblit v1.8.0