未验证 提交 d40bdc3c 编写于 作者: A ailululu 提交者: GitHub

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

上级 fdb47ba0
......@@ -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
}
]
}
......
<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>
# 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
# 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 |
\ No newline at end of file
.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);
}
}
<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>
<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>
export class FormItemRule {
regex?: RegExp;
required?: boolean;
message!: string;
validator?: (value: any) => boolean | string | Promise<boolean | string>;
}
......@@ -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';
......@@ -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';
......@@ -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';
......@@ -102,7 +102,8 @@ const subPackages = [
'pages/ecard/index',
'pages/addresslist/index',
'pages/category/index',
'pages/comment/index'
'pages/comment/index',
'pages/invoice/index'
]
}
];
......
export default {
navigationBarTitleText: 'Invoice',
disableScroll: true
};
<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>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册