Parcourir la source

feat: list/article page

Sendya il y a 6 ans
Parent
commit
f9b375694f

+ 89 - 0
src/components/ArticleListContent/ArticleListContent.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="antd-pro-components-article-list-content-index-listContent">
+    <div class="description">
+      <slot>
+        {{ description }}
+      </slot>
+    </div>
+    <div class="extra">
+      <a-avatar :src="avatar" size="small" />
+      <a :href="href">{{ owner }}</a> 发布在 <a :href="href">{{ href }}</a>
+      <em>{{ updateAt | moment }}</em>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ArticleListContent',
+  props: {
+    prefixCls: {
+      type: String,
+      default: 'antd-pro-components-article-list-content-index-listContent'
+    },
+    description: {
+      type: String,
+      default: ''
+    },
+    owner: {
+      type: String,
+      required: true
+    },
+    avatar: {
+      type: String,
+      required: true
+    },
+    href: {
+      type: String,
+      required: true
+    },
+    updateAt: {
+      type: String,
+      required: true
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+@import '../index.less';
+
+.antd-pro-components-article-list-content-index-listContent {
+  .description {
+    max-width: 720px;
+    line-height: 22px;
+  }
+  .extra {
+    margin-top: 16px;
+    color: @text-color-secondary;
+    line-height: 22px;
+
+    & /deep/ .ant-avatar {
+      position: relative;
+      top: 1px;
+      width: 20px;
+      height: 20px;
+      margin-right: 8px;
+      vertical-align: top;
+    }
+
+    & > em {
+      margin-left: 16px;
+      color: @disabled-color;
+      font-style: normal;
+    }
+  }
+}
+
+@media screen and (max-width: @screen-xs) {
+  .antd-pro-components-article-list-content-index-listContent {
+    .extra {
+      & > em {
+        display: block;
+        margin-top: 8px;
+        margin-left: 0;
+      }
+    }
+  }
+}
+</style>

+ 3 - 0
src/components/ArticleListContent/index.js

@@ -0,0 +1,3 @@
+import ArticleListContent from './ArticleListContent'
+
+export default ArticleListContent

+ 122 - 0
src/components/StandardFormRow/StandardFormRow.vue

@@ -0,0 +1,122 @@
+<template>
+  <div :class="[prefixCls, lastCls, blockCls, gridCls]">
+    <div v-if="title" class="antd-pro-components-standard-form-row-index-label">
+      <span>{{ title }}</span>
+    </div>
+    <div class="antd-pro-components-standard-form-row-index-content">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+const classes = [
+  'antd-pro-components-standard-form-row-index-standardFormRowBlock',
+  'antd-pro-components-standard-form-row-index-standardFormRowGrid',
+  'antd-pro-components-standard-form-row-index-standardFormRowLast'
+]
+export default {
+  name: 'StandardFormRow',
+  props: {
+    prefixCls: {
+      type: String,
+      default: 'antd-pro-components-standard-form-row-index-standardFormRow'
+    },
+    title: {
+      type: String,
+      default: undefined
+    },
+    last: {
+      type: Boolean
+    },
+    block: {
+      type: Boolean
+    },
+    grid: {
+      type: Boolean
+    }
+  },
+  computed: {
+    lastCls () {
+      return this.last ? classes[2] : null
+    },
+    blockCls () {
+      return this.block ? classes[0] : null
+    },
+    gridCls () {
+      return this.grid ? classes[1] : null
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+@import '../index.less';
+
+.antd-pro-components-standard-form-row-index-standardFormRow {
+  display: flex;
+  margin-bottom: 16px;
+  padding-bottom: 16px;
+  border-bottom: 1px dashed @border-color-split;
+
+  /deep/ .ant-form-item {
+    margin-right: 24px;
+  }
+  /deep/ .ant-form-item-label label {
+    margin-right: 0;
+    color: @text-color;
+  }
+  /deep/ .ant-form-item-label,
+  .ant-form-item-control {
+    padding: 0;
+    line-height: 32px;
+  }
+
+  .antd-pro-components-standard-form-row-index-label {
+    flex: 0 0 auto;
+    margin-right: 24px;
+    color: @heading-color;
+    font-size: @font-size-base;
+    text-align: right;
+    & > span {
+      display: inline-block;
+      height: 32px;
+      line-height: 32px;
+      &::after {
+        content: ':';
+      }
+    }
+  }
+
+  .antd-pro-components-standard-form-row-index-content {
+    flex: 1 1 0;
+    /deep/ .ant-form-item:last-child {
+      margin-right: 0;
+    }
+  }
+
+  &.antd-pro-components-standard-form-row-index-standardFormRowLast {
+    margin-bottom: 0;
+    padding-bottom: 0;
+    border: none;
+  }
+
+  &.antd-pro-components-standard-form-row-index-standardFormRowBlock {
+    /deep/ .ant-form-item,
+    div.ant-form-item-control-wrapper {
+      display: block;
+    }
+  }
+
+  &.antd-pro-components-standard-form-row-index-standardFormRowGrid {
+      /deep/ .ant-form-item,
+      div.ant-form-item-control-wrapper {
+        display: block;
+      }
+      /deep/ .ant-form-item-label {
+        float: left;
+      }
+  }
+}
+
+</style>

+ 3 - 0
src/components/StandardFormRow/index.js

@@ -0,0 +1,3 @@
+import StandardFormRow from './StandardFormRow'
+
+export default StandardFormRow

+ 5 - 1
src/components/index.js

@@ -26,6 +26,8 @@ import Result from '@/components/Result'
 import IconSelector from '@/components/IconSelector'
 import TagSelect from '@/components/TagSelect'
 import ExceptionPage from '@/components/Exception'
+import StandardFormRow from '@/components/StandardFormRow'
+import ArticleListContent from '@/components/ArticleListContent'
 
 export {
   AvatarList,
@@ -54,5 +56,7 @@ export {
   Result,
   ExceptionPage,
   IconSelector,
-  TagSelect
+  TagSelect,
+  StandardFormRow,
+  ArticleListContent
 }

+ 1 - 0
src/mock/index.js

@@ -10,6 +10,7 @@ if (process.env.NODE_ENV !== 'production' || process.env.VUE_APP_PREVIEW === 'tr
   require('./services/manage')
   require('./services/other')
   require('./services/tagCloud')
+  require('./services/article')
 
   Mock.setup({
     timeout: 800 // setter delay time

+ 45 - 0
src/mock/services/article.js

@@ -0,0 +1,45 @@
+import Mock from 'mockjs2'
+import { builder } from '../util'
+
+const avatar = ['https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
+  'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png'
+]
+const owner = [
+  '付小小',
+  '吴加好',
+  '周星星',
+  '林东东',
+  '曲丽丽'
+]
+
+const content = '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。'
+const description = '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+const href = 'https://ant.design'
+
+const article = () => {
+  const data = []
+  for (let i = 0; i < 5; i++) {
+    const tmpKey = i + 1
+    const num = parseInt(Math.random() * (4 + 1), 10)
+    data.push({
+      id: tmpKey,
+      avatar: avatar[num],
+      owner: owner[num],
+      content: content,
+      star: Mock.mock('@integer(1, 999)'),
+      percent: Mock.mock('@integer(1, 999)'),
+      like: Mock.mock('@integer(1, 999)'),
+      message: Mock.mock('@integer(1, 999)'),
+      description: description,
+      href: href,
+      title: 'Alipay',
+      updatedAt: Mock.mock('@datetime')
+    })
+  }
+  return builder(data)
+}
+
+Mock.mock(/\/list\/article/, 'get', article)

+ 155 - 32
src/views/list/search/Article.vue

@@ -1,48 +1,167 @@
 <template>
-  <a-card :bordered="false" class="ant-pro-components-tag-select">
-    <a-form layout="inline">
-      <a-form-item label="所属类目">
-        <tag-select>
-          <tag-select-option value="Category1">类目一</tag-select-option>
-          <tag-select-option value="Category2">类目二</tag-select-option>
-          <tag-select-option value="Category3">类目三</tag-select-option>
-          <tag-select-option value="Category4">类目四</tag-select-option>
-          <tag-select-option value="Category5">类目五</tag-select-option>
-          <tag-select-option value="Category6">类目六</tag-select-option>
-          <tag-select-option value="Category7">类目七</tag-select-option>
-          <tag-select-option value="Category8">类目八</tag-select-option>
-          <tag-select-option value="Category9">类目九</tag-select-option>
-          <tag-select-option value="Category10">类目十</tag-select-option>
-        </tag-select>
-      </a-form-item>
-      <a-divider dashed />
-      <a-form-item label="owner">
-        <a-row>
-          <a-col :md="24">
-            <a-select style="max-width: 268px; width: 100%;" mode="multiple" :defaultValue="['a1', 'b2']" @change="handleChange" placeholder="Please select">
-              <a-select-option v-for="i in 25" :key="(i + 9).toString(36) + i">{{ (i + 9).toString(36) + i }}</a-select-option>
-            </a-select>
-            <a>只看自己的</a>
-          </a-col>
-        </a-row>
-      </a-form-item>
-    </a-form>
-
-  </a-card>
+  <div>
+    <a-card :bordered="false" class="ant-pro-components-tag-select">
+      <a-form :form="form" layout="inline">
+        <standard-form-row title="所属类目" block style="padding-bottom: 11px;">
+          <a-form-item>
+            <tag-select>
+              <tag-select-option value="Category1">类目一</tag-select-option>
+              <tag-select-option value="Category2">类目二</tag-select-option>
+              <tag-select-option value="Category3">类目三</tag-select-option>
+              <tag-select-option value="Category4">类目四</tag-select-option>
+              <tag-select-option value="Category5">类目五</tag-select-option>
+              <tag-select-option value="Category6">类目六</tag-select-option>
+              <tag-select-option value="Category7">类目七</tag-select-option>
+              <tag-select-option value="Category8">类目八</tag-select-option>
+              <tag-select-option value="Category9">类目九</tag-select-option>
+              <tag-select-option value="Category10">类目十</tag-select-option>
+            </tag-select>
+          </a-form-item>
+        </standard-form-row>
+
+        <standard-form-row title="owner" grid>
+          <a-row>
+            <a-col :md="24">
+              <a-form-item :wrapper-col="{ span: 24 }">
+                <a-select
+                  style="max-width: 268px; width: 100%;"
+                  mode="multiple"
+                  placeholder="选择 onwer"
+                  v-decorator="['owner']"
+                  @change="handleChange"
+                >
+                  <a-select-option v-for="item in owners" :key="item.id">{{ item.name }}</a-select-option>
+                </a-select>
+                <a class="list-articles-trigger" @click="setOwner">只看自己的</a>
+              </a-form-item>
+            </a-col>
+          </a-row>
+        </standard-form-row>
+
+        <standard-form-row title="其它选项" grid last>
+          <a-row :gutter="16">
+            <a-col :xs="24" :sm="24" :md="12" :lg="10" :xl="8">
+              <a-form-item label="活跃用户" :wrapper-col="{ xs: 24, sm: 24, md: 12 }">
+                <a-select placeholder="不限" style="max-width: 200px; width: 100%;">
+                  <a-select-option value="李三">李三</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :xs="24" :sm="24" :md="12" :lg="10" :xl="8">
+              <a-form-item label="好评度" :wrapper-col="{ xs: 24, sm: 24, md: 12 }">
+                <a-select placeholder="不限" style="max-width: 200px; width: 100%;">
+                  <a-select-option value="优秀">优秀</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+          </a-row>
+        </standard-form-row>
+      </a-form>
+    </a-card>
+
+    <a-card style="margin-top: 24px;" :bordered="false">
+      <a-list
+        size="large"
+        rowKey="id"
+        itemLayout="vertical"
+        :dataSource="data"
+      >
+        <a-list-item :key="item.id" slot="renderItem" slot-scope="item">
+          <template slot="actions">
+            <icon-text type="star-o" :text="item.star" />
+            <icon-text type="like-o" :text="item.like" />
+            <icon-text type="message" :text="item.message" />
+          </template>
+          <a-list-item-meta>
+            <a slot="title" href="https://vue.ant.design/">{{ item.title }}</a>
+            <template slot="description">
+              <span>
+                <a-tag>Ant Design</a-tag>
+                <a-tag>设计语言</a-tag>
+                <a-tag>蚂蚁金服</a-tag>
+              </span>
+            </template>
+          </a-list-item-meta>
+          <article-list-content :description="item.description" :owner="item.owner" :avatar="item.avatar" :href="item.href" :updateAt="item.updatedAt" />
+        </a-list-item>
+        <div slot="footer" v-if="data.length > 0" style="text-align: center; margin-top: 16px;">
+          <a-button @click="loadMore" :loading="loadingMore">加载更多</a-button>
+        </div>
+      </a-list>
+    </a-card>
+  </div>
 </template>
 
 <script>
-import { TagSelect } from '@/components'
+import { TagSelect, StandardFormRow, ArticleListContent } from '@/components'
+import IconText from './components/IconText'
 const TagSelectOption = TagSelect.Option
 
+const owners = [
+  {
+    id: 'wzj',
+    name: '我自己'
+  },
+  {
+    id: 'wjh',
+    name: '吴家豪'
+  },
+  {
+    id: 'zxx',
+    name: '周星星'
+  },
+  {
+    id: 'zly',
+    name: '赵丽颖'
+  },
+  {
+    id: 'ym',
+    name: '姚明'
+  }
+]
+
 export default {
   components: {
     TagSelect,
-    TagSelectOption
+    TagSelectOption,
+    StandardFormRow,
+    ArticleListContent,
+    IconText
+  },
+  data () {
+    return {
+      owners,
+      loadingMore: false,
+      data: [],
+      form: this.$form.createForm(this)
+    }
+  },
+  mounted () {
+    this.getList()
   },
   methods: {
     handleChange (value) {
       console.log(`selected ${value}`)
+    },
+    getList () {
+      this.$http.get('/list/article').then(res => {
+        console.log('res', res)
+        this.data = res.result
+      })
+    },
+    loadMore () {
+      this.loadingMore = true
+      this.$http.get('/list/article').then(res => {
+        this.data = this.data.concat(res.result)
+      }).finally(() => {
+        this.loadingMore = false
+      })
+    },
+    setOwner () {
+      const { form: { setFieldsValue } } = this
+      setFieldsValue({
+        owner: ['wzj']
+      })
     }
   }
 }
@@ -56,4 +175,8 @@ export default {
     font-size: 14px;
   }
 }
+
+.list-articles-trigger {
+  margin-left: 12px;
+}
 </style>

+ 22 - 0
src/views/list/search/components/IconText.vue

@@ -0,0 +1,22 @@
+<template>
+  <span>
+    <a-icon type="type" style="margin-right: 8px" />
+    {{ text }}
+  </span>
+</template>
+
+<script>
+export default {
+  name: 'IconText',
+  props: {
+    'type': {
+      type: String,
+      required: true
+    },
+    text: {
+      type: [String, Number],
+      required: true
+    }
+  }
+}
+</script>