Browse Source

feat: steps 组件开发

songqibin 5 years ago
parent
commit
0e0af91125

File diff suppressed because it is too large
+ 1 - 0
src/assets/svg/finish.svg


+ 10 - 0
src/config.json

@@ -388,6 +388,16 @@
       "sort": "0",
       "showDemo": true,
       "author": "ivanwancy"
+    },
+    {
+      "version": "1.0.0",
+      "name": "Steps",
+      "chnName": "步骤条",
+      "desc": "步骤条",
+      "type": "component",
+      "sort": "0",
+      "showDemo": true,
+      "author": "undo"
     }
   ]
 }

+ 30 - 37
src/packages/steps/demo.vue

@@ -1,55 +1,48 @@
 <template>
   <div>
-    <h4>正常流程</h4>
-    <nut-steps :current="current">
-      <nut-step title="已完成" content></nut-step>
-      <nut-step title content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="进行中" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="待进行" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="待进行" content="这里是该步骤的描述信息"></nut-step>
+    <h4>基础样式</h4>
+    <nut-steps>
+      <nut-step title="已签收" content="您的订单已由本人签收。如有疑问您可以联系配送员,感谢您在京东购物。" time="2020-03-03 11:09:96">
+        <template v-slot:status-icon>
+          <nut-icon type="self" :url="require('../../assets/svg/finish.svg')"></nut-icon>
+        </template>
+      </nut-step>
+      <nut-step title="运输中" content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step content="您的订单由京东【北京顺义分拣中心】送往【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step title="已下单" content="您提交了订单,请等待系统确认" time="2020-03-03 11:09:96"></nut-step>
     </nut-steps>
-    <h4>流程终止</h4>
-    <nut-steps :current="current" status="error">
-      <nut-step title="已完成" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="已完成" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="进行中" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="待进行" content="这里是该步骤的描述信息"></nut-step>
-      <nut-step title="待进行" content="这里是该步骤的描述信息"></nut-step>
+    <h4>时间前置</h4>
+    <nut-steps :time-forward="true">
+      <nut-step title="已签收" content="您的订单已由本人签收。如有疑问您可以联系配送员,感谢您在京东购物。" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step title="运输中" content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step content="您的订单由京东【北京顺义分拣中心】送往【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+      <nut-step title="已下单" content="您提交了订单,请等待系统确认" time="2020-03-03 11:09:96"></nut-step>
     </nut-steps>
-    <h4>动态加载(2s后渲染)</h4>
-    <nut-steps :current="current2" :source="titles">
-      <nut-step :key="index" v-for="(item, index) in titles" :title="item" content="这里是该步骤的描述信息"></nut-step>
+    <h4>横向步骤条</h4>
+    <nut-steps :current="1" type="process" direction="horizontal">
+      <nut-step title="已完成" ></nut-step>
+      <nut-step title="进行中" ></nut-step>
+      <nut-step title="等待中" ></nut-step>
+    </nut-steps>
+    <nut-steps :current="1" type="process" direction="horizontal">
+      <nut-step title="已完成" content="这里是描述文字"></nut-step>
+      <nut-step title="进行中" content="这里是描述文字"></nut-step>
+      <nut-step title="等待中" content="这里是描述文字"></nut-step>
     </nut-steps>
   </div>
 </template>
 
 <script>
 export default {
-  components: {},
-  data() {
-    return {
-      current: 3,
-      titles: [],
-      current2: 0
-    };
-  },
-  mounted() {
-    setTimeout(() => {
-      this.titles = ['已完成', '已完成', '进行中'];
-      this.current2 = 3;
-    }, 2000);
-  },
-  methods: {
-    next() {
-      this.current = this.current + 1;
-    }
-  }
+
 };
 </script>
 
 <style lang="scss" scoped>
 .nut-steps {
-  margin-left: 10px;
+  margin-left: 0 10px;
 }
 .next-step {
   text-align: center;

+ 29 - 88
src/packages/steps/doc.md

@@ -4,105 +4,44 @@
 
 ## 基本用法
 
-正常流程
+基础样式
 
 ```html
-<nut-steps 
-  :current="current"
->
-  <nut-step 
-    title="已完成" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="已完成" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="进行中" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="待进行" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="待进行" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
+<nut-steps>
+  <nut-step title="已签收" content="您的订单已由本人签收。如有疑问您可以联系配送员,感谢您在京东购物。" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step title="运输中" content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step content="您的订单由京东【北京顺义分拣中心】送往【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step title="已下单" content="您提交了订单,请等待系统确认" time="2020-03-03 11:09:96"></nut-step>
 </nut-steps>
 ```
 
-流程终止
+时间前置
 
 ```html
-<nut-steps 
-  :current="current" 
-  status="error"
->
-  <nut-step 
-    title="已完成" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="已完成" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="进行中" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="待进行" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
-  <nut-step 
-    title="待进行" 
-    content="这里是该步骤的描述信息"
-  >
-  </nut-step>
+<nut-steps :time-forward="true">
+  <nut-step title="已签收" content="您的订单已由本人签收。如有疑问您可以联系配送员,感谢您在京东购物。" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step title="运输中" content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step content="您的订单已达到京东【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step content="您的订单由京东【北京顺义分拣中心】送往【北京旧宫营业部】" time="2020-03-03 11:09:96"></nut-step>
+  <nut-step title="已下单" content="您提交了订单,请等待系统确认" time="2020-03-03 11:09:96"></nut-step>
 </nut-steps>
 ```
 
-动态加载(2s后渲染)
+横向步骤条
 ```html
-<nut-steps :current="current2" status="error" :source="titles">
-  <nut-step :key="index" v-for="(item,index) in titles" :title="item" content="这里是该步骤的描述信息"></nut-step>
+<nut-steps :current="1" type="process" direction="horizontal">
+  <nut-step title="已完成" ></nut-step>
+  <nut-step title="进行中" ></nut-step>
+  <nut-step title="等待中" ></nut-step>
+</nut-steps>
+<nut-steps :current="1" type="process" direction="horizontal">
+  <nut-step title="已完成" content="这里是描述文字"></nut-step>
+  <nut-step title="进行中" content="这里是描述文字"></nut-step>
+  <nut-step title="等待中" content="这里是描述文字"></nut-step>
 </nut-steps>
 ```
 
-``` javascript
-export default {
-  components: {},
-  data() {
-    return {
-      current: 3,
-      titles: [],
-      current2: 0
-    };
-  },
-  mounted() {
-    setTimeout(() => {
-      this.titles = ["已完成", "已完成", "进行中"];
-      this.current2 = 3;
-    }, 2000);
-  },
-  methods: {
-    next() {
-      this.current = this.current + 1;
-    }
-  }
-};
-```
 
 
 ## Prop
@@ -112,12 +51,14 @@ export default {
 | 字段    | 说明                                  | 类型   | 默认值                                                   |
 |---------|---------------------------------------|--------|----------------------------------------------------------|
 | current | 当前所在的步骤                        | Number | 0                                                        |
-| status  | 流程状态                              | String | "process"(可选值 "wait"、"process"、"finish"、"error") |
-| source  | 异步数据渲染nut-step时,必须绑定对应数组 | Array  | -                                                        |
-
+| time-forward  | 时间前置选项                    | Boolean | false |
+| direction  | 垂直或水平方向 | String  | vertical                                                       |
+| type  | 步骤条类型 | String  | '' (可选 process)                                                       |
+| source  | 数据依赖 | any  |                                                     |
 ### nut-step
   
 | 字段    | 说明              | 类型   | 默认值   |
 |---------|-------------------|--------|----------|
 | title   | 流程步骤的title   | String | 步骤     |
 | content | 流程步骤的content | String | 步骤描述 |
+| time | 流程步骤的操作时间| String | 步骤操作时间 |

+ 18 - 7
src/packages/steps/step.vue

@@ -1,10 +1,19 @@
 <template>
-  <div class="nut-step clearfix" :class="'nut-step-status-' + currentStatus">
-    <div class="nut-step-line"></div>
-    <div class="nut-step-index">{{ stepNumber }}</div>
+  <div class="nut-step clearfix" :class="`${currentStatus ? 'nut-step-status-' + currentStatus : ''}`">
+    <div v-if="timeForward && time" class="nut-step-time-forward">{{ time }}</div>
+    <div class="nut-step-node">
+      <div class="nut-step-icon">
+        <slot name="status-icon">
+          <nut-icon v-if="currentStatus === 'finish'" type="self" :url="require('../../assets/svg/finish.svg')"></nut-icon>
+          <span v-else class="default-icon"></span>
+        </slot>
+      </div>
+      <div class="nut-step-line"></div>
+    </div>
     <div class="nut-step-main">
-      <div class="nut-step-title">{{ title || nutTranslate('lang.steps.step') }}</div>
-      <div class="nut-step-content">{{ content || nutTranslate('lang.steps.stepDesc') }}</div>
+      <div v-if="title" class="nut-step-title">{{ title }}</div>
+      <div v-if="content" class="nut-step-content">{{ content }}</div>
+      <div v-if="!timeForward && time" class="nut-step-time">{{ time }}</div>
     </div>
   </div>
 </template>
@@ -19,13 +28,15 @@ export default {
     },
     content: {
       type: String
+    },
+    time: {
+      type: String
     }
   },
   data() {
     return {
       currentStatus: '',
-      stepNumber: 0,
-      stepStatus: 'nut-step-status'
+      timeForward: false,
     };
   },
   methods: {},

+ 117 - 70
src/packages/steps/steps.scss

@@ -1,3 +1,5 @@
+@import '../../styles/variable.scss';
+
 .clearfix {
   zoom: 1;
 }
@@ -11,45 +13,97 @@
 }
 
 .nut-steps {
+  &.horizontal {
+    display: flex;
+    .nut-step {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      .nut-step-node {
+        display: flex;
+        width: 100%;
+        .nut-step-line {
+          height: 1px;
+          width: 100%;
+          top: 50%;
+          left: 50%;
+        }
+      }
+      .nut-step-main {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        .nut-step-title {
+          margin-bottom: 0;
+        }
+      }
+    }
+  }
 }
 
 .nut-step {
   position: relative;
-  font-size: 14px;
-  color: #999;
+  font-size: $font-size-body-small;
+  display: flex;
 
-  .nut-step-line {
-    position: absolute;
-    top: 0;
-    left: 14px;
-    height: 100%;
-    width: 1px;
+  .nut-step-time-forward {
+    font-size: $font-size-display-small;
+    width: 75px;
+    color: $text-black-2;
   }
 
-  .nut-step-index {
+  .nut-step-node {
     position: relative;
     z-index: 99;
-    float: left;
-    width: 26px;
-    height: 26px;
-    font-size: 14px;
-    line-height: 26px;
-    text-align: center;
-    border-radius: 50%;
+    width: 30px;
+    display: flex;
+    justify-content: center;
+    .nut-step-icon {
+      width: 20px;
+      height: 20px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      position: relative;
+      z-index: 1;
+      .default-icon {
+        width: 8px;
+        height: 8px;
+        border-radius: 50%;
+        background: $split-line-color;
+      }
+    }
+    .nut-step-line {
+      position: absolute;
+      top: 14px;
+      left: 14px;
+      width: 1px;
+      height: 100%;
+      background: $split-line-color;
+    }
   }
 
   .nut-step-main {
-    padding-left: 40px;
-
+    // padding-left: 40px;
+    flex: 1;
+    margin-bottom: 20px;
     .nut-step-title {
-      line-height: 28px;
+      color: $text-black-1;
+      line-height: 20px;
       font-weight: 600;
+      margin-bottom: 5px;
     }
 
     .nut-step-content {
-      padding-bottom: 10px;
+      color: $text-black-2;
       line-height: 20px;
-      font-size: 12px;
+      font-size: $font-size-display-small;
+      margin-bottom: 8px;
+    }
+    .nut-step-time {
+      color: $text-black-3;
+      font-size: $font-size-display-small;
     }
   }
 
@@ -61,58 +115,51 @@
 
   &.nut-step-status- {
     &wait {
-      .nut-step-line {
-        background: #ccc;
-      }
-
-      .nut-step-index {
-        color: #999;
-        border: 1px solid #ccc;
-        background: #ffffff;
-      }
-    }
-
-    &finish {
-      .nut-step-line {
-        background: mix($primary-color, #0f0, 50%);
-      }
-
-      .nut-step-index {
-        border: 1px solid mix($primary-color, #0f0, 50%);
-        background: #ffffff;
-        color: mix($primary-color, #0f0, 50%);
+      .nut-step-node {
+        .nut-step-icon {
+          .default-icon {
+            width: 20px;
+            height: 20px;
+            line-height: 20px;
+            border-radius: 50%;
+            background: $split-line-color;
+            position: relative;
+            &::before {
+              content: '...';
+              position: absolute;
+              top: -4px;
+              width: 100%;
+              height: 100%;
+              color: $btn-default-bg;
+              text-align: center;
+            }
+          }
+        }
       }
     }
-
     &process {
-      .nut-step-line {
-        background: #ccc;
-      }
-
-      .nut-step-main {
-        color: #666;
-      }
-
-      .nut-step-index {
-        border: 1px solid mix($primary-color, #0f0, 50%);
-        background: mix($primary-color, #0f0, 50%);
-        color: #ffffff;
-      }
-    }
-
-    &error {
-      .nut-step-line {
-        background: #ccc;
-      }
-
-      .nut-step-main {
-        color: $primary-color;
-      }
-
-      .nut-step-index {
-        border: 1px solid $primary-color;
-        background: #ffffff;
-        color: $primary-color;
+      .nut-step-node {
+        .nut-step-icon {
+          .default-icon {
+            width: 15px;
+            height: 15px;
+            border-radius: 50%;
+            background: $assist-color-orange;
+            position: relative;
+            z-index: 1;
+            &::before {
+              content: '';
+              position: absolute;
+              top: 50%;
+              left: 50%;
+              transform: translate(-50%, -50%);
+              width: 7px;
+              height: 7px;
+              border-radius: 50%;
+              background: $primary-color-jd-red;
+            }
+          }
+        }
       }
     }
   }

+ 28 - 23
src/packages/steps/steps.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="nut-steps">
+  <div class="nut-steps" :class="{horizontal: direction === 'horizontal'}">
     <slot></slot>
   </div>
 </template>
@@ -8,7 +8,19 @@ export default {
   name: 'nut-steps',
   props: {
     current: {
-      type: Number
+      type: Number,
+      default: 0
+    },
+    timeForward: {
+      type: Boolean,
+      default: false
+    },
+    direction: {
+      type: String,
+      default: 'vertical'
+    },
+    type: {
+      type: String
     },
     source: {
       type: Array,
@@ -16,45 +28,38 @@ export default {
         return [];
       }
     },
-    status: {
-      validator(value) {
-        return ['wait', 'process', 'finish', 'error'].includes(value);
-      },
-      default: 'process'
-    }
   },
   data() {
     return {
-      steps: [],
-      stepOffset: 0
+      steps: []
     };
   },
   methods: {
     updateChildProps(isInit) {
       const total = this.steps.length;
       this.steps.forEach((child, index) => {
-        child.stepNumber = index + 1;
-        if (this.direction === 'horizontal') {
-          child.total = total;
-        }
         // 如果已存在status,且在初始化时,则略过
         // todo 如果当前是error,在current改变时需要处理
         if (!(isInit && child.currentStatus)) {
-          if (index == this.current - 1) {
-            if (this.status != 'error') {
-              child.currentStatus = 'process';
-            } else {
-              child.currentStatus = 'error';
+          if (this.current === index) {
+            child.currentStatus = 'process';
+          }
+          if (this.type === 'process') {
+            if (index < this.current) {
+              child.currentStatus = 'finish';
+            }
+            if (index > this.current) {
+              child.currentStatus = 'wait';
             }
-          } else if (index < this.current) {
-            child.currentStatus = 'finish';
-          } else {
-            child.currentStatus = 'wait';
           }
         }
+        
         if (index + 1 === total) {
           child.currentStatus += ' nut-step-last';
         }
+        if (this.timeForward) {
+          child.timeForward = true;
+        }
       });
     },
     init() {