xiongzhu 4 anos atrás
pai
commit
9313c16c8a
49 arquivos alterados com 950 adições e 117 exclusões
  1. 1 0
      .env.development
  2. 1 0
      .env.production
  3. 1 0
      .gitignore
  4. 1 1
      .npmignore
  5. 13 9
      android/app/src/main/assets/capacitor.config.json
  6. 13 9
      capacitor.config.json
  7. 13 9
      ios/App/App/capacitor.config.json
  8. 1 32
      src/App.vue
  9. BIN
      src/assets/gongying_icon_01.png
  10. BIN
      src/assets/gongying_icon_02.png
  11. BIN
      src/assets/gongying_icon_03.png
  12. BIN
      src/assets/gongying_icon_04.png
  13. BIN
      src/assets/gongying_icon_05.png
  14. BIN
      src/assets/gongying_icon_06.png
  15. BIN
      src/assets/gongying_img_01.png
  16. BIN
      src/assets/gongying_img_02.png
  17. BIN
      src/assets/gongying_img_03.png
  18. BIN
      src/assets/gongying_img_04.png
  19. BIN
      src/assets/gongying_img_05.png
  20. BIN
      src/assets/gongying_img_06.png
  21. BIN
      src/assets/gongying_text_01.png
  22. BIN
      src/assets/gongying_text_02.png
  23. BIN
      src/assets/icon_sort.png
  24. BIN
      src/assets/icon_sort_asc.png
  25. BIN
      src/assets/icon_sort_desc.png
  26. BIN
      src/assets/nav_icon_search.png
  27. BIN
      src/assets/nav_icon_share.png
  28. 40 3
      src/components/NavBar.vue
  29. 55 0
      src/components/newsItem.vue
  30. 10 3
      src/main.js
  31. 7 19
      src/plugins/http.js
  32. 92 1
      src/router.js
  33. 5 1
      src/styles/app.less
  34. 46 0
      src/views/article.vue
  35. 78 12
      src/views/index/home.vue
  36. 3 1
      src/views/index/index.vue
  37. 7 6
      src/views/index/my.vue
  38. 73 10
      src/views/index/snd.vue
  39. 28 1
      src/views/login.vue
  40. 61 0
      src/views/news/news.vue
  41. 99 0
      src/views/news/subNews.vue
  42. 88 0
      src/views/policy.vue
  43. 11 0
      src/views/snd/dFinancial.vue
  44. 11 0
      src/views/snd/dProduct.vue
  45. 11 0
      src/views/snd/dTech.vue
  46. 11 0
      src/views/snd/sProduct.vue
  47. 11 0
      src/views/snd/sResource.vue
  48. 83 0
      src/views/snd/sTech.vue
  49. 76 0
      src/views/snd/sndList.vue

+ 1 - 0
.env.development

@@ -0,0 +1 @@
+VUE_APP_BASE_URL=http://192.168.50.116:8080

+ 1 - 0
.env.production

@@ -0,0 +1 @@
+VUE_APP_BASE_URL=http://jmrh.izouma.com/

+ 1 - 0
.gitignore

@@ -19,3 +19,4 @@ yarn-error.log*
 *.njsproj
 *.sln
 *.sw?
+.env.development.local

+ 1 - 1
.npmignore

@@ -3,4 +3,4 @@ node_modules/
 .vscode/
 *.map
 .DS_Store
-.sourcemaps
+.sourcemaps

+ 13 - 9
android/app/src/main/assets/capacitor.config.json

@@ -1,12 +1,16 @@
 {
-  "appId": "com.izouma.jmrh",
-  "appName": "江西融办",
-  "bundledWebRuntime": true,
-  "npmClient": "yarn",
-  "webDir": "dist",
-  "plugins": {
-    "SplashScreen": {
-      "launchShowDuration": 0
+    "appId": "com.izouma.jmrh",
+    "appName": "江西融办",
+    "bundledWebRuntime": true,
+    "npmClient": "yarn",
+    "webDir": "dist",
+    "plugins": {
+        "SplashScreen": {
+            "launchShowDuration": 0
+        }
+    },
+    "server": {
+        "url": "http://192.168.50.116:8082",
+        "cleartext": true
     }
-  }
 }

+ 13 - 9
capacitor.config.json

@@ -1,12 +1,16 @@
 {
-  "appId": "com.izouma.jmrh",
-  "appName": "江西融办",
-  "bundledWebRuntime": true,
-  "npmClient": "yarn",
-  "webDir": "dist",
-  "plugins": {
-    "SplashScreen": {
-      "launchShowDuration": 0
+    "appId": "com.izouma.jmrh",
+    "appName": "江西融办",
+    "bundledWebRuntime": true,
+    "npmClient": "yarn",
+    "webDir": "dist",
+    "plugins": {
+        "SplashScreen": {
+            "launchShowDuration": 0
+        }
+    },
+    "server": {
+        "url": "http://192.168.50.116:8082",
+        "cleartext": true
     }
-  }
 }

+ 13 - 9
ios/App/App/capacitor.config.json

@@ -1,12 +1,16 @@
 {
-  "appId": "com.izouma.jmrh",
-  "appName": "江西融办",
-  "bundledWebRuntime": true,
-  "npmClient": "yarn",
-  "webDir": "dist",
-  "plugins": {
-    "SplashScreen": {
-      "launchShowDuration": 0
+    "appId": "com.izouma.jmrh",
+    "appName": "江西融办",
+    "bundledWebRuntime": true,
+    "npmClient": "yarn",
+    "webDir": "dist",
+    "plugins": {
+        "SplashScreen": {
+            "launchShowDuration": 0
+        }
+    },
+    "server": {
+        "url": "http://192.168.50.116:8082",
+        "cleartext": true
     }
-  }
 }

+ 1 - 32
src/App.vue

@@ -38,39 +38,8 @@ export default {
 @import url(./styles/app.less);
 </style>
 <style lang="less" scoped>
-.root {
-    height: 100vh;
-    display: flex;
-    flex-direction: column;
+#root {
     background: white;
-    .navigation-bar {
-        font-size: 0;
-        line-height: 44px;
-        color: black;
-        padding-top: env(safe-area-inset-top, 0px);
-        .content {
-            height: 44px;
-            min-height: 44px;
-            position: relative;
-            font-size: 18px;
-            font-weight: bold;
-            font-weight: 500;
-            text-align: center;
-            .left-icon {
-                padding-left: 16px;
-                height: 44px;
-                display: flex;
-                align-items: center;
-                position: absolute;
-                left: 0;
-                top: 0;
-                .icon {
-                    width: 24px;
-                    height: 24px;
-                }
-            }
-        }
-    }
 }
 .router-page-wrapper {
     width: 100%;

BIN
src/assets/gongying_icon_01.png


BIN
src/assets/gongying_icon_02.png


BIN
src/assets/gongying_icon_03.png


BIN
src/assets/gongying_icon_04.png


BIN
src/assets/gongying_icon_05.png


BIN
src/assets/gongying_icon_06.png


BIN
src/assets/gongying_img_01.png


BIN
src/assets/gongying_img_02.png


BIN
src/assets/gongying_img_03.png


BIN
src/assets/gongying_img_04.png


BIN
src/assets/gongying_img_05.png


BIN
src/assets/gongying_img_06.png


BIN
src/assets/gongying_text_01.png


BIN
src/assets/gongying_text_02.png


BIN
src/assets/icon_sort.png


BIN
src/assets/icon_sort_asc.png


BIN
src/assets/icon_sort_desc.png


BIN
src/assets/nav_icon_search.png


BIN
src/assets/nav_icon_share.png


+ 40 - 3
src/components/NavBar.vue

@@ -1,14 +1,26 @@
 <template>
-    <div :style="{ height: placeholder ? 'calc(44px + var(--safe-top))' : '0px' }">
+    <div :style="computedStyle">
         <div class="app-nav-bar">
             <div class="nav-bar-body">
+                <slot name="title">
+                    <div class="nav-bar-title">{{ title }}</div>
+                </slot>
                 <div class="nav-bar-left" @click="clickLeft">
                     <slot name="left">
                         <img class="nav-left-icon" src="../assets/nav_icon_back_black.png" />
                     </slot>
                 </div>
-                <div class="nav-bar-title">{{ title }}</div>
+                <div class="nav-bar-right" @click="clickRight">
+                    <img v-if="rightIcon === 'share'" class="nav-right-icon" src="../assets/nav_icon_share.png" />
+                    <img
+                        v-else-if="rightIcon === 'search'"
+                        class="nav-right-icon"
+                        src="../assets/nav_icon_search.png"
+                    />
+                    <slot name="right" v-else> </slot>
+                </div>
             </div>
+            <slot name="append"></slot>
         </div>
     </div>
 </template>
@@ -18,14 +30,26 @@ export default {
         title: {},
         placeholder: {
             default: true
-        }
+        },
+        rightIcon: {}
     },
     data() {
         return {};
     },
+    computed: {
+        computedStyle() {
+            return {
+                height: this.placeholder ? 'calc(44px + var(--safe-top))' : '0px',
+                minHeight: this.placeholder ? 'calc(44px + var(--safe-top))' : '0px'
+            };
+        }
+    },
     methods: {
         clickLeft() {
             this.$emit('click-left');
+        },
+        clickRight() {
+            this.$emit('click-right');
         }
     }
 };
@@ -38,6 +62,7 @@ export default {
     right: 0;
     z-index: 1;
     padding-top: var(--safe-top);
+    background: white;
     .nav-bar-body {
         height: 44px;
         .flex();
@@ -55,6 +80,18 @@ export default {
                 height: 24px;
             }
         }
+        .nav-bar-right {
+            position: absolute;
+            right: 0;
+            top: 0;
+            height: 100%;
+            padding: 0 16px;
+            .flex();
+            .nav-right-icon {
+                width: 24px;
+                height: 24px;
+            }
+        }
         .nav-bar-title {
             color: black;
             font-size: 17px;

+ 55 - 0
src/components/newsItem.vue

@@ -0,0 +1,55 @@
+<template>
+    <router-link :to="{ name: 'article', query: { id: content.id } }" class="news-item">
+        <div class="info">
+            <div class="title">{{ content.title }}</div>
+            <div class="time">{{ content.createdAt }}</div>
+        </div>
+        <div class="cover" v-if="content.cover" :style="{ backgroundImage: `url(${content.cover})` }"></div>
+    </router-link>
+</template>
+<script>
+export default {
+    props: {
+        content: {
+            required: true
+        }
+    },
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped>
+.news-item {
+    padding: 8px 16px;
+    .flex();
+    &:active {
+        background: shade(#ffffff, 5%);
+    }
+    .info {
+        .flex-col();
+        justify-content: space-between;
+        .title {
+            .ellipsisLn(2);
+            font-size: 16px;
+            color: black;
+            line-height: 24px;
+        }
+        .time {
+            color: @text4;
+            font-size: 13px;
+            line-height: 22px;
+            margin-top: 6px;
+        }
+    }
+    .cover {
+        margin-left: 10px;
+        width: 110px;
+        min-width: 110px;
+        height: 66px;
+        background-size: cover;
+        background-position: center;
+        border-radius: 6px;
+    }
+}
+</style>

+ 10 - 3
src/main.js

@@ -8,7 +8,7 @@ import 'url-search-params-polyfill';
 import VueLoading from 'vue-loading-template';
 import Loadmore from './directives/loadmore';
 import Vant from 'vant';
-import { Plugins, StatusBarStyle } from '@capacitor/core';
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
 import 'vant/lib/index.less';
 import NavBar from './components/NavBar';
 import vueg from 'vueg';
@@ -16,6 +16,9 @@ import vueg from 'vueg';
 // const iNoBounce = require('./inobounce');
 // console.log(iNoBounce);
 // iNoBounce.enable();
+Vue.prototype.$colors = {
+    prim: '#BF1616'
+};
 Vue.config.productionTip = false;
 Vue.use(Vant);
 Vue.prototype.$toast.setDefaultOptions({ duration: 2000, forbidClick: true });
@@ -34,7 +37,6 @@ const { StatusBar } = Plugins;
 StatusBar.setOverlaysWebView({
     overlay: true
 });
-store.commit('setCode', new URLSearchParams(window.location.search).get('code'));
 const vm = new Vue({
     router,
     store,
@@ -85,7 +87,12 @@ document.addEventListener(
         document.addEventListener(
             'backbutton',
             e => {
-                if (vm.$route.name === 'user' || vm.$route.name === 'roomInfo') {
+                if (
+                    vm.$route.name === 'home' ||
+                    vm.$route.name === 'snd' ||
+                    vm.$route.name === 'interact' ||
+                    vm.$route.name === 'my'
+                ) {
                     let t1 = new Date().getTime();
                     if (t1 - t < 1000) {
                         navigator.app.exitApp();

+ 7 - 19
src/plugins/http.js

@@ -2,19 +2,7 @@ import axios from 'axios';
 import router from '../router';
 import qs from 'qs';
 /* eslint-disable */
-let baseUrl = 'http://localhost:8080/';
-switch (process.env.NODE_ENV) {
-    case 'development':
-        baseUrl = `http://192.168.50.116:8080/`;
-        break;
-    case 'test':
-        baseUrl = 'http://localhost:8080/';
-        break;
-    case 'production':
-        baseUrl = '../';
-        break;
-}
-// baseUrl='https://zmj.izouma.com/'
+let baseUrl = process.env.VUE_APP_BASE_URL;
 const axiosInstance = axios.create({
     baseURL: baseUrl,
 });
@@ -41,12 +29,12 @@ axiosInstance.interceptors.response.use(
         console.log(error);
         if (401 === error.response.status) {
             if (router.currentRoute.name !== 'login') {
-                router.replace({
-                    name: 'login',
-                    params: {
-                        from: router.currentRoute.name,
-                    },
-                });
+                // router.replace({
+                //     name: 'login',
+                //     params: {
+                //         from: router.currentRoute.name,
+                //     },
+                // });
             } else {
             }
         }

+ 92 - 1
src/router.js

@@ -8,6 +8,8 @@ import interact from './views/index/interact.vue';
 import my from './views/index/my.vue';
 import store from './store';
 import http from './plugins/http';
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
+const { StatusBar } = Plugins;
 Vue.use(Router);
 const v = new Vue();
 
@@ -31,7 +33,10 @@ const router = new Router({
                 {
                     path: '/snd',
                     name: 'snd',
-                    component: snd
+                    component: snd,
+                    meta: {
+                        statusBar: 'dark'
+                    }
                 },
                 {
                     path: '/interact',
@@ -54,6 +59,74 @@ const router = new Router({
             path: '/register',
             name: 'register',
             component: () => import(/* webpackChunkName: "register" */ '@/views/register.vue')
+        },
+        {
+            path: '/news',
+            name: 'news',
+            component: () => import(/* webpackChunkName: "news" */ '@/views/news/news.vue'),
+            meta: {
+                statusBar: 'dark'
+            }
+        },
+        {
+            path: '/article',
+            name: 'article',
+            component: () => import(/* webpackChunkName: "article" */ '@/views/article.vue'),
+            meta: {
+                statusBar: 'dark'
+            }
+        },
+        {
+            path: '/policy',
+            name: 'policy',
+            component: () => import(/* webpackChunkName: "policy" */ '@/views/policy.vue'),
+            meta: {
+                statusBar: 'dark'
+            }
+        },
+        {
+            path: '/sndList',
+            name: 'sndList',
+            component: () => import(/* webpackChunkName: "sndList" */ '@/views/snd/sndList.vue'),
+            meta: {
+                statusBar: 'dark'
+            },
+            children: [
+                {
+                    path: '',
+                    redirect: 'sTech'
+                },
+                {
+                    path: 'sTech',
+                    name: 'sTech',
+                    component: () => import(/* webpackChunkName: "sTech" */ '@/views/snd/sTech.vue')
+                },
+                {
+                    path: 'sProduct',
+                    name: 'sProduct',
+                    component: () => import(/* webpackChunkName: "sProduct" */ '@/views/snd/sProduct.vue')
+                },
+                {
+                    path: 'sResource',
+                    name: 'sResource',
+                    component: () => import(/* webpackChunkName: "sResource" */ '@/views/snd/sResource.vue')
+                },
+                {
+                    path: 'dTech',
+                    name: 'dTech',
+                    component: () => import(/* webpackChunkName: "dTech" */ '@/views/snd/dTech.vue')
+                },
+                {
+                    path: 'dProduct',
+                    name: 'dProduct',
+                    component: () => import(/* webpackChunkName: "dProduct" */ '@/views/snd/dProduct.vue')
+                },
+                {
+                    path: 'dFinancial',
+                    name: 'dFinancial',
+                    component: () => import(/* webpackChunkName: "dFinancial" */ '@/views/snd/dFinancial.vue')
+                }
+            ]
         }
     ]
 });
@@ -62,6 +135,9 @@ let history = { '/home': 0 };
 let historyCount = 0;
 const tabRoutePath = ['/home', '/snd', '/interact', '/my'];
 router.beforeEach((to, from, next) => {
+    if (!(store.state.userInfo && store.state.userInfo.id)) {
+        store.dispatch('updateUserInfo');
+    }
     const f = arg => {
         let direction = '';
         const toHome = tabRoutePath.indexOf(to.path) > -1;
@@ -176,4 +252,19 @@ router.beforeEach((to, from, next) => {
         f();
     }
 });
+
+router.afterEach((to, from) => {
+    const statusBarAvailable = Capacitor.isPluginAvailable('StatusBar');
+    if (statusBarAvailable) {
+        if ('dark' === to.meta.statusBar) {
+            StatusBar.setStyle({
+                style: StatusBarStyle.Light
+            });
+        } else {
+            StatusBar.setStyle({
+                style: StatusBarStyle.Dark
+            });
+        }
+    }
+});
 export default router;

+ 5 - 1
src/styles/app.less

@@ -282,6 +282,10 @@ input {
     }
 }
 
+::-webkit-scrollbar {
+    display: none;
+}
+
 .btn-lg {
     width: 280px;
     height: 40px;
@@ -307,4 +311,4 @@ input {
     &:active {
         background: fade(@prim, 5%);
     }
-}
+}

+ 46 - 0
src/views/article.vue

@@ -0,0 +1,46 @@
+<template>
+    <div>
+        <nav-bar right-icon="share" @click-left="$router.go(-1)" title="文章详情"></nav-bar>
+        <div class="article-title">{{ article.title }}</div>
+        <div class="article-desc">
+            <div class="time">发布时间:{{ article.createdAt }}</div>
+        </div>
+        <div class="article-content" v-html="article.content"></div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            article: {}
+        };
+    },
+    created() {
+        this.$http.get(`/article/get/${this.$route.query.id}`).then(res => {
+            this.article = res;
+        });
+    }
+};
+</script>
+<style lang="less" scoped>
+.article-title {
+    margin: 20px 16px 0 16px;
+    font-size: 20px;
+    color: black;
+    font-weight: bold;
+}
+.article-desc {
+    margin: 10px 16px 0 16px;
+    font-size: 13px;
+    color: @text3;
+}
+.article-content {
+    margin: 10px 16px 0 16px;
+    line-height: 1.5;
+    /deep/ img {
+        width: 100%;
+        height: auto;
+        border-radius: 8px;
+    }
+}
+</style>

+ 78 - 12
src/views/index/home.vue

@@ -1,5 +1,5 @@
 <template>
-    <div>
+    <div style="padding-bottom: calc(50px + var(--safe-bottom));">
         <div class="notification-wrapper">
             <img src="../../assets/home_notification.png" />
             <div class="badge"></div>
@@ -24,44 +24,75 @@
                     搜索...
                 </div>
                 <div class="menus">
-                    <div class="item">
+                    <router-link to="/news" class="item">
                         <img class="icon" src="../../assets/home_menu_1.png" />
                         <div class="text">通知公告</div>
-                    </div>
-                    <div class="item">
+                    </router-link>
+                    <router-link to="/policy" class="item">
                         <img class="icon" src="../../assets/home_menu_2.png" />
                         <div class="text">政策法规</div>
-                    </div>
-                    <div class="item">
+                    </router-link>
+                    <router-link to="/news" class="item">
                         <img class="icon" src="../../assets/home_menu_3.png" />
                         <div class="text">找产品</div>
-                    </div>
-                    <div class="item">
+                    </router-link>
+                    <router-link to="/news" class="item">
                         <img class="icon" src="../../assets/home_menu_4.png" />
                         <div class="text">看需求</div>
-                    </div>
+                    </router-link>
                 </div>
             </div>
         </div>
+        <div class="category">
+            <div class="item">
+                <img src="../../assets/home_category_1.png" />
+            </div>
+            <div class="item" style="margin-left:13px;">
+                <img src="../../assets/home_category_2.png" />
+            </div>
+        </div>
+        <div class="page-title" style="margin-top:50px;">
+            <div class="text">热点新闻</div>
+            <router-link to="/news" tag="div" class="more">
+                <div class="text">更多</div>
+                <img src="../../assets/icon_into.png" class="icon" />
+            </router-link>
+        </div>
+        <div class="news-list">
+            <news-item v-for="item in news" :key="item.id" :content="item"></news-item>
+        </div>
     </div>
 </template>
 <script>
+import newsItem from '../../components/newsItem';
 export default {
+    components: {
+        newsItem
+    },
     data() {
         return {
-            showNavBar: false
+            showNavBar: false,
+            news: []
         };
     },
+    created() {
+        this.$http.get('/article/all', { query: { typeId: 1005 }, sort: 'createdAt,desc' }).then(res => {
+            this.news = res.content;
+        });
+        this.$http.get('/product/all?size=5').then(res => {
+            this.products = res.content;
+        });
+    },
     mounted() {
         document.querySelector('#root').addEventListener('scroll', this.scroll);
     },
     beforeDestroy() {
         document.querySelector('#root').removeEventListener('scroll', this.scroll);
     },
+
     methods: {
         scroll(e) {
-            console.log(e.target.scrollTop);
-            if (e.target.scrollTop > 100) {
+            if (e.target.scrollTop > 230) {
                 this.showNavBar = true;
             } else {
                 this.showNavBar = false;
@@ -194,4 +225,39 @@ export default {
         }
     }
 }
+.page-title {
+    height: 28px;
+    .flex();
+    > .text {
+        margin-left: 16px;
+        flex-grow: 1;
+        font-size: 18px;
+        font-weight: bold;
+    }
+    .more {
+        .flex();
+        margin-right: 16px;
+        > .text {
+            color: @text4;
+            font-size: 14px;
+        }
+        > .icon {
+            width: 24px;
+            height: 24px;
+        }
+    }
+}
+.category {
+    padding: 0 16px;
+    margin-top: 16px;
+    .flex();
+    .item {
+        flex-basis: 0;
+        flex-grow: 1;
+        img {
+            width: 100%;
+            height: auto;
+        }
+    }
+}
 </style>

+ 3 - 1
src/views/index/index.vue

@@ -1,6 +1,8 @@
 <template>
     <div>
-        <router-view></router-view>
+        <keep-alive>
+            <router-view></router-view>
+        </keep-alive>
         <van-tabbar v-model="tab" safe-area-inset-bottom route active-color="#BF1616" inactive-color="#313233">
             <van-tabbar-item to="/home" name="home" icon="home-o">
                 <template v-slot:icon="{ active }">

+ 7 - 6
src/views/index/my.vue

@@ -111,6 +111,7 @@ export default {
     .flex-col();
     position: relative;
     .item {
+        position: relative;
         .flex();
         height: 70px;
         .icon {
@@ -129,12 +130,12 @@ export default {
             height: 24px;
             margin-right: 16px;
         }
-    }
-    &::after {
-        content: '';
-        .setBottomLine();
-        left: 50px;
-        right: 16px;
+        &::after {
+            content: '';
+            .setBottomLine(@border2);
+            left: 50px;
+            right: 16px;
+        }
     }
 }
 </style>

+ 73 - 10
src/views/index/snd.vue

@@ -1,15 +1,54 @@
 <template>
     <div>
-        <van-nav-bar
-            title="标题"
-            left-text="返回"
-            right-text="按钮"
-            left-arrow
-            @click-left="onClickLeft"
-            @click-right="onClickRight"
-            safe-area-inset-top
-            fixed
+        <img
+            src="../../assets/gongying_text_01.png"
+            class="img-title"
+            style="margin-top:calc(26px + var(--safe-top))"
         />
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_01.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_01.png" />技术发布
+        </router-link>
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_02.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_02.png" />产品发布
+        </router-link>
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_03.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_03.png" />资源共享
+        </router-link>
+        <img src="../../assets/gongying_text_02.png" class="img-title" style="margin-top:42px" />
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_04.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_04.png" />技术需求
+        </router-link>
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_05.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_05.png" />产品需求
+        </router-link>
+        <router-link
+            to="/sndList"
+            class="item"
+            :style="{ backgroundImage: `url(${require('../../assets/gongying_img_06.png')})` }"
+        >
+            <img src="../../assets/gongying_icon_06.png" />融资需求
+        </router-link>
+        <div style="height:calc(50px + var(--safe-bottom))"></div>
     </div>
 </template>
 <script>
@@ -19,4 +58,28 @@ export default {
     }
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.img-title {
+    margin-left: 16px;
+    margin-bottom: 17px;
+    width: 93px;
+    height: 27px;
+}
+.item {
+    .flex();
+    justify-content: center;
+    color: white;
+    font-size: 22px;
+    font-weight: bold;
+    background-size: cover;
+    background-position: center;
+    height: 120px;
+    border-radius: 8px;
+    margin: 0 16px 12px 16px;
+    img {
+        width: 36px;
+        height: 36px;
+        margin-right: 8px;
+    }
+}
+</style>

+ 28 - 1
src/views/login.vue

@@ -9,7 +9,7 @@
             <img class="icon" src="../assets/login_icon_pwd.png" />
             <input placeholder="请输入密码" v-model="password" type="password" />
         </div>
-        <div class="btn-lg btn-login">登录</div>
+        <div class="btn-lg btn-login" @click="login">登录</div>
         <router-link tag="div" to="/register" replace class="btn-lg-o btn-register">
             暂无账号,立即注册
         </router-link>
@@ -22,6 +22,33 @@ export default {
             username: '',
             password: ''
         };
+    },
+    methods: {
+        login() {
+            if (!this.username) {
+                this.$toast('请输入用户名');
+                return;
+            }
+            if (!this.password) {
+                this.$toast('请输入密码');
+                return;
+            }
+            this.$toast.loading();
+            this.$http
+                .post('/auth/login', {
+                    username: this.username,
+                    password: this.password
+                })
+                .then(res => {
+                    localStorage.setItem('token', res);
+                    this.$store.dispatch('updateUserInfo');
+                    this.$router.go(-1);
+                    this.$toast.success('登录成功');
+                })
+                .catch(e => {
+                    this.$toast(e.error || '登录失败,请稍后再试');
+                });
+        }
     }
 };
 </script>

+ 61 - 0
src/views/news/news.vue

@@ -0,0 +1,61 @@
+<template>
+    <div class="news-root">
+        <nav-bar @click-left="$router.go(-1)" right-icon="search">
+            <div slot="title" class="nav-tabs">
+                <div class="nav-tab-item" :class="{ active: tab === 0 }" @click="swipeTo(0)">热点</div>
+                <div class="nav-tab-item" :class="{ active: tab === 1 }" @click="swipeTo(1)">动态</div>
+                <div class="nav-tab-item" :class="{ active: tab === 2 }" @click="swipeTo(2)">通知</div>
+            </div>
+        </nav-bar>
+        <van-swipe class="swipe-container" :loop="false" :show-indicators="false" @change="tabChange" ref="swipe">
+            <sub-news title="热点推荐" type-id="1002" key="1"></sub-news>
+            <sub-news title="新闻动态" type-id="1004" key="2"></sub-news>
+            <sub-news title="通知公告" type-id="1108" key="3"></sub-news>
+        </van-swipe>
+    </div>
+</template>
+<script>
+import subNews from './subNews';
+export default {
+    components: { subNews },
+    data() {
+        return {
+            tab: 0
+        };
+    },
+    methods: {
+        swipeTo(i) {
+            this.tab = i;
+            this.$refs.swipe.swipeTo(i);
+        },
+        tabChange(i) {
+            console.log(i);
+            this.tab = i;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.news-root {
+    .flex-col();
+}
+.swipe-container {
+    flex-grow: 1;
+}
+.nav-tabs {
+    .flex();
+    .nav-tab-item {
+        width: 76px;
+        font-size: 16px;
+        color: black;
+        .flex();
+        justify-content: center;
+        transition: all 0.2s;
+        &.active {
+            color: @prim;
+            font-weight: bold;
+            transform: scale(1.1);
+        }
+    }
+}
+</style>

+ 99 - 0
src/views/news/subNews.vue

@@ -0,0 +1,99 @@
+<template>
+    <van-swipe-item class="news-swipe-item">
+        <div>
+            <van-swipe class="banner" :loop="false" :width="bannerWidth" :show-indicators="false">
+                <van-swipe-item
+                    v-for="item in banners"
+                    :key="item.id"
+                    class="banner-item-wrapper"
+                    @click="detail(item)"
+                >
+                    <div class="banner-item" :style="{ backgroundImage: `url(${item.cover})` }">
+                        <div class="title">{{ item.title }}</div>
+                    </div>
+                </van-swipe-item>
+            </van-swipe>
+            <div class="page-title">{{ title }}</div>
+            <div class="news-list">
+                <news-item v-for="item in news" :key="item.id" :content="item"></news-item>
+            </div>
+        </div>
+    </van-swipe-item>
+</template>
+<script>
+import newsItem from '../../components/newsItem';
+export default {
+    components: {
+        newsItem
+    },
+    props: ['title', 'typeId'],
+    data() {
+        return {
+            bannerWidth: 0,
+            banners: [],
+            news: []
+        };
+    },
+    mounted() {
+        this.bannerWidth = window.innerWidth - 54;
+    },
+    created() {
+        this.$http.get('/article/all', { query: { typeId: 1005 }, sort: 'createdAt,desc' }).then(res => {
+            this.banners = res.content;
+        });
+        this.getData();
+    },
+    methods: {
+        getData() {
+            this.$http.get('/article/all', { query: { typeId: this.typeId }, sort: 'createdAt,desc' }).then(res => {
+                this.news = res.content;
+            });
+        },
+        detail(item) {
+            this.$router.push({
+                name: 'article',
+                query: { id: item.id }
+            });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.news-swipe-item {
+    overflow-y: auto;
+    -webkit-overflow-scrolling: touch;
+}
+.banner {
+    margin-left: 11px;
+    margin-right: 11px;
+    // overflow: visible;
+}
+.banner-item-wrapper {
+    margin-top: 12px;
+}
+.banner-item {
+    background-size: cover;
+    background-position: center;
+    border-radius: 6px;
+    position: relative;
+    height: 190px;
+    margin: 0 5px;
+    .title {
+        position: absolute;
+        left: 10px;
+        bottom: 10px;
+        right: 10px;
+        color: white;
+        font-size: 16px;
+        font-weight: bold;
+        .ellipsisLn(2);
+    }
+}
+.page-title {
+    font-size: 18px;
+    line-height: 28px;
+    color: black;
+    font-weight: bold;
+    margin: 30px 0 4px 16px;
+}
+</style>

+ 88 - 0
src/views/policy.vue

@@ -0,0 +1,88 @@
+<template>
+    <div>
+        <nav-bar title="政策法规" @click-left="$router.go(-1)" right-icon="search">
+            <div class="tab-wrapper" slot="append">
+                <van-tabs v-model="typeId" type="card" :color="$colors.prim" title-inactive-color="#494A4D">
+                    <van-tab v-for="item in types" :name="item.id" :title="item.name" :key="item.id"></van-tab>
+                </van-tabs>
+            </div>
+        </nav-bar>
+        <div style="width:100%;height:58px"></div>
+        <div class="news-list">
+            <news-item v-for="item in list" :key="item.id" :content="item"></news-item>
+        </div>
+        <van-empty v-if="empty" description="暂无内容" />
+    </div>
+</template>
+<script>
+import newsItem from '../components/newsItem';
+export default {
+    components: { newsItem },
+    data() {
+        return {
+            types: [],
+            typeId: null,
+            list: [],
+            last: false,
+            page: 0,
+            empty: false
+        };
+    },
+    created() {
+        this.$http.get('/dataType/all', { size: 1000, query: { keyType: 'zcfg' } }).then(res => {
+            this.typeId = res.content[0].id;
+            this.types = res.content;
+        });
+    },
+    methods: {
+        getData() {
+            if (this.last) {
+                return;
+            }
+            this.$http
+                .get('/article/all', {
+                    page: this.page,
+                    query: {
+                        type: { id: this.typeId }
+                    }
+                })
+                .then(res => {
+                    if (res.first) {
+                        this.list = [];
+                    }
+                    this.list = this.list.concat(res.content);
+                    this.last = res.last;
+                    this.empty = res.totalElements === 0;
+                });
+        }
+    },
+    watch: {
+        typeId() {
+            this.last = false;
+            this.page = 0;
+            this.empty = false;
+            this.getData();
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.tab-wrapper {
+    padding: 10px 0 8px 0;
+}
+/deep/ .van-tabs__wrap {
+    padding: 0 8px;
+    height: 40px;
+    .van-tabs__nav {
+        border: none;
+        margin: 0;
+        height: 40px;
+    }
+    .van-tab {
+        border: none;
+    }
+    .van-tab--active {
+        border-radius: 6px;
+    }
+}
+</style>

+ 11 - 0
src/views/snd/dFinancial.vue

@@ -0,0 +1,11 @@
+<template>
+    <div></div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 11 - 0
src/views/snd/dProduct.vue

@@ -0,0 +1,11 @@
+<template>
+    <div></div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 11 - 0
src/views/snd/dTech.vue

@@ -0,0 +1,11 @@
+<template>
+    <div></div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 11 - 0
src/views/snd/sProduct.vue

@@ -0,0 +1,11 @@
+<template>
+    <div></div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 11 - 0
src/views/snd/sResource.vue

@@ -0,0 +1,11 @@
+<template>
+    <div></div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 83 - 0
src/views/snd/sTech.vue

@@ -0,0 +1,83 @@
+<template>
+    <div class="sub-snd">
+        <div class="filters">
+            <div class="filter-item btn">综合</div>
+            <div class="filter-item btn">
+                发布时间
+                <img src="../../assets/icon_sort.png" class="icon" />
+            </div>
+            <van-dropdown-menu class="filter-item">
+                <van-dropdown-item v-model="value1" :options="option1" />
+            </van-dropdown-menu>
+            <van-dropdown-menu class="filter-item">
+                <van-dropdown-item v-model="value2" :options="option2" />
+            </van-dropdown-menu>
+        </div>
+        <div class="list">
+            <div v-for="(n, i) in 1000" :key="i">222123123</div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            value1: 0,
+            value2: 'a',
+            option1: [
+                { text: '全部商品', value: 0 },
+                { text: '环境与目标特性试验场', value: 1 },
+                { text: '活动商品', value: 2 }
+            ],
+            option2: [
+                { text: '默认排序', value: 'a' },
+                { text: '环境与目标特性试验场', value: 'b' },
+                { text: '销量排序', value: 'c' }
+            ]
+        };
+    }
+};
+</script>
+<style lang="less" scoped>
+.sub-snd {
+    flex-grow: 1;
+    position: relative;
+    .flex-col();
+    .list {
+        min-height: 0;
+        flex-basis: 0;
+        flex-grow: 1;
+        overflow: auto;
+    }
+}
+.filters {
+    height: 44px;
+    min-height: 44px;
+    .flex();
+    width: 100%;
+    .filter-item {
+        flex-grow: 1;
+    }
+    .btn {
+        height: 44px;
+        .flex();
+        justify-content: center;
+        font-size: 14px;
+        color: #292c33;
+        .icon {
+            width: 16px;
+            height: 24px;
+            margin-left: 1px;
+        }
+    }
+    /deep/ .van-dropdown-menu__bar {
+        height: 44px;
+        box-shadow: none;
+    }
+    /deep/ .van-dropdown-menu__title {
+        font-size: 14px;
+        color: #292c33;
+        max-width: 72px;
+    }
+}
+</style>

+ 76 - 0
src/views/snd/sndList.vue

@@ -0,0 +1,76 @@
+<template>
+    <div class="snd-root">
+        <nav-bar @click-left="$router.go(-1)">
+            <div slot="title" class="nav-title-search"><img src="../../assets/icon_search.png" />搜索供需...</div>
+            <div slot="append">
+                <div class="tab-row">
+                    <van-tabs
+                        v-model="type"
+                        :color="$colors.prim"
+                        :title-active-color="$colors.prim"
+                        title-inactive-color="#000000"
+                    >
+                        <van-tab title="技术发布" to="sTech" replace></van-tab>
+                        <van-tab title="产品发布" to="sProduct" replace></van-tab>
+                        <van-tab title="资源共享" to="sResource" replace></van-tab>
+                        <van-tab title="技术需求" to="dTech" replace></van-tab>
+                        <van-tab title="产品需求" to="dProduct" replace></van-tab>
+                        <van-tab title="融资需求" to="dFinancial" replace></van-tab>
+                    </van-tabs>
+                </div>
+                <div class="filter-row"></div>
+            </div>
+        </nav-bar>
+        <div style="height:44px"></div>
+        <router-view></router-view>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            type: 0
+        };
+    },
+    created() {
+        console.log(this.$route.name);
+        this.type = Math.max(
+            ['sTech', 'sProduct', 'sResource', 'dTech', 'dProduct', 'dFinancial'].findIndex(
+                i => i === this.$route.name
+            ),
+            0
+        );
+    }
+};
+</script>
+<style lang="less" scoped>
+.snd-root {
+    .flex-col();
+}
+.nav-title-search {
+    height: 34px;
+    background: #f5f7fa;
+    border-radius: 17px;
+    margin-left: 59px;
+    margin-right: 16px;
+    .flex();
+    color: @text4;
+    font-size: 13px;
+    flex-grow: 1;
+    img {
+        width: 16px;
+        height: 16px;
+        margin-left: 10px;
+        margin-right: 6px;
+    }
+}
+/deep/ .van-tabs__line {
+    bottom: 23px;
+}
+/deep/ .van-tab__text {
+    padding-bottom: 1.5px;
+}
+/deep/ .van-tab--active .van-tab__text {
+    transform: scale(1.28);
+}
+</style>