浏览代码

feat: ecard、datepicker taro bug (#1184)

* feat: ecard新增

* fix: datepicker在Taro上更新
yangxiaolu1993 3 年之前
父节点
当前提交
89f36a4535

+ 31 - 26
src/config.json

@@ -51,7 +51,8 @@
       }
     ]
   },
-  "nav": [{
+  "nav": [
+    {
       "name": "基础组件",
       "enName": "base",
       "packages": [
@@ -110,7 +111,8 @@
           "sort": 14,
           "show": true,
           "author": "szg2008"
-        }, {
+        },
+        {
           "version": "3.0.0",
           "name": "Popup",
           "taro": true,
@@ -121,7 +123,6 @@
           "desc": "弹出层容器,用于展示弹窗、信息提示等内容,支持多个弹出层叠加展示",
           "author": "szg2008"
         }
-
       ]
     },
     {
@@ -163,7 +164,6 @@
           "desc": "布局组件Row",
           "author": "undo"
         },
-
         {
           "version": "3.0.0",
           "name": "Sticky",
@@ -215,7 +215,8 @@
     {
       "name": "导航组件",
       "enName": "nav",
-      "packages": [{
+      "packages": [
+        {
           "version": "3.0.0",
           "name": "Navbar",
           "taro": true,
@@ -380,7 +381,8 @@
     {
       "name": "数据录入",
       "enName": "dentry",
-      "packages": [{
+      "packages": [
+        {
           "version": "3.0.0",
           "name": "Range",
           "taro": true,
@@ -568,7 +570,6 @@
           "desc": "上传文件、图片",
           "author": "richard1015"
         },
-
         {
           "version": "3.0.0",
           "name": "NumberKeyboard",
@@ -580,7 +581,6 @@
           "desc": "虚拟数字键盘",
           "author": "Drjingfubo"
         },
-
         {
           "version": "3.0.0",
           "name": "Form",
@@ -604,7 +604,6 @@
           "exportEmpty": true,
           "author": "richard1015"
         },
-
         {
           "version": "3.0.0",
           "name": "OldPicker",
@@ -621,7 +620,8 @@
     {
       "name": "操作反馈",
       "enName": "feedback",
-      "packages": [{
+      "packages": [
+        {
           "version": "3.0.0",
           "name": "Swipe",
           "taro": true,
@@ -655,7 +655,6 @@
           "desc": "较长页面快捷返回顶部",
           "author": "liqiong43"
         },
-
         {
           "version": "3.0.0",
           "name": "Drag",
@@ -704,7 +703,6 @@
           "show": true,
           "author": "wangyue217"
         },
-
         {
           "version": "3.0.0",
           "name": "PullRefresh",
@@ -715,7 +713,6 @@
           "show": false,
           "author": "yangxiaolu3"
         },
-
         {
           "version": "3.0.0",
           "name": "Switch",
@@ -739,7 +736,6 @@
           "desc": "轻提示",
           "author": "undo"
         },
-
         {
           "version": "3.0.0",
           "name": "Audio",
@@ -750,8 +746,8 @@
           "desc": "音频播放器",
           "sort": 25,
           "show": true,
-          "exportEmpty":false,
-          "exportEmptyTaro":false,
+          "exportEmpty": false,
+          "exportEmptyTaro": false,
           "author": "yangxiaolu"
         },
         {
@@ -762,17 +758,17 @@
           "desc": "音频操作按钮",
           "sort": 26,
           "show": false,
-          "exportEmpty":false,
-          "exportEmptyTaro":false,
+          "exportEmpty": false,
+          "exportEmptyTaro": false,
           "author": "yangxiaolu"
         }
-
       ]
     },
     {
       "name": "展示组件",
       "enName": "exhibition",
-      "packages": [{
+      "packages": [
+        {
           "version": "3.0.0",
           "name": "List",
           "cType": "操作反馈",
@@ -816,7 +812,6 @@
           "taro": true,
           "author": "yangxiaolu"
         },
-
         {
           "version": "3.0.0",
           "name": "Empty",
@@ -838,11 +833,10 @@
           "taro": false,
           "show": true,
           "tarodoc": true,
-          "exportEmpty":false,
-          "exportEmptyTaro":false,
+          "exportEmpty": false,
+          "exportEmptyTaro": false,
           "author": "zy19940510"
         },
-
         {
           "version": "3.0.0",
           "name": "Steps",
@@ -1027,7 +1021,8 @@
     {
       "name": "特色组件",
       "enName": "business",
-      "packages": [{
+      "packages": [
+        {
           "version": "3.0.0",
           "taro": true,
           "name": "Address",
@@ -1117,8 +1112,18 @@
           "sort": 1,
           "show": true,
           "author": "Drjingfubo"
+        },
+        {
+          "version": "3.0.0",
+          "name": "Ecard",
+          "cType": "特色组件",
+          "cName": "虚拟电子卡",
+          "desc": "虚拟电子卡选择",
+          "show": true,
+          "tarodoc": false,
+          "type": "component",
+          "author": "yangxiaolu"
         }
-
       ]
     }
   ]

+ 3 - 0
src/packages/__VUE/datepicker/index.taro.vue

@@ -187,6 +187,9 @@ export default create({
         case 'time':
           result = result.slice(3, 6);
           break;
+        case 'year-month':
+          result = result.slice(0, 2);
+          break;
         case 'month-day':
           result = result.slice(1, 3);
           break;

+ 1 - 0
src/packages/__VUE/ecard/__tests__/ecard.spec.ts

@@ -0,0 +1 @@
+import { mount } from '@vue/test-utils';

+ 66 - 0
src/packages/__VUE/ecard/demo.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-cell>
+      <nut-ecard
+        chooseText="请选择电子卡面值"
+        @inputChange="inputChange"
+        @change="change"
+        @changeStep="changeStep"
+        :data-list="dataList"
+        v-model="money"
+      ></nut-ecard>
+    </nut-cell>
+  </div>
+</template>
+<script lang="ts">
+import { reactive, ref } from 'vue';
+import { createComponent } from '../../utils/create';
+const { createDemo } = createComponent('ecard');
+export default createDemo({
+  props: {},
+  setup() {
+    const dataList = reactive([
+      {
+        price: 10
+      },
+      {
+        price: 20
+      },
+      {
+        price: 30
+      },
+      {
+        price: 40
+      }
+    ]);
+    const money = ref(0);
+    const inputChange = (val: any) => {
+      money.value = val;
+    };
+    const change = (item: any) => {
+      console.log(item);
+      money.value = item.price;
+    };
+    const changeStep = (num) => {
+      const val = money.value * num;
+      if (val > 100) {
+        money.value = val * 0.9;
+      } else {
+        money.value = val;
+      }
+    };
+    return {
+      dataList,
+      inputChange,
+      change,
+      money,
+      changeStep
+    };
+  }
+});
+</script>
+<style lang="scss" scoped>
+.demo {
+}
+</style>

+ 98 - 0
src/packages/__VUE/ecard/doc.md

@@ -0,0 +1,98 @@
+# Ecard 电子卡
+
+### 介绍
+
+虚拟电子卡选择
+
+### 安装
+
+```javascript
+
+import { createApp } from 'vue';
+// vue
+import { Ecard, InputNumber } from '@nutui/nutui';
+// taro
+import { Ecard, InputNumber } from '@nutui/nutui-taro';
+
+const app = createApp();
+app.use(Ecard);
+app.use(InputNumber);
+
+```
+
+### 基础用法
+
+:::demo
+
+```html
+<template>
+  <nut-ecard 
+    chooseText='请选择电子卡面值'
+    @inputChange="inputChange" 
+    @change="change" 
+    :data-list="dataList" 
+    :money="money">
+  </nut-ecard>
+</template>
+<script>
+  import { reactive, toRefs } from 'vue';
+  export default {
+    setup() {
+      const dataList=reactive([
+        {
+          price:10
+        },
+        {
+          price:20
+        },
+        {
+          price:30
+        },
+        {
+          price:40
+        },
+      ])
+      const money = ref(0)
+      const inputChange = (val:any)=>{
+        money.value = val
+      }
+      const change = (item:any)=>{
+        money.value = item.price
+      }
+      return {
+        dataList,
+        inputChange,
+        change,
+        money
+      };
+    }
+  };
+</script>
+```
+
+:::
+
+## API
+
+### Props
+
+| 参数         | 说明                             | 类型   | 默认值           |
+|--------------|----------------------------------|--------|------------------|
+| choose-text         | 选择面值文案               | String |   请选择电子卡面值              |
+| other-value-text        | 其他面值文案   | String |         其他面值        |
+| data-list         | 电子卡面值列表| Array |        []        |
+| card-amount-min| 其它面值最小值     | Number | 1|
+| card-amount-max        | 其他面值最大值                      | Number | 9999            |
+| card-buy-min        | 购买数量最小值                      | Number | 9999            |
+| card-buy-max        | 购买数量最大值                      | Number | 9999            |
+| money        | 购买电子卡所需价钱                    | Number | 0            |
+| placeholder        | 其他面值默认提示语                    | String |    请输入1-5000整数         |
+| suffix        | 符号标示                      | String | ¥            |
+
+### Events
+
+| 事件名 | 说明           | 回调参数     |
+|--------|----------------|--------------|
+| change  | 选中电子卡事件 | 点击的数据 |
+| input-change  | 更改input框触发事件 |输入的数据 |
+| change-step  | 更改数量时触发 | 当前数量 |

+ 83 - 0
src/packages/__VUE/ecard/index.scss

@@ -0,0 +1,83 @@
+.nut-ecard {
+  width: 100%;
+
+  &__title {
+    line-height: 1;
+    font-size: 15px;
+    font-family: PingFangSC;
+    font-weight: normal;
+    color: rgba(0, 0, 0, 0.6);
+  }
+
+  &__list {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    margin-top: 15px;
+
+    &__item {
+      width: 48%;
+      height: 46px;
+      background: $ecard-bg-color;
+      border-radius: 4px;
+      margin-bottom: 12px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      &.active {
+        background: $white;
+        border: 1px solid $primary-color;
+        border-radius: 4px;
+      }
+    }
+
+    &__input {
+      width: 100%;
+      height: 46px;
+      background: $ecard-bg-color;
+      color: rgba(0, 0, 0, 0.8);
+      border-radius: 4px;
+      display: flex;
+      padding: 0 15px 0 20px;
+      font-size: 14px;
+      justify-content: space-between;
+      align-items: center;
+
+      &--con {
+        flex: 1;
+        display: flex;
+        justify-content: flex-end;
+        > input {
+          caret-color: $primary-color; //光标颜色
+          text-align: right;
+          background: $ecard-bg-color;
+          margin-right: 10px;
+          outline: 0 none;
+          border: 0;
+          text-decoration: none;
+        }
+      }
+
+      &.active {
+        background: $white;
+        border: 1px solid $primary-color;
+
+        > view > input {
+          background: $white;
+        }
+      }
+    }
+
+    &__step {
+      width: 100%;
+      margin-top: 17px;
+      display: flex;
+      justify-content: space-between;
+      font-size: 20px;
+      font-family: PingFangSC;
+      font-weight: normal;
+      color: $primary-color;
+    }
+  }
+}

+ 129 - 0
src/packages/__VUE/ecard/index.taro.vue

@@ -0,0 +1,129 @@
+<template>
+  <view class="nut-ecard">
+    <view class="nut-ecard__title">{{ chooseText }}</view>
+    <view class="nut-ecard__list">
+      <view
+        v-for="(item, index) in dataList"
+        :key="index"
+        :class="['nut-ecard__list__item', currentIndex == index ? 'active' : '']"
+        @click="handleClick(item, index)"
+      >
+        {{ item.price }}
+      </view>
+      <view :class="['nut-ecard__list__input', currentIndex == 'input' ? 'active' : '']" @click="inputClick">
+        <view>{{ otherValueText }}</view>
+        <view class="nut-ecard__list__input--con">
+          <input type="text" :value="inputValue" @input="change" :placeholder="placeholder" />
+          {{ suffix }}
+        </view>
+      </view>
+      <view class="nut-ecard__list__step">
+        <view>{{ suffix }}{{ money }}</view>
+        <nut-inputnumber v-model="stepValue" :min="cardBuyMin" :max="cardBuyMax" @change="changeStep" />
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts">
+import { Ref, ref, watch } from 'vue';
+import { createComponent } from '../../utils/create';
+const { componentName, create } = createComponent('ecard');
+export default create({
+  props: {
+    chooseText: {
+      type: String,
+      default: '请选择电子卡面值'
+    },
+    otherValueText: {
+      type: String,
+      default: '其他面值'
+    },
+    dataList: {
+      type: [Object, Array],
+      default: () => {
+        return [];
+      }
+    },
+    cardAmountMin: {
+      type: Number,
+      default: 1
+    },
+    cardAmountMax: {
+      type: Number,
+      default: 9999
+    },
+    cardBuyMin: {
+      type: Number,
+      default: 1
+    },
+    cardBuyMax: {
+      type: Number,
+      default: 9999
+    },
+    modelValue: {
+      type: Number,
+      default: 0
+    },
+    placeholder: {
+      type: String,
+      default: '请输入1-5000整数'
+    },
+    suffix: {
+      type: String,
+      default: '¥'
+    }
+  },
+  emits: ['inputChange', 'changeStep', 'inputClick', 'change', 'update:modelValue'],
+
+  setup(props, { emit }) {
+    const currentIndex: Ref<number | null | string> = ref(null);
+    const inputValue: Ref<string | undefined | number> = ref();
+    const stepValue: Ref<number> = ref(props.cardAmountMin);
+    const money: Ref<number | string | undefined> = ref(props.modelValue);
+    const handleClick = (item: { price: number | string }, index: number) => {
+      currentIndex.value = index;
+      inputValue.value = '';
+      emit('change', item);
+    };
+    const change = (event: Event) => {
+      let input = event.target as HTMLInputElement;
+      let val = input.value.replace(/[^\d]/g, '');
+
+      inputValue.value = val;
+      if (Number(val) > props.cardAmountMax) {
+        inputValue.value = props.cardAmountMax;
+      }
+      if (Number(val) < props.cardAmountMin) {
+        inputValue.value = props.cardAmountMin;
+      }
+      emit('inputChange', Number(inputValue.value));
+    };
+    const inputClick = () => {
+      currentIndex.value = 'input';
+      emit('update:modelValue', 0);
+      emit('inputClick');
+    };
+    const changeStep = (value: number) => {
+      stepValue.value = value;
+      emit('changeStep', stepValue.value); // 返回数量
+    };
+    watch(
+      () => props.modelValue,
+      (value) => {
+        console.log('value', value);
+        money.value = value;
+      }
+    );
+    return {
+      handleClick,
+      changeStep,
+      change,
+      inputClick,
+      stepValue,
+      currentIndex,
+      inputValue,
+      money
+    };
+  }
+});
+</script>

+ 142 - 0
src/packages/__VUE/ecard/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <view class="nut-ecard">
+    <view class="nut-ecard__title">{{ chooseText }}</view>
+    <view class="nut-ecard__list">
+      <view
+        v-for="(item, index) in dataList"
+        :key="index"
+        :class="['nut-ecard__list__item', currentIndex == index ? 'active' : '']"
+        @click="handleClick(item, index)"
+      >
+        {{ item.price }}
+      </view>
+      <view :class="['nut-ecard__list__input', currentIndex == 'input' ? 'active' : '']" @click="inputClick">
+        <view>{{ otherValueText }}</view>
+        <view class="nut-ecard__list__input--con">
+          <input type="text" v-model="inputValue" @input="change" :placeholder="placeholder" />
+          {{ suffix }}
+        </view>
+      </view>
+      <view class="nut-ecard__list__step">
+        <view>{{ suffix }}{{ money }}</view>
+        <nut-inputnumber v-model="stepValue" :min="cardBuyMin" :max="cardBuyMax" @change="changeStep" />
+      </view>
+    </view>
+  </view>
+</template>
+<script lang="ts">
+import { Ref, ref, watch } from 'vue';
+import { createComponent } from '../../utils/create';
+const { componentName, create } = createComponent('ecard');
+
+interface props {
+  chooseText: string; // 选择文案
+  dataList: Array<any>; // 电子卡列表
+  cardAmountMin: number; // 其他面值最小值
+  cardAmountMax: number; // 其他面值最大值
+  cardBuyMin: number; // 其他面值最小值
+  cardBuyMax: number; // 其他面值最大值
+  modelValue: number; // 购买电子卡需花费的价钱
+  placeholder: string; //提示语
+  suffix: string; // 符号标示
+  otherValueText: string; // 其他面值
+}
+
+export default create({
+  props: {
+    chooseText: {
+      type: String,
+      default: '请选择电子卡面值'
+    },
+    otherValueText: {
+      type: String,
+      default: '其他面值'
+    },
+    dataList: {
+      type: [Object, Array],
+      default: () => {
+        return [];
+      }
+    },
+    cardAmountMin: {
+      type: Number,
+      default: 1
+    },
+    cardAmountMax: {
+      type: Number,
+      default: 9999
+    },
+    cardBuyMin: {
+      type: Number,
+      default: 1
+    },
+    cardBuyMax: {
+      type: Number,
+      default: 9999
+    },
+    modelValue: {
+      type: Number,
+      default: 0
+    },
+    placeholder: {
+      type: String,
+      default: '请输入1-5000整数'
+    },
+    suffix: {
+      type: String,
+      default: '¥'
+    }
+  },
+  emits: ['inputChange', 'changeStep', 'inputClick', 'change', 'update:modelValue'],
+
+  setup(props, { emit }) {
+    const currentIndex: Ref<number | null | string> = ref(null);
+    const inputValue: Ref<string | undefined | number> = ref();
+    const stepValue: Ref<number> = ref(props.cardAmountMin);
+    const money: Ref<number | string | undefined> = ref(props.modelValue);
+    const handleClick = (item: { price: number | string }, index: number) => {
+      currentIndex.value = index;
+      inputValue.value = '';
+      emit('change', item);
+    };
+    const change = (event: Event) => {
+      let input = event.target as HTMLInputElement;
+      let val = input.value.replace(/[^\d]/g, '');
+      inputValue.value = val;
+      if (Number(val) > props.cardAmountMax) {
+        inputValue.value = props.cardAmountMax;
+      }
+      if (Number(val) < props.cardAmountMin) {
+        inputValue.value = props.cardAmountMin;
+      }
+      emit('inputChange', Number(inputValue.value));
+    };
+    const inputClick = () => {
+      currentIndex.value = 'input';
+      emit('update:modelValue', 0);
+      emit('inputClick');
+    };
+    const changeStep = (value: number) => {
+      stepValue.value = value;
+      emit('changeStep', stepValue.value); // 返回数量
+    };
+    watch(
+      () => props.modelValue,
+      (value) => {
+        console.log('value', value);
+        money.value = value;
+      }
+    );
+    return {
+      handleClick,
+      changeStep,
+      change,
+      inputClick,
+      stepValue,
+      currentIndex,
+      inputValue,
+      money
+    };
+  }
+});
+</script>

+ 2 - 1
src/packages/__VUE/picker/ColumnTaro.vue

@@ -182,7 +182,6 @@ export default create({
         } else {
           deg = `${(-updateMove / state.lineSpacing + 1) * state.rotation}deg`;
         }
-
         setTransform(updateMove, null, undefined, deg);
         state.currIndex = Math.abs(Math.round(updateMove / state.lineSpacing)) + 1;
       }
@@ -226,6 +225,8 @@ export default create({
           setTimeout(() => {
             getReference();
           }, 200);
+        } else {
+          state.transformY = 0;
         }
       },
       {

+ 3 - 0
src/packages/styles/variables-jdt.scss

@@ -724,5 +724,8 @@ $elevator-list-item-bars-inner-item-font-size: 10px !default;
 // list
 $list-item-margin: 0 0 10px 0;
 
+//Ecard
+$ecard-bg-color: #f0f2f5 !default;
+
 @import './mixins/index';
 @import './animation/index';

+ 3 - 0
src/packages/styles/variables.scss

@@ -748,5 +748,8 @@ $elevator-list-item-bars-inner-item-font-size: 10px !default;
 // list
 $list-item-margin: 0 0 10px 0;
 
+//Ecard
+$ecard-bg-color: #f0f2f5 !default;
+
 @import './mixins/index';
 @import './animation/index';

+ 1 - 1
src/sites/mobile-taro/vue/project.private.config.json

@@ -26,7 +26,7 @@
         },
         {
           "name": "dentry/pages/pickers/index",
-          "pathName": "dentry/pages/pickers/index",
+          "pathName": "dentry/pages/picker/index",
           "query": "",
           "scene": null,
           "launchMode": "default"

+ 2 - 1
src/sites/mobile-taro/vue/src/app.config.ts

@@ -86,7 +86,8 @@ export default {
         'pages/signature/index',
         'pages/timeselect/index',
         'pages/sku/index',
-        'pages/card/index'
+        'pages/card/index',
+        'pages/ecard/index'
       ]
     }
   ],

+ 1 - 0
src/sites/mobile-taro/vue/src/business/pages/ecard/index.config.ts

@@ -0,0 +1 @@
+export default { navigationBarTitleText: 'Ecard' };

+ 59 - 0
src/sites/mobile-taro/vue/src/business/pages/ecard/index.vue

@@ -0,0 +1,59 @@
+<template>
+  <div class="demo">
+    <h2>基础用法</h2>
+    <nut-cell>
+      <nut-ecard
+        chooseText="请选择电子卡面值"
+        @inputChange="inputChange"
+        @change="change"
+        @changeStep="changeStep"
+        :data-list="dataList"
+        v-model="money"
+      ></nut-ecard>
+    </nut-cell>
+  </div>
+</template>
+<script lang="ts">
+import { defineComponent, reactive, ref } from 'vue';
+export default defineComponent({
+  props: {},
+  setup() {
+    const dataList = reactive([
+      {
+        price: 10
+      },
+      {
+        price: 20
+      },
+      {
+        price: 30
+      },
+      {
+        price: 40
+      }
+    ]);
+    const money = ref(0);
+    const inputChange = (val: any) => {
+      money.value = val;
+    };
+    const change = (item: any) => {
+      money.value = item.price;
+    };
+    const changeStep = (num: any) => {
+      const val = money.value * num;
+      if (val > 100) {
+        money.value = val * 0.9;
+      } else {
+        money.value = val;
+      }
+    };
+    return {
+      dataList,
+      inputChange,
+      change,
+      money,
+      changeStep
+    };
+  }
+});
+</script>

+ 4 - 3
src/sites/mobile-taro/vue/src/dentry/pages/picker/index.vue

@@ -14,7 +14,7 @@
     <h2>默认选中项</h2>
     <nut-cell title="请选择城市" :desc="defult" @click="open(1)"></nut-cell>
     <nut-picker
-      v-model="selectedValue"
+      v-model="selectedVal"
       v-model:visible="showDefult"
       :columns="columns"
       title="城市选择"
@@ -58,7 +58,7 @@ import { PickerOption } from '../../../../../../../packages/__VUE/picker/types';
 export default {
   props: {},
   setup() {
-    const selectedValue = ref(['ZheJiang']);
+    const selectedVal = ref(['ZheJiang']);
     const asyncValue = ref<string[]>([]);
     const columns = ref([
       { text: '南京市', value: 'NanJing' },
@@ -187,6 +187,7 @@ export default {
     });
 
     const confirm = (tag: string, { selectedValue }: { selectedValue: string[] }) => {
+      console.log('确定', selectedVal.value);
       desc[tag] = selectedValue.join(',');
     };
     const change = ({ selectedValue }: { selectedValue: string[] }) => {
@@ -194,7 +195,7 @@ export default {
     };
 
     return {
-      selectedValue,
+      selectedVal,
       asyncValue,
       columns,
       show,