[improvement] rename packages dir to src (#3659)
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('basicUsage')">
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
:button-text="$t('submit')"
|
||||
@submit="onClickButton"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('disabled')">
|
||||
<van-submit-bar
|
||||
disabled
|
||||
:price="3050"
|
||||
:button-text="$t('submit')"
|
||||
:tip="$t('tip1')"
|
||||
tip-icon="info-o"
|
||||
@submit="onClickButton"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('loadingStatus')">
|
||||
<van-submit-bar
|
||||
loading
|
||||
:price="3050"
|
||||
:button-text="$t('submit')"
|
||||
@submit="onClickButton"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('advancedUsage')">
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
:button-text="$t('submit')"
|
||||
@submit="onClickButton"
|
||||
>
|
||||
<van-checkbox v-model="checked">{{ $t('check') }}</van-checkbox>
|
||||
<template #tip>
|
||||
{{ $t('tip2') }}
|
||||
<span
|
||||
class="edit-address"
|
||||
@click="onClickLink"
|
||||
>
|
||||
{{ $t('tip3') }}
|
||||
</span>
|
||||
</template>
|
||||
</van-submit-bar>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
submit: '提交订单',
|
||||
tip1: '你的收货地址不支持同城送, 我们已为你推荐快递',
|
||||
tip2: '你的收货地址不支持同城送, ',
|
||||
tip3: '修改地址',
|
||||
check: '全选',
|
||||
clickButton: '点击按钮',
|
||||
clickLink: '修改地址'
|
||||
},
|
||||
'en-US': {
|
||||
submit: 'Submit',
|
||||
tip1: 'Some tips',
|
||||
tip2: 'Some tips, ',
|
||||
tip3: 'Link',
|
||||
check: 'Label',
|
||||
clickButton: 'Click button',
|
||||
clickLink: 'Click Link'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
checked: true
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickButton() {
|
||||
this.$toast(this.$t('clickButton'));
|
||||
},
|
||||
onClickLink() {
|
||||
this.$toast(this.$t('clickLink'));
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import '../../style/var';
|
||||
|
||||
.demo-submit-bar {
|
||||
.van-submit-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.edit-address {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
.van-checkbox {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,99 @@
|
||||
# SubmitBar
|
||||
|
||||
### Install
|
||||
|
||||
``` javascript
|
||||
import { SubmitBar } from 'vant';
|
||||
|
||||
Vue.use(SubmitBar);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
button-text="Submit"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
`submit` event will not triggerd when disabled.
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
disabled
|
||||
:price="3050"
|
||||
button-text="Submit"
|
||||
tip="Some tips"
|
||||
tip-icon="info-o"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### Loading
|
||||
|
||||
`submit` event will not triggerd when loading.
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
loading
|
||||
:price="3050"
|
||||
button-text="Submit"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
|
||||
Use slot to add custom contents.
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
button-text="Submit"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<van-checkbox v-model="checked">Check</van-checkbox>
|
||||
<span slot="tip">
|
||||
Some tips, <span @click="onClickEditAddress">Link</span>
|
||||
</span>
|
||||
</van-submit-bar>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|
|
||||
| price | Price | `Number` | - |
|
||||
| label | Price left label | `String` | `Total:` |
|
||||
| suffix-label | Price right label | `String` | - |
|
||||
| button-text | Button text | `String` | - |
|
||||
| button-type | Button type | `String` | `danger` |
|
||||
| tip | Tip | `String` | - |
|
||||
| tip-icon | Icon | `String` | - |
|
||||
| disabled | Whether to disable button | `Boolean` | `false` |
|
||||
| loading | Whether to show loading icon | `Boolean` | `false` |
|
||||
| currency | Currency symbol | `String` | `¥` |
|
||||
| decimal-length | Number of digits to appear after the decimal point | `Number` | `2` |
|
||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation, to enable those features use `viewport-fit=cover` in the `viewport` meta tag | `Boolean` | `false` |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
|------|------|------|
|
||||
| submit | Triggerd when click submit button | - |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
|------|------|
|
||||
| default | Custom left content |
|
||||
| top | Custom top content |
|
||||
| tip | Custom tips |
|
||||
@@ -0,0 +1,71 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-submit-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: @submit-bar-z-index;
|
||||
width: 100%;
|
||||
background-color: @submit-bar-background-color;
|
||||
user-select: none;
|
||||
|
||||
&__tip {
|
||||
padding: @submit-bar-tip-padding;
|
||||
color: @submit-bar-tip-color;
|
||||
font-size: @submit-bar-tip-font-size;
|
||||
line-height: @submit-bar-tip-line-height;
|
||||
background-color: @submit-bar-tip-background-color;
|
||||
}
|
||||
|
||||
&__tip-icon {
|
||||
min-width: @submit-bar-tip-icon-size * 1.5;
|
||||
font-size: @submit-bar-tip-icon-size;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__tip-text {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: @submit-bar-height;
|
||||
font-size: @submit-bar-text-font-size;
|
||||
}
|
||||
|
||||
&__text {
|
||||
flex: 1;
|
||||
padding-right: 12px;
|
||||
color: @submit-bar-text-color;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
&__suffix-label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
&__price {
|
||||
color: @submit-bar-price-color;
|
||||
font-size: @submit-bar-price-font-size;
|
||||
|
||||
&::first-letter {
|
||||
font-size: @submit-bar-currency-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
width: @submit-bar-button-width;
|
||||
}
|
||||
|
||||
&--safe-area-inset-bottom {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import { createNamespace } from '../utils';
|
||||
import { emit, inherit } from '../utils/functional';
|
||||
import Button, { ButtonType } from '../button';
|
||||
import Icon from '../icon';
|
||||
|
||||
// Types
|
||||
import { CreateElement, RenderContext } from 'vue/types';
|
||||
import { ScopedSlot, DefaultSlots } from '../utils/types';
|
||||
|
||||
export type SubmitBarProps = {
|
||||
tip?: string;
|
||||
tipIcon?: string;
|
||||
label?: string;
|
||||
price?: number;
|
||||
loading?: boolean;
|
||||
currency: string;
|
||||
disabled?: boolean;
|
||||
buttonType: ButtonType;
|
||||
buttonText?: string;
|
||||
suffixLabel?: string;
|
||||
decimalLength: number;
|
||||
safeAreaInsetBottom?: boolean;
|
||||
};
|
||||
|
||||
export type SubmitBarSlots = DefaultSlots & {
|
||||
top?: ScopedSlot;
|
||||
tip?: ScopedSlot;
|
||||
};
|
||||
|
||||
const [createComponent, bem, t] = createNamespace('submit-bar');
|
||||
|
||||
function SubmitBar(
|
||||
h: CreateElement,
|
||||
props: SubmitBarProps,
|
||||
slots: SubmitBarSlots,
|
||||
ctx: RenderContext<SubmitBarProps>
|
||||
) {
|
||||
const { tip, price, tipIcon } = props;
|
||||
|
||||
function Text() {
|
||||
if (typeof price === 'number') {
|
||||
const priceText = `${props.currency} ${(price / 100).toFixed(props.decimalLength)}`;
|
||||
|
||||
return (
|
||||
<div class={bem('text')}>
|
||||
<span>{props.label || t('label')}</span>
|
||||
<span class={bem('price')}>{priceText}</span>
|
||||
{props.suffixLabel && (
|
||||
<span class={bem('suffix-label')}>{props.suffixLabel}</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function Tip() {
|
||||
if (slots.tip || tip) {
|
||||
return (
|
||||
<div class={bem('tip')}>
|
||||
{tipIcon && <Icon class={bem('tip-icon')} name={tipIcon} />}
|
||||
{tip && <span class={bem('tip-text')}>{tip}</span>}
|
||||
{slots.tip && slots.tip()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={bem({ 'safe-area-inset-bottom': props.safeAreaInsetBottom })}
|
||||
{...inherit(ctx)}
|
||||
>
|
||||
{slots.top && slots.top()}
|
||||
{Tip()}
|
||||
<div class={bem('bar')}>
|
||||
{slots.default && slots.default()}
|
||||
{Text()}
|
||||
<Button
|
||||
square
|
||||
size="large"
|
||||
class={bem('button')}
|
||||
type={props.buttonType}
|
||||
loading={props.loading}
|
||||
disabled={props.disabled}
|
||||
text={props.loading ? '' : props.buttonText}
|
||||
onClick={() => {
|
||||
emit(ctx, 'submit');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
SubmitBar.props = {
|
||||
tip: String,
|
||||
tipIcon: String,
|
||||
label: String,
|
||||
loading: Boolean,
|
||||
disabled: Boolean,
|
||||
buttonText: String,
|
||||
suffixLabel: String,
|
||||
safeAreaInsetBottom: Boolean,
|
||||
price: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
decimalLength: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
default: '¥'
|
||||
},
|
||||
buttonType: {
|
||||
type: String,
|
||||
default: 'danger'
|
||||
}
|
||||
};
|
||||
|
||||
export default createComponent<SubmitBarProps, {}, SubmitBarSlots>(SubmitBar);
|
||||
@@ -0,0 +1,47 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 30.50</span></div><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"><span class="van-button__text">提交订单</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__tip"><i class="van-icon van-icon-info-o van-submit-bar__tip-icon">
|
||||
<!----></i><span class="van-submit-bar__tip-text">你的收货地址不支持同城送, 我们已为你推荐快递</span></div>
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 30.50</span></div><button disabled="disabled" class="van-button van-button--danger van-button--large van-button--disabled van-button--square van-submit-bar__button"><span class="van-button__text">提交订单</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 30.50</span></div><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button">
|
||||
<div class="van-loading van-loading--circular van-button__loading"><span class="van-loading__spinner van-loading__spinner--circular" style="width: 20px; height: 20px;"><svg viewBox="25 25 50 50" class="van-loading__circular"><circle cx="50" cy="50" r="20" fill="none"></circle></svg></span></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__tip">
|
||||
你的收货地址不支持同城送,
|
||||
<span class="edit-address">
|
||||
修改地址
|
||||
</span></div>
|
||||
<div class="van-submit-bar__bar">
|
||||
<div role="checkbox" tabindex="0" aria-checked="true" class="van-checkbox">
|
||||
<div class="van-checkbox__icon van-checkbox__icon--round van-checkbox__icon--checked"><i class="van-icon van-icon-success">
|
||||
<!----></i></div><span class="van-checkbox__label">全选</span>
|
||||
</div>
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 30.50</span></div><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"><span class="van-button__text">提交订单</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,36 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`decimal-length prop 1`] = `
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 1.1</span></div><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`disable submit 1`] = `
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>合计:</span><span class="van-submit-bar__price">¥ 0.01</span></div><button disabled="disabled" class="van-button van-button--danger van-button--large van-button--disabled van-button--square van-submit-bar__button"></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`suffix-label prop 1`] = `
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar">
|
||||
<div class="van-submit-bar__text"><span>Label</span><span class="van-submit-bar__price">¥ 1.11</span><span class="van-submit-bar__suffix-label">Suffix Label</span></div><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"></button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`top slot 1`] = `
|
||||
<div class="van-submit-bar">top<div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"></button></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`without price 1`] = `
|
||||
<div class="van-submit-bar">
|
||||
<div class="van-submit-bar__bar"><button class="van-button van-button--danger van-button--large van-button--square van-submit-bar__button"></button></div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
||||
@@ -0,0 +1,87 @@
|
||||
import SubmitBar from '..';
|
||||
import { mount } from '../../../test/utils';
|
||||
|
||||
test('submit event', () => {
|
||||
const submit = jest.fn();
|
||||
const wrapper = mount(SubmitBar, {
|
||||
context: {
|
||||
props: {
|
||||
price: 1
|
||||
},
|
||||
on: { submit }
|
||||
}
|
||||
});
|
||||
|
||||
const button = wrapper.find('.van-button');
|
||||
button.trigger('click');
|
||||
expect(submit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('disable submit', () => {
|
||||
const submit = jest.fn();
|
||||
const wrapper = mount(SubmitBar, {
|
||||
context: {
|
||||
props: {
|
||||
price: 1,
|
||||
disabled: true
|
||||
},
|
||||
on: { submit }
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
// disabled
|
||||
const button = wrapper.find('.van-button');
|
||||
button.trigger('click');
|
||||
expect(submit).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test('without price', () => {
|
||||
const wrapper = mount(SubmitBar, {
|
||||
context: {
|
||||
props: {
|
||||
label: 'Label'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('top slot', () => {
|
||||
const wrapper = mount(SubmitBar, {
|
||||
scopedSlots: {
|
||||
top: () => 'top'
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('decimal-length prop', () => {
|
||||
const wrapper = mount(SubmitBar, {
|
||||
context: {
|
||||
props: {
|
||||
price: 111,
|
||||
decimalLength: 1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('suffix-label prop', () => {
|
||||
const wrapper = mount(SubmitBar, {
|
||||
context: {
|
||||
props: {
|
||||
price: 111,
|
||||
label: 'Label',
|
||||
suffixLabel: 'Suffix Label'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
# SubmitBar 提交订单栏
|
||||
|
||||
### 引入
|
||||
|
||||
``` javascript
|
||||
import { SubmitBar } from 'vant';
|
||||
|
||||
Vue.use(SubmitBar);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
button-text="提交订单"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### 禁用状态
|
||||
|
||||
禁用状态下不会触发`submit`事件
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
disabled
|
||||
:price="3050"
|
||||
button-text="提交订单"
|
||||
tip="你的收货地址不支持同城送, 我们已为你推荐快递"
|
||||
tip-icon="info-o"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### 加载状态
|
||||
|
||||
加载状态下不会触发`submit`事件
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
loading
|
||||
:price="3050"
|
||||
button-text="提交订单"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
|
||||
通过插槽插入自定义内容
|
||||
|
||||
```html
|
||||
<van-submit-bar
|
||||
:price="3050"
|
||||
button-text="提交订单"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<van-checkbox v-model="checked">全选</van-checkbox>
|
||||
<span slot="tip">
|
||||
你的收货地址不支持同城送, <span>修改地址</span>
|
||||
</span>
|
||||
</van-submit-bar>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| price | 价格(单位分) | `Number` | - | - |
|
||||
| label | 价格左侧文案 | `String` | `合计:` | - |
|
||||
| suffix-label | 价格右侧文案 | `String` | - | 2.0.0 |
|
||||
| button-text | 按钮文字 | `String` | - | - |
|
||||
| button-type | 按钮类型 | `String` | `danger` | - |
|
||||
| tip | 提示文案 | `String` | - | - |
|
||||
| tip-icon | 左侧图标名称或图片链接,可选值见 Icon 组件 | `String` | - | - |
|
||||
| disabled | 是否禁用按钮 | `Boolean` | `false` | - |
|
||||
| loading | 是否显示加载中的按钮 | `Boolean` | `false` | - |
|
||||
| currency | 货币符号 | `String` | `¥` | 1.0.6 |
|
||||
| decimal-length | 价格小数点后位数 | `Number` | `2` | 1.6.15 |
|
||||
| safe-area-inset-bottom | 是否开启 iPhone X 底部安全区适配,需要在 `viewport` meta 标签中设置 `viewport-fit=cover` | `Boolean` | `false` | 1.6.15 |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
|------|------|------|
|
||||
| submit | 按钮点击事件回调 | - |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
|------|------|
|
||||
| default | 自定义订单栏左侧内容 |
|
||||
| top | 自定义订单栏上方内容 |
|
||||
| tip | 提示文案中的额外操作和说明 |
|
||||
Reference in New Issue
Block a user