xiongzhu 4 jaren geleden
bovenliggende
commit
bf538989b4

BIN
src/assets/icon_call.png


BIN
src/assets/icon_edit.png


BIN
src/assets/interact_banner_0.png


BIN
src/assets/interact_banner_1.png


BIN
src/assets/interact_banner_2.png


BIN
src/assets/interact_banner_call.png


BIN
src/assets/interact_icon_answer.png


BIN
src/assets/interact_icon_comment.png


BIN
src/assets/interact_icon_hot.png


BIN
src/assets/interact_icon_like.png


BIN
src/assets/interact_icon_like_pre.png


BIN
src/assets/nav_icon_back_white.png


BIN
src/assets/nav_icon_search_white.png


+ 48 - 6
src/components/NavBar.vue

@@ -1,21 +1,40 @@
 <template>
     <div :style="computedStyle">
-        <div class="app-nav-bar">
+        <div class="app-nav-bar" :style="navBarStyle">
             <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" />
+                        <img
+                            class="nav-left-icon"
+                            :src="
+                                theme === 'dark'
+                                    ? require('../assets/nav_icon_back_black.png')
+                                    : require('../assets/nav_icon_back_white.png')
+                            "
+                        />
                     </slot>
                 </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-if="rightIcon === 'share'"
+                        class="nav-right-icon"
+                        :src="
+                            theme === 'dark'
+                                ? require('../assets/nav_icon_share.png')
+                                : require('../assets/nav_icon_share.png')
+                        "
+                    />
                     <img
                         v-else-if="rightIcon === 'search'"
                         class="nav-right-icon"
-                        src="../assets/nav_icon_search.png"
+                        :src="
+                            theme === 'dark'
+                                ? require('../assets/nav_icon_search.png')
+                                : require('../assets/nav_icon_search_white.png')
+                        "
                     />
                     <slot name="right" v-else> </slot>
                 </div>
@@ -25,18 +44,29 @@
     </div>
 </template>
 <script>
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
+const { StatusBar } = Plugins;
 export default {
     props: {
         title: {},
         placeholder: {
             default: true
         },
-        rightIcon: {}
+        rightIcon: {},
+        theme: {
+            default: 'dark'
+        },
+        transparent: { type: Boolean, default: false }
     },
     data() {
         return {};
     },
     computed: {
+        navBarStyle() {
+            return {
+                background: this.transparent ? 'none' : this.theme === 'dark' ? 'white' : 'black'
+            };
+        },
         computedStyle() {
             return {
                 height: this.placeholder ? 'calc(44px + var(--safe-top))' : '0px',
@@ -51,6 +81,19 @@ export default {
         clickRight() {
             this.$emit('click-right');
         }
+    },
+    watch: {
+        theme(val) {
+            if (val === 'dark') {
+                StatusBar.setStyle({
+                    style: StatusBarStyle.Light
+                });
+            } else {
+                StatusBar.setStyle({
+                    style: StatusBarStyle.Dark
+                });
+            }
+        }
     }
 };
 </script>
@@ -62,7 +105,6 @@ export default {
     right: 0;
     z-index: 1;
     padding-top: var(--safe-top);
-    background: white;
     .nav-bar-body {
         height: 44px;
         .flex();

+ 21 - 0
src/router.js

@@ -51,6 +51,16 @@ const router = new Router({
                             path: 'official',
                             name: 'official',
                             component: () => import(/* webpackChunkName: "official" */ '@/views/interact/official.vue')
+                        },
+                        {
+                            path: 'forum',
+                            name: 'forum',
+                            component: () => import(/* webpackChunkName: "forum" */ '@/views/interact/forum.vue')
+                        },
+                        {
+                            path: 'qa',
+                            name: 'qa',
+                            component: () => import(/* webpackChunkName: "qa" */ '@/views/interact/qa.vue')
                         }
                     ]
                 },
@@ -164,6 +174,14 @@ const router = new Router({
             meta: {
                 statusBar: 'dark'
             }
+        },
+        {
+            path: '/createInteract',
+            name: 'createInteract',
+            component: () => import(/* webpackChunkName: "createInteract" */ '@/views/interact/createInteract.vue'),
+            meta: {
+                statusBar: 'dark'
+            }
         }
     ]
 });
@@ -291,6 +309,9 @@ router.beforeEach((to, from, next) => {
 });
 
 router.afterEach((to, from) => {
+    if (['official', 'forum', 'qa'].find(i => i === to.name)) {
+        return;
+    }
     const statusBarAvailable = Capacitor.isPluginAvailable('StatusBar');
     if (statusBarAvailable) {
         if ('dark' === to.meta.statusBar) {

+ 0 - 27
src/styles/app.less

@@ -284,31 +284,4 @@ input {
 
 ::-webkit-scrollbar {
     display: none;
-}
-
-.btn-lg {
-    width: 280px;
-    height: 40px;
-    background: @prim;
-    border-radius: 4px;
-    .flex();
-    color: white;
-    font-size: 14px;
-    justify-content: center;
-    &:active {
-        background: shade(@prim, 10%);
-    }
-}
-.btn-lg-o {
-    width: 280px;
-    height: 40px;
-    border-radius: 4px;
-    .flex();
-    color: @prim;
-    border: 1px solid @prim;
-    font-size: 14px;
-    justify-content: center;
-    &:active {
-        background: fade(@prim, 5%);
-    }
 }

+ 32 - 1
src/styles/common/index.less

@@ -1,4 +1,4 @@
-@divider: #dcdfe6;
+@divider: #f2f3f5;
 @prim: #bf1616;
 @success: #07c160;
 @danger: #ee0a24;
@@ -124,6 +124,36 @@
         background-color: #8f9294;
     }
 }
+
+.btn-lg {
+    width: 280px;
+    height: 40px;
+    background: @prim;
+    border-radius: 4px;
+    .flex();
+    color: white;
+    font-size: 14px;
+    justify-content: center;
+    user-select: none;
+    &:active {
+        background: shade(@prim, 10%);
+    }
+}
+.btn-lg-o {
+    width: 280px;
+    height: 40px;
+    border-radius: 4px;
+    .flex();
+    color: @prim;
+    border: 1px solid @prim;
+    font-size: 14px;
+    justify-content: center;
+    user-select: none;
+    &:active {
+        background: fade(@prim, 5%);
+    }
+}
+
 .btn-sm {
     height: 30px;
     .flex();
@@ -133,6 +163,7 @@
     border-radius: 4px;
     color: white;
     font-size: 13px;
+    user-select: none;
     &:active {
         background: shade(@prim, 10%);
     }

+ 138 - 3
src/views/index/interact.vue

@@ -1,11 +1,146 @@
 <template>
-    <div></div>
+    <div class="interact-root">
+        <nav-bar :theme="navTheme" :placeholder="false" :transparent="navTransparent" rightIcon="search">
+            <div slot="left"></div>
+            <div class="tabs" :class="navTheme" slot="title">
+                <div class="tab-item" :class="{ active: tab === 0 }" @click="changeTab(0)">官答</div>
+                <div class="tab-item" :class="{ active: tab === 1 }" @click="changeTab(1)">热议</div>
+                <div class="tab-item" :class="{ active: tab === 2 }" @click="changeTab(2)">互动</div>
+            </div>
+        </nav-bar>
+        <div class="top-banner-wrapper">
+            <transition name="fade">
+                <img class="top-banner" src="../../assets/interact_banner_0.png" v-if="tab === 0" key="0" />
+                <img class="top-banner" src="../../assets/interact_banner_1.png" v-if="tab === 1" key="1" />
+                <img class="top-banner" src="../../assets/interact_banner_2.png" v-if="tab === 2" key="2" />
+            </transition>
+        </div>
+        <router-view></router-view>
+    </div>
 </template>
 <script>
 export default {
     data() {
-        return {};
+        return {
+            navTheme: 'light',
+            navTransparent: true,
+            tab: 0
+        };
+    },
+    created() {
+        this.matchRoute();
+    },
+    activated() {
+        this.matchRoute();
+        document.querySelector('#root').addEventListener('scroll', this.scroll);
+    },
+    mounted() {
+        console.log('mounted');
+        document.querySelector('#root').addEventListener('scroll', this.scroll);
+    },
+    deactivated() {
+        console.log('deactivated');
+        document.querySelector('#root').removeEventListener('scroll', this.scroll);
+    },
+    beforeDestroy() {
+        console.log('beforeDestroy');
+        document.querySelector('#root').removeEventListener('scroll', this.scroll);
+    },
+    computed: {
+        bannerSrc() {
+            return require(`../../assets/interact_banner_${this.tab}.png`);
+        }
+    },
+    methods: {
+        scroll(e) {
+            if (
+                e.target.scrollTop >
+                (200 / 375) * window.innerWidth -
+                    44 -
+                    Number(document.documentElement.style.getPropertyValue('--safe-top').replace('px', ''))
+            ) {
+                this.navTheme = 'dark';
+                this.navTransparent = false;
+            } else {
+                this.navTheme = 'light';
+                this.navTransparent = true;
+            }
+        },
+        changeTab(i) {
+            this.tab = i;
+            switch (i) {
+                case 0:
+                    this.$router.replace({
+                        name: 'official'
+                    });
+                    break;
+                case 1:
+                    this.$router.replace({
+                        name: 'forum'
+                    });
+                    break;
+                case 2:
+                    this.$router.replace({
+                        name: 'qa'
+                    });
+                    break;
+            }
+        },
+        matchRoute() {
+            ['official', 'forum', 'qa'].forEach((name, index) => {
+                if (
+                    this.$route.matched.find(e => {
+                        return e.name === name;
+                    })
+                ) {
+                    this.tab = index;
+                }
+            });
+        }
     }
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.interact-root {
+    padding-bottom: calc(50px + var(--safe-bottom));
+}
+.tabs {
+    .flex();
+    padding: 0 68px;
+    width: 100%;
+    .tab-item {
+        flex-basis: 0;
+        flex-grow: 1;
+        .flex();
+        justify-content: center;
+        color: rgba(255, 255, 255, 0.5);
+        font-size: 16px;
+        transition: all 0.2s;
+        &.active {
+            font-size: 20px;
+            color: white;
+            font-weight: bold;
+        }
+    }
+    &.dark {
+        .tab-item {
+            color: rgba(0, 0, 0, 0.5);
+            &.active {
+                color: black;
+            }
+        }
+    }
+}
+.top-banner-wrapper {
+    width: 100vw;
+    height: calc(200 / 375 * 100vw);
+    position: relative;
+    .top-banner {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+        left: 0;
+    }
+}
+</style>

+ 162 - 0
src/views/interact/createInteract.vue

@@ -0,0 +1,162 @@
+<template>
+    <div class="create-interact">
+        <nav-bar :title="title" @click-left="$router.go(-1)">
+            <div slot="right" class="nav-bar-right">提交</div>
+        </nav-bar>
+        <div class="title">
+            <input placeholder="输入标题内容,30字以内" maxlength="30" v-model="form.title" />
+        </div>
+        <div class="content">
+            <textarea placeholder="详细描述您的问题" v-model="form.content"></textarea>
+        </div>
+        <div class="upload">
+            <van-uploader v-model="fileList" accept="image/*" multiple :after-read="afterRead" max-count="9" />
+        </div>
+        <div class="switch-wrapper">
+            <div class="label">是否公开</div>
+            <van-switch v-model="pub" active-color="#BF1616" />
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            type: '',
+            form: { title: '', content: '' },
+            fileList: [],
+            pub: false
+        };
+    },
+    created() {
+        this.type = this.$route.query.type;
+    },
+    computed: {
+        title() {
+            switch (this.type) {
+                case 'official':
+                    return '我要咨询';
+                case 'forum':
+                    return '发布话题';
+                case 'qa':
+                    return '发布问题';
+                default:
+                    return '';
+            }
+        }
+    },
+    methods: {
+        afterRead(file) {
+            console.log(file);
+            file.status = 'uploading';
+            file.message = '上传中...';
+            let form = new FormData();
+            form.append('file', file.file);
+            this.$http
+                .post('/upload/file', form)
+                .then(res => {
+                    console.log(res);
+                    file.status = 'success';
+                    file.url = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    file.status = 'failed';
+                    file.message = '上传失败';
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.create-interact {
+    height: 100%;
+    .flex-col();
+}
+.nav-bar-right {
+    color: @prim;
+    font-size: 16px;
+    word-break: keep-all;
+    user-select: none;
+    &:active {
+        color: fade(@prim, 60%);
+    }
+}
+.title {
+    position: relative;
+    padding: 16px 16px 18px 16px;
+    &::after {
+        .setBottomLine();
+        left: 16px;
+        right: 16px;
+    }
+    input {
+        width: 100%;
+        padding: 0;
+        margin: 0;
+        font-size: 20px;
+        line-height: 30px;
+        &::-webkit-input-placeholder {
+            color: @text4;
+        }
+    }
+}
+.content {
+    flex-grow: 1;
+    padding: 16px;
+    position: relative;
+    textarea {
+        width: 100%;
+        height: 100%;
+        border: none;
+        font-size: 16px;
+        line-height: 26px;
+        resize: none;
+        &::-webkit-input-placeholder {
+            color: @text4;
+        }
+    }
+    &::after {
+        .setBottomLine();
+        left: 16px;
+        right: 16px;
+    }
+}
+.upload {
+    padding: 16px;
+}
+/deep/ .van-uploader__preview-image {
+    width: 70px;
+    height: 70px;
+}
+/deep/ .van-uploader__upload {
+    width: 70px;
+    height: 70px;
+    &::after {
+        content: '添加图片';
+        font-size: 12px;
+        color: @text4;
+        margin-top: 4px;
+    }
+}
+.switch-wrapper {
+    padding: 0 16px 14px 16px;
+    .flex();
+    .label {
+        flex-grow: 1;
+        color: @text1;
+        font-size: 13px;
+    }
+}
+/deep/ .van-switch--on {
+    .van-switch__node {
+        .flex();
+        justify-content: center;
+        &::after {
+            content: '是';
+            font-size: 12px;
+            color: @prim;
+        }
+    }
+}
+</style>

+ 144 - 0
src/views/interact/forum.vue

@@ -0,0 +1,144 @@
+<template>
+    <div>
+        <div class="item" v-for="(n, index) in 20" :key="index">
+            <div class="title">
+                <div class="tag hot"></div>
+                <div class="txt">
+                    #普及急救知识,避免错过黄金抢救时间##普及急救知识,避免错过黄金抢救时间##普及急救知识,避免错过黄金抢救时间#
+                </div>
+            </div>
+            <div class="content">
+                有些急症只有几分钟的黄金抢救时间,若等120专业急救人员来到现场处置,就可能错过生机。我所居住城市的急救中心每年也会为市民无偿进行几期…
+            </div>
+            <div class="opt">
+                <div class="opt-item">
+                    <img class="icon" src="../../assets/interact_icon_hot.png" />
+                    2348
+                </div>
+                <div class="opt-item">
+                    <img class="icon" src="../../assets/interact_icon_comment.png" />
+                    2348
+                </div>
+                <div class="opt-item">
+                    <img class="icon" src="../../assets/interact_icon_like.png" />
+                    2348
+                </div>
+            </div>
+        </div>
+        <div class="btn-fixed btn-edit">
+            <img src="../../assets/icon_edit.png" class="icon" />
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped>
+.item {
+    .flex-col();
+    padding: 20px 16px;
+    position: relative;
+    .title {
+        .flex();
+        align-items: flex-start;
+        line-height: 24px;
+        .tag {
+            width: 18px;
+            height: 18px;
+            min-width: 18px;
+            border-radius: 2px;
+            position: relative;
+            margin-right: 6px;
+            margin-top: 3px;
+            &::after {
+                display: block;
+                font-size: 11px;
+                color: white;
+                text-align: center;
+                line-height: 18px;
+            }
+            &.hot {
+                background: @prim;
+                &::after {
+                    content: '热';
+                }
+            }
+            &.new {
+                background: #ffac34;
+                &::after {
+                    content: '新';
+                }
+            }
+        }
+        .txt {
+            font-size: 16px;
+            color: black;
+            font-weight: bold;
+            line-height: 24px;
+            .ellipsisLn(2);
+        }
+    }
+    .content {
+        color: @text3;
+        line-height: 24px;
+        font-size: 14px;
+        margin-left: 24px;
+        margin-top: 5px;
+        .ellipsisLn(3);
+    }
+    .opt {
+        margin-top: 8px;
+        margin-left: 24px;
+        justify-content: space-between;
+        .flex();
+        .opt-item {
+            .flex();
+            color: @text3;
+            font-size: 13px;
+            width: 70px;
+            .icon {
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
+    &::after {
+        .setBottomLine();
+        left: 16px;
+        right: 16px;
+    }
+}
+.btn-fixed {
+    .flex();
+    justify-content: center;
+    position: fixed;
+    right: 16px;
+    border-radius: 22px;
+    width: 44px;
+    height: 44px;
+    .icon {
+        width: 18px;
+        height: 18px;
+    }
+}
+.btn-call {
+    bottom: calc(132px + var(--safe-bottom));
+    background: #ff9733;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(#ff9733, 10%);
+    }
+}
+.btn-edit {
+    bottom: calc(73px + var(--safe-bottom));
+    background: @prim;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(@prim, 10%);
+    }
+}
+</style>

+ 260 - 0
src/views/interact/official.vue

@@ -0,0 +1,260 @@
+<template>
+    <div>
+        <div class="item" v-for="(n, index) in 20" :key="index">
+            <div class="title">
+                <van-image
+                    class="avatar"
+                    src="https://img01.yzcdn.cn/vant/cat.jpeg"
+                    width="24"
+                    height="24"
+                    fit="cover"
+                    round
+                />
+                <div class="txt">
+                    人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?
+                </div>
+            </div>
+            <div class="answer">
+                <img class="icon" src="../../assets/interact_icon_answer.png" />
+                <div class="content">
+                    <div class="txt">
+                        地球气候变化已经成为了人类健康发展、以及未来生存最大的障碍,除了大气污染、空气中颗粒物超标以外,最严重的…
+                    </div>
+                    <div class="btn-more">查看详情</div>
+                </div>
+            </div>
+        </div>
+
+        <div class="btn-fixed btn-call" @click="showCall = true">
+            <img src="../../assets/icon_call.png" class="icon" />
+        </div>
+        <div class="btn-fixed btn-edit" @click="showNotice = true">
+            <img src="../../assets/icon_edit.png" class="icon" />
+        </div>
+
+        <van-popup v-model="showCall" class="popup-call">
+            <img src="../../assets/interact_banner_call.png" class="banner" />
+            <div class="content">
+                <div class="row">
+                    <div class="label">服务电话:</div>
+                    <div class="value">0791-88529267</div>
+                </div>
+                <div class="row">
+                    <div class="label">电子邮箱:</div>
+                    <div class="value">XXXXX@sina.com</div>
+                </div>
+                <div class="row">
+                    <div class="label">传&#12288;&#12288;真:</div>
+                    <div class="value">0791-XXX88888</div>
+                </div>
+            </div>
+
+            <div class="btn-lg">拨打电话咨询</div>
+        </van-popup>
+
+        <van-popup v-model="showNotice" class="popup-notice" position="bottom">
+            <div class="title">
+                <div class="back" @click="showNotice = false">
+                    <img src="../../assets/nav_icon_back_black.png" />
+                </div>
+                发布须知
+            </div>
+            <div class="content">
+                1、请您自觉遵守中华人民共和国宪法和法律;<br />
+                2、您应对来信内容的真实性、客观性负责,信中不要含有猥亵、色情、造谣诽谤、人身攻击和反政府言论。否则,您将承担由此而引发的一切法律责任;<br />
+                3、不得发表未经证实的消息,亲身经历请注明;<br />
+                4、请勿发表与军民融合无关的留言,以及任何形式的广告和推介企业产品或服务等内容;<br />
+                5、请您真实、准确地填写您联系方式的信息,以便与您联系,我们将依法保护您的隐私权,保守您的联系方式等信息秘密;<br />
+                6、您联系方式的信息如不真实、不准确,留言将可予以删除;<br />
+                7、本平台拥有发布、编辑、删除网上留言的权利,凡不符合本须知规定的留言将予以删除;<br />
+                8、如在本平台留言,即表明已阅读并接受了上述各项条款。
+            </div>
+            <div class="btn-wrapper">
+                <div class="btn-lg" @click="$router.push({ name: 'createInteract', query: { type: 'official' } })">
+                    我已知晓且同意须知相关内容
+                </div>
+            </div>
+        </van-popup>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            showCall: false,
+            showNotice: false
+        };
+    }
+};
+</script>
+<style lang="less" scoped>
+.item {
+    margin-top: 20px;
+    position: relative;
+    padding-bottom: 20px;
+    &::after {
+        .setBottomLine();
+        left: 16px;
+        right: 16px;
+    }
+    &:last-child {
+        &::after {
+            content: none;
+        }
+    }
+    .title {
+        .flex();
+        align-items: flex-start;
+        .avatar {
+            min-width: 24px;
+            margin-left: 16px;
+        }
+        .txt {
+            font-weight: bold;
+            font-size: 16px;
+            color: black;
+            line-height: 24px;
+            margin-left: 6px;
+            .ellipsisLn(2);
+            margin-right: 16px;
+        }
+    }
+    .answer {
+        .flex();
+        align-items: flex-start;
+        margin-top: 15px;
+        .icon {
+            width: 26px;
+            height: 26px;
+            margin-left: 14px;
+        }
+        .content {
+            .flex-col();
+            margin: 8px 16px 0 6px;
+            background: @bg;
+            padding: 10px 12px;
+            border-radius: 0px 16px 16px 16px;
+            .txt {
+                font-size: 16px;
+                color: black;
+                line-height: 26px;
+                .ellipsisLn(3);
+            }
+            .btn-more {
+                color: @prim;
+                font-size: 13px;
+                margin-top: 6px;
+                line-height: 22px;
+                &:active {
+                    color: fade(@prim, 60%);
+                }
+            }
+        }
+    }
+}
+.btn-fixed {
+    .flex();
+    justify-content: center;
+    position: fixed;
+    right: 16px;
+    border-radius: 22px;
+    width: 44px;
+    height: 44px;
+    .icon {
+        width: 18px;
+        height: 18px;
+    }
+}
+.btn-call {
+    bottom: calc(132px + var(--safe-bottom));
+    background: #ff9733;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(#ff9733, 10%);
+    }
+}
+.btn-edit {
+    bottom: calc(73px + var(--safe-bottom));
+    background: @prim;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(@prim, 10%);
+    }
+}
+.popup-call {
+    border-radius: 12px;
+    width: 300px;
+    .flex-col();
+    align-items: center;
+    .banner {
+        width: 100%;
+        height: auto;
+    }
+    .content {
+        font-size: 16px;
+        color: black;
+        line-height: 32px;
+        margin-top: 20px;
+        .flex-col();
+        .row {
+            .flex();
+            .label {
+                width: 86px;
+            }
+            .value {
+            }
+        }
+    }
+    .btn-lg {
+        margin: 44px auto 40px auto;
+        width: 230px;
+    }
+}
+.popup-notice {
+    .flex-col();
+    .title {
+        height: 65px;
+        .flex();
+        justify-content: center;
+        font-size: 16px;
+        color: black;
+        font-weight: bold;
+        position: relative;
+        .back {
+            position: absolute;
+            left: 0;
+            top: 0;
+            height: 100%;
+            padding: 0 16px;
+            .flex();
+            justify-content: center;
+            img {
+                width: 24px;
+                height: 24px;
+            }
+        }
+        &::after {
+            .setBottomLine();
+            left: 16px;
+            right: 16px;
+        }
+    }
+    .content {
+        padding: 10px 16px;
+        font-size: 14px;
+        color: black;
+        line-height: 26px;
+        position: relative;
+        &::after {
+            .setBottomLine();
+            left: 16px;
+            right: 16px;
+        }
+    }
+    .btn-wrapper {
+        padding: 10px 0 calc(6px + var(--safe-bottom)) 0;
+        .flex();
+        justify-content: center;
+    }
+}
+</style>

+ 93 - 0
src/views/interact/qa.vue

@@ -0,0 +1,93 @@
+<template>
+    <div>
+        <div class="item" v-for="(item, index) in 20" :key="index">
+            <div class="title">人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?人类未来如何逆转全球变暖?</div>
+            <div class="info">
+                <van-image
+                    class="avatar"
+                    src="https://img01.yzcdn.cn/vant/cat.jpeg"
+                    width="20"
+                    height="20"
+                    fit="cover"
+                    round
+                />
+                <div class="name">Stella Simpson</div>
+                <div class="time">5分钟前</div>
+                <div class="num">5 回答</div>
+            </div>
+        </div>
+        <div class="btn-fixed btn-edit">
+            <img src="../../assets/icon_edit.png" class="icon" />
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped>
+.item {
+    .flex-col();
+    padding: 20px 16px 22px 16px;
+    position: relative;
+    &::after {
+        .setBottomLine();
+        left: 16px;
+        right: 16px;
+    }
+    .title {
+        font-size: 16px;
+        color: black;
+        line-height: 24px;
+        font-weight: bold;
+        .ellipsisLn(2);
+    }
+    .info {
+        margin-top: 12px;
+        .flex();
+        color: @text3;
+        font-size: 13px;
+        .avatar {
+        }
+        .name {
+            margin-left: 6px;
+        }
+        .time {
+            margin-left: 16px;
+            flex-grow: 1;
+        }
+    }
+}
+.btn-fixed {
+    .flex();
+    justify-content: center;
+    position: fixed;
+    right: 16px;
+    border-radius: 22px;
+    width: 44px;
+    height: 44px;
+    .icon {
+        width: 18px;
+        height: 18px;
+    }
+}
+.btn-call {
+    bottom: calc(132px + var(--safe-bottom));
+    background: #ff9733;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(#ff9733, 10%);
+    }
+}
+.btn-edit {
+    bottom: calc(73px + var(--safe-bottom));
+    background: @prim;
+    box-shadow: 0px 6px 12px -2px rgba(191, 22, 22, 0.08);
+    &:active {
+        background: shade(@prim, 10%);
+    }
+}
+</style>