diff --git a/components/index.js b/components/index.js
index 7c6cc7313..cfb3b4429 100644
--- a/components/index.js
+++ b/components/index.js
@@ -137,6 +137,8 @@ import { default as ConfigProvider } from './config-provider';
import { default as Empty } from './empty';
+import { default as Result } from './result';
+
const components = [
Base,
Affix,
@@ -195,6 +197,7 @@ const components = [
Comment,
ConfigProvider,
Empty,
+ Result,
];
const install = function(Vue) {
@@ -279,6 +282,7 @@ export {
Comment,
ConfigProvider,
Empty,
+ Result,
};
export default {
diff --git a/components/result/__tests__/__snapshots__/demo.test.js.snap b/components/result/__tests__/__snapshots__/demo.test.js.snap
new file mode 100644
index 000000000..01b14d639
--- /dev/null
+++ b/components/result/__tests__/__snapshots__/demo.test.js.snap
@@ -0,0 +1,289 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders ./components/result/demo/403.md correctly 1`] = `
+
+
+
403
+
Sorry, you are not authorized to access this page.
+
+
+`;
+
+exports[`renders ./components/result/demo/404.md correctly 1`] = `
+
+
+
404
+
Sorry, the page you visited does not exist.
+
+
+`;
+
+exports[`renders ./components/result/demo/500.md correctly 1`] = `
+
+
+
500
+
Sorry, the server is wrong.
+
+
+`;
+
+exports[`renders ./components/result/demo/customIcon.md correctly 1`] = `
+
+
+
Great, we have done all the operations!
+
+
+`;
+
+exports[`renders ./components/result/demo/error.md correctly 1`] = `
+
+
+
Submission Failed
+
Please check and modify the following information before resubmitting.
+
+
+
The content you submitted has the following error:
+
Your account has been frozen Thaw immediately >
+
Your account is not yet eligible to apply Apply Unlock >
+
+
+
+
+`;
+
+exports[`renders ./components/result/demo/info.md correctly 1`] = `
+
+
+
Your operation has been executed
+
+
+`;
+
+exports[`renders ./components/result/demo/success.md correctly 1`] = `
+
+
+
Successfully Purchased Cloud Server ECS!
+
Order number: 2017182818828182881 Cloud server configuration takes 1-5 minutes, please wait.
+
+
+`;
+
+exports[`renders ./components/result/demo/warning.md correctly 1`] = `
+
+
+
There are some problems with your operation.
+
+
+`;
diff --git a/components/result/__tests__/demo.test.js b/components/result/__tests__/demo.test.js
new file mode 100644
index 000000000..bb3506ef1
--- /dev/null
+++ b/components/result/__tests__/demo.test.js
@@ -0,0 +1,3 @@
+import demoTest from '../../../tests/shared/demoTest';
+
+demoTest('result');
diff --git a/components/result/__tests__/index.test.js b/components/result/__tests__/index.test.js
new file mode 100644
index 000000000..fff8d2530
--- /dev/null
+++ b/components/result/__tests__/index.test.js
@@ -0,0 +1,66 @@
+import { mount } from '@vue/test-utils';
+import Result from '../index';
+import Button from '../../button';
+
+describe('Result', () => {
+
+ it('🙂 successPercent should decide the progress status when it exists', () => {
+ const wrapper = mount({
+ render () {
+ return (
+ Go Console}
+ />
+ );
+ },
+ });
+ expect(wrapper.findAll('.anticon-check-circle')).toHaveLength(1);
+ });
+
+ it('🙂 different status, different class', () => {
+ const wrapper = mount(Result, { propsData: { status: 'warning' } });
+ expect(wrapper.findAll('.ant-result-warning')).toHaveLength(1);
+
+ wrapper.setProps({
+ status: 'error',
+ });
+
+ expect(wrapper.findAll('.ant-result-error')).toHaveLength(1);
+
+ wrapper.setProps({
+ status: '500',
+ });
+
+ expect(wrapper.findAll('.ant-result-500')).toHaveLength(1);
+ });
+
+ it('🙂 When status = 404, the icon is an image', () => {
+ const wrapper = mount({
+ render () {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-result-404 .ant-result-image')).toHaveLength(1);
+ });
+
+ it('🙂 When extra is undefined, the extra dom is undefined', () => {
+ const wrapper = mount({
+ render () {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-result-extra')).toHaveLength(0);
+ });
+
+ it('🙂 result should support className', () => {
+ const wrapper = mount({
+ render () {
+ return ;
+ },
+ });
+ expect(wrapper.findAll('.ant-result.my-result')).toHaveLength(1);
+ });
+});
diff --git a/components/result/demo/403.md b/components/result/demo/403.md
new file mode 100644
index 000000000..88d86d9f1
--- /dev/null
+++ b/components/result/demo/403.md
@@ -0,0 +1,31 @@
+
+#### 403
+你没有此页面的访问权限。
+
+
+
+#### 403
+you are not authorized to access this page.
+
+
+```tpl
+
+
+
+ Back Home
+
+
+
+
+```
diff --git a/components/result/demo/404.md b/components/result/demo/404.md
new file mode 100644
index 000000000..0a5d1177d
--- /dev/null
+++ b/components/result/demo/404.md
@@ -0,0 +1,31 @@
+
+#### 404
+此页面未找到。
+
+
+
+#### 404
+The page you visited does not exist.
+
+
+```tpl
+
+
+
+ Back Home
+
+
+
+
+```
diff --git a/components/result/demo/500.md b/components/result/demo/500.md
new file mode 100644
index 000000000..0658146b5
--- /dev/null
+++ b/components/result/demo/500.md
@@ -0,0 +1,31 @@
+
+#### 500
+服务器发生了错误。
+
+
+
+#### 500
+The server is wrong.
+
+
+```tpl
+
+
+
+ Back Home
+
+
+
+
+```
diff --git a/components/result/demo/customIcon.md b/components/result/demo/customIcon.md
new file mode 100644
index 000000000..dad2f3d5f
--- /dev/null
+++ b/components/result/demo/customIcon.md
@@ -0,0 +1,30 @@
+
+#### 自定义 icon
+自定义 icon。
+
+
+
+#### Custom icon
+Custom icon.
+
+
+```tpl
+
+
+
+
+
+
+ Next
+
+
+
+
+```
diff --git a/components/result/demo/error.md b/components/result/demo/error.md
new file mode 100644
index 000000000..5d440f7bb
--- /dev/null
+++ b/components/result/demo/error.md
@@ -0,0 +1,47 @@
+
+#### Error
+复杂的错误反馈。
+
+
+
+#### Error
+Complex error feedback.
+
+
+```tpl
+
+
+
+
+ Go Console
+
+
+ Buy Again
+
+
+
+
+
The content you submitted has the following error:
+
Your account has been frozen Thaw immediately >
+
Your account is not yet eligible to apply Apply Unlock >
+
+
+
+
+
+```
diff --git a/components/result/demo/index.vue b/components/result/demo/index.vue
new file mode 100644
index 000000000..fb87b832a
--- /dev/null
+++ b/components/result/demo/index.vue
@@ -0,0 +1,71 @@
+
diff --git a/components/result/demo/info.md b/components/result/demo/info.md
new file mode 100644
index 000000000..56ac34874
--- /dev/null
+++ b/components/result/demo/info.md
@@ -0,0 +1,29 @@
+
+#### Info
+展示处理结果。
+
+
+
+#### Info
+Show processing results.
+
+
+```tpl
+
+
+
+
+ Go Console
+
+
+
+
+
+```
diff --git a/components/result/demo/success.md b/components/result/demo/success.md
new file mode 100644
index 000000000..f11d77abe
--- /dev/null
+++ b/components/result/demo/success.md
@@ -0,0 +1,32 @@
+
+#### Success
+成功的结果。
+
+
+
+#### Success
+Show successful results.
+
+
+```tpl
+
+
+
+ Go Console
+ Buy Again
+
+
+
+
+```
diff --git a/components/result/demo/warning.md b/components/result/demo/warning.md
new file mode 100644
index 000000000..7ebac475b
--- /dev/null
+++ b/components/result/demo/warning.md
@@ -0,0 +1,27 @@
+
+#### Warning
+警告类型的结果。
+
+
+
+#### Warning
+The result of the warning.
+
+
+```tpl
+
+
+
+ Go Console
+
+
+
+
+```
diff --git a/components/result/index.en-US.md b/components/result/index.en-US.md
new file mode 100644
index 000000000..e86df6f6e
--- /dev/null
+++ b/components/result/index.en-US.md
@@ -0,0 +1,9 @@
+## API
+
+| Property | Description | Type | Default |
+| -------- | ------------------------------------- | ----------------------------------------------------------------- | ------- |
+| title | title string | string \| VNode \| v-slot:title | - |
+| subTitle | subTitle string | string \| VNode \| v-slot:subTitle | - |
+| status | result status,decide icons and colors | `'success' | 'error' | 'info' | 'warning'| '404' | '403' | '500'` | 'info' |
+| icon | custom back icon | v-slot:icon | - |
+| extra | operating area | v-slot:extra | - |
diff --git a/components/result/index.jsx b/components/result/index.jsx
new file mode 100644
index 000000000..b53f0072c
--- /dev/null
+++ b/components/result/index.jsx
@@ -0,0 +1,94 @@
+import PropTypes from '../_util/vue-types';
+import { getOptionProps, getComponentFromProp } from '../_util/props-util';
+import { ConfigConsumerProps } from '../config-provider';
+import Icon from '../icon';
+import Base from '../base';
+import noFound from './noFound';
+import serverError from './serverError';
+import unauthorized from './unauthorized';
+
+export const IconMap = {
+ success: 'check-circle',
+ error: 'close-circle',
+ info: 'exclamation-circle',
+ warning: 'warning',
+};
+
+export const ExceptionMap = {
+ '404': noFound,
+ '500': serverError,
+ '403': unauthorized,
+};
+
+// ExceptionImageMap keys
+const ExceptionStatus = Object.keys(ExceptionMap);
+
+export const ResultProps = {
+ prefixCls: PropTypes.string,
+ icon: PropTypes.any,
+ status: PropTypes.oneOf(['success', 'error', 'info', 'warning', '404', '403', '500']).def('info'),
+ title: PropTypes.any,
+ subTitle: PropTypes.any,
+ extra: PropTypes.any,
+};
+
+const renderIcon = (h, prefixCls, { status, icon }) => {
+ if (ExceptionStatus.includes(status)) {
+ const SVGComponent = ExceptionMap[status];
+ return (
+
+
+
+ );
+ }
+ // prop `icon` require slot or VNode
+ const iconString = IconMap[status];
+ const iconNode = icon || ;
+ return {iconNode}
;
+};
+
+const renderExtra = (h, prefixCls, extra) => extra && ;
+
+const Result = {
+ name: 'AResult',
+ props: ResultProps,
+ inject: {
+ configProvider: { default: () => ConfigConsumerProps },
+ },
+ render(h) {
+ const {
+ prefixCls: customizePrefixCls,
+ status,
+ ...restProps
+ } = this;
+ const getPrefixCls = this.configProvider.getPrefixCls;
+ const prefixCls = getPrefixCls('result', customizePrefixCls);
+
+ const title = getComponentFromProp(this, 'title');
+ const subTitle = getComponentFromProp(this, 'subTitle');
+ const icon = getComponentFromProp(this, 'icon');
+ const extra = getComponentFromProp(this, 'extra');
+
+ return (
+
+ {renderIcon(h, prefixCls, { status, icon })}
+
{title}
+ {subTitle &&
{subTitle}
}
+ {this.$slots.default &&
{this.$slots.default}
}
+ {renderExtra(h, prefixCls, extra)}
+
+ );
+ },
+};
+
+/* add resource */
+Result.PRESENTED_IMAGE_403 = ExceptionMap[403];
+Result.PRESENTED_IMAGE_404 = ExceptionMap[404];
+Result.PRESENTED_IMAGE_500 = ExceptionMap[500];
+
+/* istanbul ignore next */
+Result.install = function(Vue) {
+ Vue.use(Base);
+ Vue.component(Result.name, Result);
+};
+export default Result;
diff --git a/components/result/index.zh-CN.md b/components/result/index.zh-CN.md
new file mode 100644
index 000000000..15d02eb28
--- /dev/null
+++ b/components/result/index.zh-CN.md
@@ -0,0 +1,9 @@
+## API
+
+| 参数 | 说明 | 类型 | 默认值 |
+| -------- | ------------------------- | ----------------------------------------------------------------- | ------ |
+| title | title 文字 | string \| VNode \| v-slot:title | - |
+| subTitle | subTitle 文字 | string \| VNode \| v-slot:subTitle | - |
+| status | 结果的状态,决定图标和颜色 | `'success' | 'error' | 'info' | 'warning'| '404' | '403' | '500'` | 'info' |
+| icon | 自定义 icon | v-slot:icon | - |
+| extra | 操作区 | v-slot:extra | - |
diff --git a/components/result/noFound.jsx b/components/result/noFound.jsx
new file mode 100644
index 000000000..9f352ed89
--- /dev/null
+++ b/components/result/noFound.jsx
@@ -0,0 +1,289 @@
+const NoFound = {
+ functional: true,
+ render() {
+ return(
+
+ );
+ },
+};
+
+export default NoFound;
diff --git a/components/result/serverError.jsx b/components/result/serverError.jsx
new file mode 100644
index 000000000..986d03372
--- /dev/null
+++ b/components/result/serverError.jsx
@@ -0,0 +1,334 @@
+const ServerError = {
+ functional: true,
+ render() {
+ return (
+
+ );
+ },
+};
+
+export default ServerError;
diff --git a/components/result/style/index.js b/components/result/style/index.js
new file mode 100644
index 000000000..3a3ab0de5
--- /dev/null
+++ b/components/result/style/index.js
@@ -0,0 +1,2 @@
+import '../../style/index.less';
+import './index.less';
diff --git a/components/result/style/index.less b/components/result/style/index.less
new file mode 100644
index 000000000..5ebf40dcf
--- /dev/null
+++ b/components/result/style/index.less
@@ -0,0 +1,71 @@
+@import '../../style/themes/default';
+@import '../../style/mixins/index';
+
+@result-prefix-cls: ~'@{ant-prefix}-result';
+
+.@{result-prefix-cls} {
+ padding: 48px 32px;
+ // status color
+ &-success &-icon > .anticon {
+ color: @success-color;
+ }
+
+ &-error &-icon > .anticon {
+ color: @error-color;
+ }
+
+ &-info &-icon > .anticon {
+ color: @info-color;
+ }
+
+ &-warning &-icon > .anticon {
+ color: @warning-color;
+ }
+
+ // Exception Status image
+ &-image {
+ width: 250px;
+ height: 295px;
+ margin: auto;
+ }
+
+ &-icon {
+ margin-bottom: 24px;
+ text-align: center;
+
+ > .anticon {
+ font-size: 72px;
+ }
+ }
+
+ &-title {
+ color: @heading-color;
+ font-size: 24px;
+ line-height: 1.8;
+ text-align: center;
+ }
+
+ &-subtitle {
+ color: @text-color-secondary;
+ font-size: 14px;
+ line-height: 1.6;
+ text-align: center;
+ }
+
+ &-extra {
+ margin-top: 32px;
+ text-align: center;
+ > * {
+ margin-right: 8px;
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ &-content {
+ margin-top: 24px;
+ padding: 24px 40px;
+ background-color: @background-color-light;
+ }
+}
diff --git a/components/result/unauthorized.jsx b/components/result/unauthorized.jsx
new file mode 100644
index 000000000..9fd2f4ac5
--- /dev/null
+++ b/components/result/unauthorized.jsx
@@ -0,0 +1,283 @@
+const Unauthorized = {
+ functional: true,
+ render() {
+ return (
+
+ );
+ },
+};
+
+export default Unauthorized;
diff --git a/site/components.js b/site/components.js
index 4a4df60ec..5fd855ddf 100644
--- a/site/components.js
+++ b/site/components.js
@@ -61,6 +61,7 @@ import {
ConfigProvider,
Empty,
Base,
+ Result,
} from 'ant-design-vue';
Vue.prototype.$message = message;
@@ -130,6 +131,7 @@ Vue.use(Skeleton);
Vue.use(Comment);
Vue.use(ConfigProvider);
Vue.use(Empty);
+Vue.use(Result);
/* v1.1.2 registration methods */
// Vue.component(Affix.name, Affix) // a-affix
diff --git a/site/demo.js b/site/demo.js
index 654774385..636ccf3bb 100644
--- a/site/demo.js
+++ b/site/demo.js
@@ -174,6 +174,12 @@ export default {
type: 'Feedback',
title: 'Spin',
},
+ result: {
+ category: 'Components',
+ subtitle: '结果',
+ type: 'Feedback',
+ title: 'Result',
+ },
switch: {
category: 'Components',
subtitle: '开关',
diff --git a/site/demoRoutes.js b/site/demoRoutes.js
index b23c6d993..5aa0e8445 100644
--- a/site/demoRoutes.js
+++ b/site/demoRoutes.js
@@ -455,4 +455,12 @@ export default [
path: 'empty-cn',
component: () => import('../components/empty/demo/index.vue'),
},
+ {
+ path: 'result',
+ component: () => import('../components/result/demo/index.vue'),
+ },
+ {
+ path: 'result-cn',
+ component: () => import('../components/result/demo/index.vue'),
+ },
];
diff --git a/types/ant-design-vue.d.ts b/types/ant-design-vue.d.ts
index 97f69d428..5b3deaf84 100644
--- a/types/ant-design-vue.d.ts
+++ b/types/ant-design-vue.d.ts
@@ -61,6 +61,7 @@ import { TimePicker } from './time-picker';
import { Timeline } from './timeline/timeline';
import { Tooltip } from './tootip/tooltip';
import { Upload } from './upload';
+import { Result } from './result';
/**
* Install all ant-design-vue components into Vue.
@@ -129,4 +130,5 @@ export {
Upload,
Drawer,
Skeleton,
+ Result,
};
diff --git a/types/result.d.ts b/types/result.d.ts
new file mode 100644
index 000000000..bf6effa62
--- /dev/null
+++ b/types/result.d.ts
@@ -0,0 +1,38 @@
+import { AntdComponent } from './component';
+
+export declare class Result extends AntdComponent {
+ /**
+ * result title
+ * @type string
+ */
+ title: any;
+
+ /**
+ * result sub title
+ *
+ * @type string
+ */
+ subTitle: any;
+
+ /**
+ * result status,decide icons and colors
+ * enum of 'success' | 'error' | 'info' | 'warning'| '404' | '403' | '500'` | 'info'
+ *
+ * @default 'info'
+ * @type string
+ */
+ status: string;
+
+ /**
+ * custom back icon
+ * @type any v-slot
+ */
+ icon: any;
+
+ /**
+ * operating area
+ * @type any v-slot
+ */
+ extra: any;
+
+}