浏览代码

feat: 发票组件+taro (#1590)

ailululu 3 年之前
父节点
当前提交
d40bdc3c85

+ 12 - 0
src/config.json

@@ -1247,6 +1247,18 @@
           "tarodoc": false,
           "type": "component",
           "author": "yangxiaolu"
+        },
+        {
+          "version": "3.0.0",
+          "name": "Invoice",
+          "cType": "特色组件",
+          "cName": "发票",
+          "desc": "发票",
+          "show": true,
+          "tarodoc": false,
+          "type": "component",
+          "author": "ailululu",
+          "taro": true
         }
       ]
     }

+ 115 - 0
src/packages/__VUE/invoice/demo.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="demo full">
+    <h2>{{ translate('basic') }}</h2>
+    <nut-invoice :data="data" :formValue="formValue" @onSubmit="submit"></nut-invoice>
+  </div>
+</template>
+
+<script lang="ts">
+import { ref, reactive } from 'vue';
+import { createComponent } from '@/packages/utils/create';
+const { createDemo, translate } = createComponent('invoice');
+import { useTranslate } from '@/sites/assets/util/useTranslate';
+import { Toast } from '@/packages/nutui.vue';
+
+const initTranslate = () =>
+  useTranslate({
+    'zh-CN': {
+      basic: '基本用法'
+    },
+    'en-US': {
+      basic: 'Basic Usage'
+    }
+  });
+export default createDemo({
+  props: {},
+  setup() {
+    initTranslate();
+    const formValue = reactive({
+      name: '',
+      num: '',
+      adress: '',
+      tel: '',
+      address: '',
+      bank: '',
+      account: ''
+    });
+
+    // Promise 异步校验
+    const asyncValidator = (val: string) => {
+      return new Promise((resolve) => {
+        Toast.loading('模拟异步验证中...');
+        setTimeout(() => {
+          Toast.hide();
+          resolve(/^400(-?)[0-9]{7}$|^1\d{10}$|^0[0-9]{2,3}-[0-9]{7,8}$/.test(val));
+        }, 1000);
+      });
+    };
+
+    let data: any = ref([
+      {
+        label: '发票抬头',
+        placeholder: '请输入发票抬头',
+        formItemProp: 'name',
+        rules: [{ required: true, message: '请输入发票抬头' }],
+        required: true
+      },
+      {
+        label: '纳税人识别号',
+        placeholder: '请输入纳税人识别号',
+        formItemProp: 'num',
+        rules: [{ message: '请输入纳税人识别号' }]
+      },
+      {
+        label: '注册地址',
+        placeholder: '请输入注册地址',
+        formItemProp: 'adress',
+        rules: [{ required: true, message: '请输入地址' }],
+        required: true
+      },
+      {
+        label: '注册电话',
+        placeholder: '请输入注册电话',
+        formItemProp: 'tel',
+        rules: [
+          { required: true, message: '请输入联系电话' },
+          { validator: asyncValidator, message: '电话格式不正确' }
+        ],
+        required: true
+      },
+      {
+        label: '开户行',
+        placeholder: '请输入开户行',
+        formItemProp: 'bank'
+      },
+      {
+        label: '银行账户',
+        placeholder: '请输入银行账户',
+        formItemProp: 'account'
+      }
+    ]);
+
+    const submit = (valid: boolean, errors: []) => {
+      if (valid) {
+        console.log('success', formValue);
+      } else {
+        console.log('error submit!!', errors);
+      }
+    };
+
+    return {
+      translate,
+      data,
+      formValue,
+      submit,
+      asyncValidator
+    };
+  }
+});
+</script>
+
+<style lang="scss" scoped>
+.nut-button {
+  margin-right: 10px;
+}
+</style>

+ 156 - 0
src/packages/__VUE/invoice/doc.en-US.md

@@ -0,0 +1,156 @@
+# Progress
+
+### Intro
+
+Used to show the current progress of the operation.
+
+### Install
+
+``` javascript
+import { createApp } from 'vue';
+//vue
+import { Progress,Icon } from '@nutui/nutui';
+//taro
+import { Progress,Icon } from '@nutui/nutui-taro';
+
+const app = createApp();
+app.use(Progress);
+app.use(Icon);
+
+```
+
+
+### Basic Usage
+:::demo
+```html
+<template>
+  <nut-cell>
+     <nut-progress percentage="30" />
+  </nut-cell>
+</template>
+```
+:::
+### Custom Style
+
+:::demo
+```html
+<template>
+  <nut-cell>
+    <nut-progress percentage="30" stroke-color=" rgba(250,44,25,0.47)" stroke-width="20" text-color="red" />
+   </nut-cell>
+</template>
+```
+:::
+### Don't  Show Percentage
+:::demo
+```html
+<template>
+  <nut-cell>
+     <nut-progress percentage="50" :show-text="false" stroke-height="24" />
+  </nut-cell>
+</template>
+```
+:::
+### Show Percentage
+
+:::demo
+```html
+<template>
+  <nut-cell>
+     <nut-progress percentage="30" />
+  </nut-cell>
+</template>
+```
+:::
+
+### Text Inside
+:::demo
+```html
+<template>
+     <nut-cell>
+        <nut-progress percentage="60" :text-inside="true" />
+      </nut-cell>
+</template>
+```
+:::
+### Custom Content
+:::demo
+```html
+<template>
+     <nut-cell>
+        <nut-progress percentage="60" :text-inside="true">
+          <nut-icon
+            style="display: block"
+            size="30"
+            name="https://img11.360buyimg.com/imagetools/jfs/t1/137646/13/7132/1648/5f4c748bE43da8ddd/a3f06d51dcae7b60.png"
+          ></nut-icon>
+        </nut-progress>
+      </nut-cell>
+</template>
+```
+:::
+
+## Custom Size
+
+ **small**,**base**,**large** .
+:::demo
+```html
+<template>
+  <nut-cell>
+        <nut-progress percentage="30" :text-inside="true" size="small"> </nut-progress>
+      </nut-cell>
+      <nut-cell>
+        <nut-progress percentage="50" :text-inside="true" size="base"> </nut-progress>
+      </nut-cell>
+      <nut-cell>
+        <nut-progress percentage="70" :text-inside="true" size="large"> </nut-progress>
+      </nut-cell>
+</template>
+```
+:::
+### Status Display
+:::demo
+```html
+<template>
+   <div>
+      <nut-cell>
+        <nut-progress
+          percentage="30"
+          stroke-color="linear-gradient(270deg, rgba(18,126,255,1) 0%,rgba(32,147,255,1) 32.815625%,rgba(13,242,204,1) 100%)"
+          status="active"
+        />
+      </nut-cell>
+      <nut-cell>
+        <nut-progress percentage="50" :stroke-width="strokeWidth" status="icon" />
+      </nut-cell>
+      <nut-cell>
+        <nut-progress
+          percentage="100"
+          stroke-color="linear-gradient(90deg, rgba(180,236,81,1) 0%,rgba(66,147,33,1) 100%)"
+          stroke-width="15"
+          status="icon"
+          icon-name="issue"
+          icon-color="red"
+        />
+      </nut-cell>
+    </div>
+</template>
+```
+:::
+
+## Prop
+
+| Attribute | Description | Type | Default
+|----- | ----- | ----- | -----
+| percentage | percentage | Number | 0
+| is-show-percentage | Whether to display the percent sign | Boolean | true
+| stroke-color |Stroke color | String | #f30
+| stroke-width |Stroke width | String | ''
+| size | Progress bar and text size, small/base/large | String | -
+| show-text | Whether to show text | Boolean | true
+| text-inside | Progress bar text display position(false:outside,true:Inside) | Boolean | false
+| text-color | Progress bar text color setting | String | #333
+| text-background | Progress bar text background color setting | String | Same progress bar color
+| status | The current state of the progress bar,active(show animation)/icon(show icon) | String | text
+| icon-name | Icon Name | String | checked
+| icon-color | Icon Color | String | #439422

+ 150 - 0
src/packages/__VUE/invoice/doc.md

@@ -0,0 +1,150 @@
+# Invoice f发票
+
+### 介绍
+
+展示操作或任务的当前进度。
+
+### 安装
+
+``` javascript
+import { createApp } from 'vue';
+//vue
+import { Invoice,Form,FormItem,Button } from '@nutui/nutui';
+//taro
+import { Invoice,Form,FormItem,Button } from '@nutui/nutui-taro';
+
+const app = createApp();
+app.use(Invoice);
+app.use(Form);
+app.use(FormItem);
+app.use(Button);
+
+```
+
+
+### 基础用法
+:::demo
+```html
+<template>
+  <nut-invoice 
+    :data="data" 
+    :formValue="formValue" 
+    @onSubmit="submit"
+  >
+  </nut-invoice>
+</template>
+<script lang="ts">
+import { ref,reactive } from 'vue';
+export default {
+  setup(){
+    // Promise 异步校验
+    const asyncValidator = (val: string) => {
+      return new Promise((resolve) => {
+        Toast.loading('模拟异步验证中...');
+        setTimeout(() => {
+          Toast.hide();
+          resolve(/^400(-?)[0-9]{7}$|^1\d{10}$|^0[0-9]{2,3}-[0-9]{7,8}$/.test(val));
+        }, 1000);
+      });
+    };
+
+    let data: any = ref([
+      {
+        label: '发票抬头',
+        placeholder: '请输入发票抬头',
+        formItemProp: 'name',
+        rules: [{ required: true, message: '请输入发票抬头' }],
+        required: true
+      },
+      {
+        label: '纳税人识别号',
+        placeholder: '请输入纳税人识别号',
+        formItemProp: 'num',
+        rules: [{ message: '请输入纳税人识别号' }],
+      },
+      {
+        label: '注册地址',
+        placeholder: '请输入注册地址',
+        formItemProp: 'adress',
+        rules: [{ required: true, message: '请输入地址' }],
+        required: true
+      },
+      {
+        label: '注册电话',
+        placeholder: '请输入注册电话',
+        formItemProp: 'tel',
+        rules: [
+          { required: true, message: '请输入联系电话' },
+          { validator: asyncValidator, message: '电话格式不正确' }
+        ],
+        required: true
+      },
+      {
+        label: '开户行',
+        placeholder: '请输入开户行',
+        formItemProp: 'bank'
+      },
+      {
+        label: '银行账户',
+        placeholder: '请输入银行账户',
+        formItemProp: 'account'
+      }
+    ]);
+
+    const formValue = reactive({
+      name: '',
+      num: '',
+      adress: '',
+      tel: '',
+      address: '',
+      bank: '',
+      account: ''
+    });
+
+    const submit = (valid: boolean, errors: []) => {
+      if (valid) {
+        console.log('success', formValue);
+      } else {
+        console.log('error submit!!', errors);
+      }
+    };
+
+    return {
+      translate,
+      data,
+      formValue,
+      submit,
+      asyncValidator
+    };
+  }
+}
+</script>
+```
+:::
+
+
+## Prop
+
+| 字段 | 说明 | 类型 | 默认值
+|----- | ----- | ----- | -----
+| data | 发票数据 | array | -
+| formValue | 表单数据对象(使用表单校验时,_必填_) | object | -
+| submit | 是否显示提交按钮 | boolean | true
+
+### data 数据结构
+
+可选属性如下:
+
+| 键名      | 说明                   | 类型                                    |
+|-----------|------------------------|-----------------------------------------|
+| label  | 表单项 label         | string                                 |
+| placeholder   | 输入框 placeholder           | string                                  |
+| formItemProp | 表单域 v-model 字段, 在使用表单校验功能的情况下,该属性是必填的 | string | -
+| rules | 校验规则,[可参考 FormItem Rule 数据结构](#/form) | array | []
+| required | 是否显示必填字段的标签旁边的红色星号 | Boolean | `false`
+
+### Events
+
+| 方法名            | 说明                                                               | 参数                | 返回值  |
+|-------------------|--------------------------------------------------------------------|---------------------|---------|
+| onSubmit            | 提交表单的方法                                             | -                   | Promise |

+ 25 - 0
src/packages/__VUE/invoice/index.scss

@@ -0,0 +1,25 @@
+.nut-theme-dark {
+  .nut-invoice {
+    .nut-invoice__submit {
+      background: $dark-background2;
+    }
+  }
+}
+
+.nut-invoice {
+  width: 100%;
+  position: relative;
+  &__submit {
+    position: fixed;
+    bottom: 0;
+    width: 100%;
+    padding: $invoice-padding;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background: #fff;
+    box-sizing: border-box;
+    bottom: constant(safe-area-inset-bottom);
+    bottom: env(safe-area-inset-bottom);
+  }
+}

+ 108 - 0
src/packages/__VUE/invoice/index.taro.vue

@@ -0,0 +1,108 @@
+<template>
+  <view :class="classes">
+    <nut-form :model-value="formValue" ref="formRef">
+      <nut-form-item
+        v-for="(item, index) of list"
+        :key="index"
+        :label="item.label"
+        :required="item.required"
+        :rules="item.rules"
+        :prop="item.formItemProp"
+      >
+        <input
+          class="nut-input-text"
+          :placeholder="item.placeholder"
+          v-model="formValue[item.formItemProp]"
+          type="text"
+        />
+      </nut-form-item>
+    </nut-form>
+    <div v-if="submit" class="nut-invoice__submit">
+      <nut-button type="primary" block @click="submit">提交审批</nut-button>
+    </div>
+  </view>
+</template>
+<script lang="ts">
+import { reactive, toRefs, computed, ref, onMounted, watch, PropType } from 'vue';
+import { createComponent } from '@/packages/utils/create';
+const { componentName, create } = createComponent('invoice');
+export default create({
+  props: {
+    data: {
+      type: Array,
+      default: () => []
+    },
+    required: {
+      type: Boolean,
+      default: false
+    },
+    formValue: {
+      type: Object,
+      default: {}
+    },
+    rules: {
+      type: Array as PropType<import('./types').FormItemRule[]>,
+      default: () => {
+        return [];
+      }
+    },
+    formItemProp: {
+      type: String,
+      default: ''
+    },
+    submit: {
+      type: Boolean,
+      default: true
+    }
+  },
+  emits: ['onSubmit', 'scroll-bottom'],
+
+  setup(props, { emit }) {
+    const formRef = ref();
+
+    const list: any = ref([]);
+
+    const state = reactive({
+      // list: []
+    });
+
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      console.log('prefixCls', prefixCls);
+      return {
+        [prefixCls]: true
+      };
+    });
+
+    onMounted(() => {
+      init();
+    });
+
+    const init = () => {
+      list.value = props.data;
+    };
+
+    const submit = () => {
+      console.log('11');
+      formRef.value.validate().then(({ valid, errors }: any) => {
+        console.log('22', valid, errors);
+        emit('onSubmit', valid, errors);
+      });
+    };
+
+    watch(
+      () => props.data,
+      () => init(),
+      { deep: true }
+    );
+
+    return {
+      ...toRefs(state),
+      classes,
+      formRef,
+      list,
+      submit
+    };
+  }
+});
+</script>

+ 108 - 0
src/packages/__VUE/invoice/index.vue

@@ -0,0 +1,108 @@
+<template>
+  <view :class="classes">
+    <nut-form :model-value="formValue" ref="formRef">
+      <nut-form-item
+        v-for="(item, index) of list"
+        :key="index"
+        :label="item.label"
+        :required="item.required"
+        :rules="item.rules"
+        :prop="item.formItemProp"
+      >
+        <input
+          class="nut-input-text"
+          :placeholder="item.placeholder"
+          v-model="formValue[item.formItemProp]"
+          type="text"
+        />
+      </nut-form-item>
+    </nut-form>
+    <div v-if="submit" class="nut-invoice__submit">
+      <nut-button type="primary" block @click="submit">提交审批</nut-button>
+    </div>
+  </view>
+</template>
+<script lang="ts">
+import { reactive, toRefs, computed, ref, onMounted, watch, PropType } from 'vue';
+import { createComponent } from '@/packages/utils/create';
+const { componentName, create } = createComponent('invoice');
+export default create({
+  props: {
+    data: {
+      type: Array,
+      default: () => []
+    },
+    required: {
+      type: Boolean,
+      default: false
+    },
+    formValue: {
+      type: Object,
+      default: {}
+    },
+    rules: {
+      type: Array as PropType<import('./types').FormItemRule[]>,
+      default: () => {
+        return [];
+      }
+    },
+    formItemProp: {
+      type: String,
+      default: ''
+    },
+    submit: {
+      type: Boolean,
+      default: true
+    }
+  },
+  emits: ['onSubmit', 'scroll-bottom'],
+
+  setup(props, { emit }) {
+    const formRef = ref();
+
+    const list: any = ref([]);
+
+    const state = reactive({
+      // list: []
+    });
+
+    const classes = computed(() => {
+      const prefixCls = componentName;
+      console.log('prefixCls', prefixCls);
+      return {
+        [prefixCls]: true
+      };
+    });
+
+    onMounted(() => {
+      init();
+    });
+
+    const init = () => {
+      list.value = props.data;
+    };
+
+    const submit = () => {
+      console.log('11');
+      formRef.value.validate().then(({ valid, errors }: any) => {
+        console.log('22', valid, errors);
+        emit('onSubmit', valid, errors);
+      });
+    };
+
+    watch(
+      () => props.data,
+      () => init(),
+      { deep: true }
+    );
+
+    return {
+      ...toRefs(state),
+      classes,
+      formRef,
+      list,
+      submit
+    };
+  }
+});
+</script>

+ 6 - 0
src/packages/__VUE/invoice/types.ts

@@ -0,0 +1,6 @@
+export class FormItemRule {
+  regex?: RegExp;
+  required?: boolean;
+  message!: string;
+  validator?: (value: any) => boolean | string | Promise<boolean | string>;
+}

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

@@ -893,5 +893,8 @@ $ellipsis-expand-collapse-color: #3460fa !default;
 // WaterMark
 $watermark-z-index: 2000 !default;
 
+// invoice
+$invoice-padding: 10px 10px 20px !default;
+
 @import './mixins/index';
 @import './animation/index';

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

@@ -799,5 +799,8 @@ $ellipsis-expand-collapse-color: #3460fa !default;
 // WaterMark
 $watermark-z-index: 2000 !default;
 
+// invoice
+$invoice-padding: 10px 10px 20px !default;
+
 @import './mixins/index';
 @import './animation/index';

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

@@ -824,5 +824,8 @@ $ellipsis-expand-collapse-color: #3460fa !default;
 // WaterMark
 $watermark-z-index: 2000 !default;
 
+// invoice
+$invoice-padding: 10px 10px 20px !default;
+
 @import './mixins/index';
 @import './animation/index';

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

@@ -102,7 +102,8 @@ const subPackages = [
       'pages/ecard/index',
       'pages/addresslist/index',
       'pages/category/index',
-      'pages/comment/index'
+      'pages/comment/index',
+      'pages/invoice/index'
     ]
   }
 ];

+ 4 - 0
src/sites/mobile-taro/vue/src/business/pages/invoice/index.config.ts

@@ -0,0 +1,4 @@
+export default {
+  navigationBarTitleText: 'Invoice',
+  disableScroll: true
+};

+ 98 - 0
src/sites/mobile-taro/vue/src/business/pages/invoice/index.vue

@@ -0,0 +1,98 @@
+<template>
+  <div class="demo full">
+    <h2>默认用法</h2>
+    <nut-invoice :data="data" :formValue="formValue" @onSubmit="submit"></nut-invoice>
+  </div>
+</template>
+
+<script lang="ts">
+import { ref, reactive } from 'vue';
+
+export default {
+  setup() {
+    const formValue = reactive({
+      name: '',
+      num: '',
+      adress: '',
+      tel: '',
+      address: '',
+      bank: '',
+      account: ''
+    });
+
+    // Promise 异步校验
+    const asyncValidator = (val: string) => {
+      return new Promise((resolve) => {
+        console.log('模拟异步验证中...');
+        setTimeout(() => {
+          resolve(/^400(-?)[0-9]{7}$|^1\d{10}$|^0[0-9]{2,3}-[0-9]{7,8}$/.test(val));
+        }, 1000);
+      });
+    };
+
+    let data: any = ref([
+      {
+        label: '发票抬头',
+        placeholder: '请输入发票抬头',
+        formItemProp: 'name',
+        rules: [{ required: true, message: '请输入发票抬头' }],
+        required: true
+      },
+      {
+        label: '纳税人识别号',
+        placeholder: '请输入纳税人识别号',
+        formItemProp: 'num',
+        rules: [{ message: '请输入纳税人识别号' }]
+      },
+      {
+        label: '注册地址',
+        placeholder: '请输入注册地址',
+        formItemProp: 'adress',
+        rules: [{ required: true, message: '请输入地址' }],
+        required: true
+      },
+      {
+        label: '注册电话',
+        placeholder: '请输入注册电话',
+        formItemProp: 'tel',
+        rules: [
+          { required: true, message: '请输入联系电话' },
+          { validator: asyncValidator, message: '电话格式不正确' }
+        ],
+        required: true
+      },
+      {
+        label: '开户行',
+        placeholder: '请输入开户行',
+        formItemProp: 'bank'
+      },
+      {
+        label: '银行账户',
+        placeholder: '请输入银行账户',
+        formItemProp: 'account'
+      }
+    ]);
+
+    const submit = (valid: boolean, errors: []) => {
+      if (valid) {
+        console.log('success', formValue);
+      } else {
+        console.log('error submit!!', errors);
+      }
+    };
+
+    return {
+      data,
+      formValue,
+      submit,
+      asyncValidator
+    };
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.nut-button {
+  margin-right: 10px;
+}
+</style>