入门学习使用museui开发移动端学习系统。界面包括登录页、注册页、课程知识地图页(首页)、课程知识图谱页、学习资源页、交流讨论专区、个人中心。

界面展示如下:

                             

       

首先,项目目录见下图:

【main.js】: 项目的核心文件,实例化vue对象,引入项目中使用到的插件/工具和路由

项目中使用了museui、axios(处理http请求)、iconfont、vue-ztree(生成文档树)https://www.npmjs.com/package/vue-ztree

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './components/router'
import MuseUI from 'muse-ui';
import 'muse-ui/dist/muse-ui.css';
import axios from 'axios'
import vueztree from 'vue-ztree-2.0/dist/vue-ztree-2.0.umd.min.js'
import 'vue-ztree-2.0/dist/vue-ztree-2.0.css'
import './assets/iconfont/iconfont.css'

Vue.prototype.$axios = axios;
Vue.use(MuseUI);
Vue.use(axios)
Vue.use(vueztree)

Vue.config.productionTip = false


/* eslint-disable no-new */
// 实例化vue对象
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',


})

【App.vue】:项目入口文件

<template>
  <div id="app">
    <router-view/>
    <!-- 增大底部的可视区域 -->
    <div style="width:100%;height:50px;"></div>
    <!-- bottom-nav 底部导航栏 -->
    <bottom-nav v-show="showNav"></bottom-nav>
  </div>
</template>

<script>
import BottomNav from "./components/BottomNav";
export default {
  name: "App",
  data() {
    return {
      showNav: false
    };
  },
  components: {
    "bottom-nav": BottomNav
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.header_title {
  position: fixed;
  width: 100%;
  left: 0;
  top: 0;
  z-index: 1000;
}
</style>

其中,【BottomNav.vue】为底部导航栏,由于底部导航页在登录成功后的每一个页面均显示,故设置其为公共组件,在【App.vue】中引入。【showNav】为底部导航栏显示与否的标志。


【BottomNav.vue】:底部导航栏

底部导航栏分为四栏,分别对于于不同的路径。注意,底部导航栏的位置需要固定在页面底端。

#nav {
  position: fixed;
  width: 100%;
  left: 0;
  bottom: 0;
  z-index: 1000;
}

<template>
  <!-- 底部导航栏 -->
  <div id="nav">
    <mu-bottom-nav style="background-color: #2196f3;color: hsla(0,0%,100%,.7);">
      <router-link to="/student">
        <mu-bottom-nav-item title="首页" icon="home"></mu-bottom-nav-item>
      </router-link>
      <router-link to="/studyResource">
        <mu-bottom-nav-item title="学习资源" icon="local_library"></mu-bottom-nav-item>
      </router-link>
      <router-link to="/discuss">
        <mu-bottom-nav-item title="讨论交流" icon="record_voice_over"></mu-bottom-nav-item>
      </router-link>
      <router-link to="/PersonalCenter">
        <mu-bottom-nav-item title="个人中心" icon="account_circle"></mu-bottom-nav-item>
      </router-link>
    </mu-bottom-nav>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // shift: "index"
    };
  }
};
</script>

<style lang="less">
.mu-bottom-item-active {
  color: white;
}
a {
  color: rgba(218, 214, 214, 0.7);
}
// 固定底部导航栏位置
#nav {
  position: fixed;
  width: 100%;
  left: 0;
  bottom: 0;
  z-index: 1000;
}
</style>

【Login.vue】登录及注册界面

注册页面包含用户名、邮箱及密码输入框,登录页面包含用户名和密码输入框,可选择管理员或者非管理员角色进行登录,本项目只做了非管理员登录成功界面。

<template>
  <mu-container>
    <mu-tabs :value.sync="active" center color="teal">
      <mu-tab>
        <mu-icon value="person"></mu-icon>登录
      </mu-tab>
      <mu-tab>
        <mu-icon value="person_add"></mu-icon>注册
      </mu-tab>
    </mu-tabs>
    <div class="demo-text" v-if="active === 0">
      <!-- 1.登录窗口 -->
      <mu-form ref="form" :model="user" class="mu-demo-form">
        <mu-form-item label="用户名" prop="username" :rules="usernameRules">
          <mu-text-field v-model="user.username" prop="username"></mu-text-field>
        </mu-form-item>
        <mu-form-item label="密码" prop="password" :rules="passwordRules">
          <mu-text-field type="password" v-model="user.password" prop="password"></mu-text-field>
        </mu-form-item>
        <!-- 是否管理员 -->
        <mu-form-item prop="admin" label>
          <mu-switch v-model="user.admin"></mu-switch>
          <span>管理员</span>
        </mu-form-item>
        <mu-form-item>
          <mu-button color="primary" @click="submitLogin()">提交</mu-button>
          <mu-button @click="clear">重置</mu-button>
        </mu-form-item>
      </mu-form>
    </div>
    <div class="demo-text" v-if="active === 1">
      <!-- 2.注册窗口 -->
      <mu-form ref="form" :model="user" class="mu-demo-form">
        <mu-form-item label="用户名" prop="username" :rules="usernameRules">
          <mu-text-field v-model="user.username" prop="username"></mu-text-field>
        </mu-form-item>
        <mu-form-item label="设置密码" prop="password" :rules="passwordRules">
          <mu-text-field type="password" v-model="user.password" prop="password"></mu-text-field>
        </mu-form-item>
        <mu-form-item label="邮箱" prop="email" :rules="emailRules">
          <mu-text-field v-model="user.email" prop="email"></mu-text-field>
        </mu-form-item>
        <mu-form-item>
          <mu-button color="primary" @click="submitRegister">提交</mu-button>
          <mu-button @click="clear">重置</mu-button>
        </mu-form-item>
      </mu-form>
    </div>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      active: 0,
      usernameRules: [
        { validate: val => !!val, message: "必须填写用户名" },
        { validate: val => val.length >= 2, message: "用户名长度大于2" }
      ],
      passwordRules: [
        { validate: val => !!val, message: "必须填写密码" },
        {
          validate: val => val.length >= 3 && val.length <= 10,
          message: "密码长度大于3小于10"
        }
      ],
      emailRules: [
        { validate: val => !!val, message: "必须填写邮箱" },
        {
          validate: val =>
            /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(
              val
            ),
          message: "输入有效的邮箱"
        }
      ],
      user: {
        admin: false,
        username: "",
        password: "",
        email: ""
      }
    };
  },
  methods: {
    // 提交登录
    submitLogin() {
      this.$refs.form.validate().then(result => {
        if (result) {
          axios.post("/api/loginUser/", this.user).then(res => {
            // console.log("输出response.data", res.data);
            if (res.data.status === 200) {
              if (this.user.admin) {
                this.$router.push({ path: "/admin" });
              } else {
                // 登录成功
                this.$parent.showNav = true;
                this.$router.push({ path: "/student" });
              }
            } else {
              alert(res.data.msg);
            }
          });
        }
      });
    },
    // 提交注册账号
    submitRegister() {
      this.$refs.form.validate().then(result => {
        if (result) {
          axios.post("/api/registerUser", this.user).then(res => {
            console.log("输出response.data", res.data);
            // 后台校验用户名是否存在
            this.active = 0;
          });
        }
      });
    },

    clear() {
      this.$refs.form.clear();
      this.user = {
        username: "",
        password: "",
        email: ""
      };
    }
  }
};
</script>

<style lang="less">
.mu-demo-form {
  width: 100%;
  max-width: 460px;
}
.mu-form-item-label {
  font-size: 16px;
  line-height: 28px;
  text-align: left;
  font-weight: 600;
}
.demo-text {
  padding: 16px;
  background: #fff;
  p {
    margin: 8px 0;
  }
}
</style>

【Student.vue】课程知识地图页(首页)

主要展示各个课程的学习进度,通过progress进度条方式展示。

<template>
  <mu-container>
    <mu-appbar
      class="header_title"
      style="width: 100%; margin-bottom:15px;"
      title="课程知识地图"
      color="#d81b60"
    ></mu-appbar>
    <div style="width: 100%; margin-bottom:35px;">
      <mu-list class="list" v-for="item in progressData" :key="item.id">
        <mu-list-item>
          <mu-list-item-title>
            <mu-linear-progress mode="determinate" :value="item.currentV" :size="16" color="blue"></mu-linear-progress>
          </mu-list-item-title>
        </mu-list-item>
        <p class="list_desc">{{item.name}}:当前进度:{{item.currentV}}%</p>
        <span class="list_icon">
          <mu-icon size="30" value="arrow_downward"></mu-icon>
          {{item.purpose}}
        </span>
      </mu-list>
      <!-- 复用技术 -->
      <mu-list class="list" @click="goMap">
        <mu-list-item>
          <mu-list-item-title>
            <mu-linear-progress mode="determinate" :value="tech.currentV" :size="16" color="green"></mu-linear-progress>
          </mu-list-item-title>
        </mu-list-item>
        <p class="list_desc">{{tech.name}}:当前进度:{{tech.currentV}}%</p>
      </mu-list>
    </div>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      progressData: [
        {
          id: 0,
          currentV: 10.5,
          name: "物理层",
          purpose: "传输什么"
        },
        {
          id: 1,
          currentV: 20.1,
          name: "透明比特流传输",
          purpose: "用什么传"
        },
        {
          id: 2,
          currentV: 5.9,
          name: "传输介质",
          purpose: "怎么传输"
        },
        {
          id: 3,
          currentV: 30.3,
          name: "传输方案",
          purpose: "影响因素"
        },
        {
          id: 4,
          currentV: 2.5,
          name: "物理带宽",
          purpose: "共享信道"
        }
      ],
      tech: {
        currentV: 43,
        name: "复用技术",
        purpose: "共享信道"
      }
    };
  },
  methods: {
    goMap() {
      this.$router.push({ path: "/map" });
    }
  },
  created() {
    this.$parent.showNav = true;
  }
};
</script>

<style lang="less">
.list {
  margin-top: -1px;
  border: 1px solid #ccc;
  padding-top: 5px;
}
.list_desc {
  font-size: 14px;
  font-weight: 600;
  color: rgb(86, 168, 235);
}
</style>

【Map.vue】课程知识地图学习树页

点击课程知识地图页复用技术可跳转至课程知识图谱页,通过vue-zue生成知识图谱

<template>
  <mu-container>
    <mu-appbar
      class="header_title"
      style="width: 100%; margin-bottom:15px;"
      title="课程知识图谱"
      color="#d81b60"
    ></mu-appbar>
    <vue-ztree
      :list.sync="ztreeDataSource"
      :func="nodeClick"
      :expand="expandClick"
      :contextmenu="contextmenuClick"
      :is-open="true"
    ></vue-ztree>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      msg: "Map界面",
      ztreeDataSource: [
        {
          id: 1,
          name: "复用技术",
          children: [
            {
              id: 12,
              name: "原理",
              url: "0"
            },
            {
              id: 13,
              name: "分类",
              children: [
                {
                  id: 131,
                  name: "时分多路复用",
                  children: [
                    { id: 1311, name: "原理", url: "1" },
                    {
                      id: 1312,
                      name: "分类",
                      children: [{ id: 13121, name: "STDM", url: "2" }]
                    },
                    { id: 1213, name: "应用", url: "3" }
                  ]
                },
                {
                  id: 132,
                  name: "频分多路复用",
                  children: [
                    { id: 1321, name: "原理", url: "4" },
                    {
                      id: 1322,
                      name: "分类",
                      children: [
                        { id: 13221, name: "WDM", url: "5" },
                        { id: 13222, name: "OFDM", url: "6" }
                      ]
                    },
                    { id: 1323, name: "应用", url: "7" }
                  ]
                },
                {
                  id: 133,
                  name: "码分多路复用",
                  children: [
                    { id: 1331, name: "原理", url: "8" },
                    { id: 1332, name: "应用", url: "9" }
                  ]
                }
              ]
            }
          ]
        }
      ]
    };
  },
  methods: {
    // 点击节点
    nodeClick: function(m) {
      console.log(" 点击节点:", JSON.parse(JSON.stringify(m)));
    },
    // 右击事件
    contextmenuClick: function(m) {
      console.log("右击事件:", m);
      console.log("触发了自定义的contextmenuClick事件");
    },
    // 点击展开收起
    expandClick: function(m) {
      console.log(JSON.parse(JSON.stringify(m)));
      // 点击异步加载
      if (m.isExpand) {
        // 动态加载子节点, 模拟ajax请求数据
        // 请注意 id 不能重复哦。
        if (m.hasOwnProperty("children")) {
          m.loadNode = 1; // 正在加载节点
          setTimeout(() => {
            m.loadNode = 2; // 节点加载完毕
            m.isFolder = !m.isFolder;
            m.children.push({
              id: +new Date(),
              name: "动态加载节点1",
              path: "",
              clickNode: false,
              isFolder: false,
              isExpand: false,
              loadNode: 0,
              children: [
                {
                  id: +new Date() + 1,
                  name: "动态加载末节点",
                  path: "",
                  clickNode: false,
                  isExpand: false,
                  isFolder: false,
                  loadNode: 0
                }
              ]
            });
          }, 1000);
        }
      }
    }
  },
  created() {
    this.$parent.showNav = true;
  }
};
</script>

<style lang="less">
.container {
  overflow: hidden;
}
</style>

【StudyResource】:学习资源页

学习资源页设置了自定义过滤器【snippet】,作用是使得显示字数为100以内。使用mu-expansion-panel面板展示学习资源,图片通过mu-card-media展示。

<template>
  <!-- 学习资源界面 -->
  <mu-container>
    <mu-appbar
      class="header_title"
      style="width: 100%; margin-bottom:15px;"
      title="学习资源"
      color="#d81b60"
    ></mu-appbar>
    <mu-expansion-panel v-for="(item,index) in resources" :key="index">
      <div class="title" slot="header">{{item.title}}</div>
      <mu-card-media v-if="item.imgName">
        <img :src="item.imgName">
      </mu-card-media>
      <div style="width:100%">
        <router-link :to="{path:'/moreResource',query:{resourceIndex:index}}">
          <p class="desc">{{item.content | snippet}}</p>
        </router-link>
      </div>
    </mu-expansion-panel>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      msg: "学习资源界面",
      resources: []
    };
  },
  // 渲染前获取数据源
  created() {
    this.$parent.showNav = true;
    // axios提交数据
    axios
      .post("/api/getResources")
      .then(response => {
        this.resources = response.data.data;
        console.log("学习资源输出:", this.resources);
      })
      // 提交出错
      .catch(response => {
        console.log(response);
      });
  },
  //自定义过滤器
  filters: {
    snippet: function(value) {
      return value.slice(0, 100) + "...";
    }
  }
};
</script>

<style lang="less">
.title {
  font-size: 16px;
  font-weight: 500;
  //   color: rgb(33, 150, 243);
}
.desc {
  color: rgb(58, 135, 187);
  text-align: left;
}
</style>

【MoreResource.vue】学习资源详情页

<template>
  <mu-container>
    <mu-appbar class="header_title" style="width: 100%; margin-bottom:15px;" color="#d81b60">
      学习资源详情
      <mu-button flat slot="right" @click="goBack">
        <mu-icon value="reply" color="white"></mu-icon>
      </mu-button>
    </mu-appbar>
    <div style="margin:14px;">
      <h2 class="study-title">{{item.title}}</h2>
      <mu-divider></mu-divider>
      <mu-card-media v-if="item.imgName">
        <img :src="item.imgName">
      </mu-card-media>
      <div style="width:100%">
        <p class="desc">{{item.content}}</p>
      </div>
      <!-- <div v-if="item.videoName">
        <video id="myVideo" class="video-js" width="100%" height="100%">
        <source src="//vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
      </div>-->
    </div>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      refleftUrl: "",
      startTime: 0,
      item: {},
      rid: this.$route.query.resourceIndex
    };
  },
  methods: {
    goBack() {
      this.$router.go(-1);
    }
  },
  created() {
    this.$parent.showNav = true;
    this.startTime = Date.parse(new Date());
    let resindex = this.$route.query.resourceIndex;
    axios
      .post("/api/getResource", { index: resindex })
      .then(response => {
        if (response.data.status == 200) {
          console.log("获取学习资源详情", response);
          this.item = response.data.data;
          this.refleftUrl = {
            path: "/reflectSelf",
            query: { resourceIndex: resindex }
          };
        } else {
          console.log(response.data.msg);
        }
      })
      .catch(response => {
        console.log(response);
      });
  }

  //   // 开始计时
  //   mounted: function(params) {},
  //   // 统计浏览时长
  //   beforeRouteLeave(to, from, next) {
  //     let currentTimeStamp = Date.parse(new Date());
  //     let interval = (currentTimeStamp - this.startTime) / 1000;
  //     this.axios
  //       .post("/api/submitOnlineTime", { onlineTime: interval })
  //       .then(response => {})
  //       .catch(response => {
  //         console.info(response);
  //       });
  //     next(true);
  //   }
};
</script>

<style lang="less">
.study-title {
  font-size: 17px;
  font-weight: 600;
  margin-top: 68px;
}
</style>

【Discuss.vue】交流讨论专区

交流讨论页功能有:发布帖子,显示帖子,给帖子点赞、踩、评论。

<template>
  <mu-container>
    <mu-appbar
      class="header_title"
      style="width: 100%; margin-bottom:15px;"
      title="交流讨论专区"
      color="#d81b60"
    >
      <!-- 我要发帖按钮 点击打开我要发帖对话框 -->
      <mu-button flat slot="right" @click="openDiscussDialog">
        <mu-icon value="border_color" size="15" color="white"></mu-icon>
      </mu-button>
    </mu-appbar>
    <!-- 发帖显示区域 -->
    <mu-paper :z-depth="1" v-for="(item,index) in posts" :key="index">
      <mu-appbar style="height:35px; font-size:16px;" color="lightBlue400">{{item.theme}}</mu-appbar>
      <div
        style="margin:10px;border:1px solid #d1cdcd;padding:0px 10px;border-radius:4px;"
        v-for="(postItem, i) in item.data"
        :key="i"
      >
        <h3>{{postItem.title}}</h3>
        <p style="color:gray; font-size:8px;">作者: {{postItem.author}} {{postItem.createdTime}}</p>
        <mu-card-media v-if="postItem.image" title sub-title>
          <img :src="postItem.image">
        </mu-card-media>
        <p>{{postItem.content}}</p>
        <!-- 点赞、踩、评论功能 -->
        <div class="dicuss-icon" :itemIndex="postItem.id" :typeIndex="index" :listIndex="i">
          <span @click="commentUp">
            <i class="iconfont" style="color:#49bb10">&#xe627;</i>
          </span>
          <span style="color:black;">{{postItem.upCount}}</span>
          &nbsp;&nbsp;&nbsp;
          <span href="javascript:;" @click="commentDown">
            <i class="iconfont" style="color:#e26ba7">&#xe68f;</i>
          </span>
          <span style="color:black;">{{postItem.downCount}}</span>
          &nbsp;&nbsp;&nbsp;
          <span href="javascript:;" @click="commentAdd">
            <i class="iconfont" style="color:#299fce">&#xe617;</i>
          </span>
          <span style="color:black;">{{postItem.commentCount}}</span>
        </div>
        <!-- 评论列表 -->
        <mu-list style="border-top:1px solid #d1cdcd;padding-top:10px;">
          <div v-for="(itemComment, ic) in postItem.comments" :key="ic">
            <img class="commemtImg" src="../assets/images/girl.png">
            <div class="commentContent">
              <div
                class="commentContent-desc"
              >{{itemComment.createdTime}}&nbsp;{{itemComment.commenter.name}}&nbsp;发表了评论</div>
              <div>
                <span>{{itemComment.content}}</span>
              </div>
            </div>
          </div>
        </mu-list>
      </div>
    </mu-paper>

    <!-- 发帖对话框 -->
    <mu-dialog title="我要发帖" width="360" :open.sync="createDicussVisible">
      <mu-col gutter>
        <mu-col span="12" lg="4" sm="6">
          <mu-form
            ref="form"
            :model="form"
            class="mu-demo-form"
            :label-position="labelPosition"
            label-width="100"
          >
            <mu-form-item prop="select" label="请选择发帖主题" :rules="selectRules">
              <mu-select v-model="form.select">
                <mu-option
                  v-for="(option,index) in options"
                  :key="index"
                  :label="option"
                  :value="index"
                ></mu-option>
              </mu-select>
            </mu-form-item>
            <mu-form-item prop="input" label="输入帖子标题" :rules="inputRules">
              <mu-text-field v-model="form.input"></mu-text-field>
            </mu-form-item>

            <mu-form-item prop="textarea" label="输入帖子内容" :rules="textareaRules">
              <mu-text-field multi-line :rows="3" :rows-max="6" v-model="form.textarea"></mu-text-field>
            </mu-form-item>

            <!-- 是否添加图片 -->
            <mu-checkbox label="添加图片资源" v-model="addImgFile"></mu-checkbox>
            <!-- 显示添加的图片 -->
            <div v-if="addImgFile">
              <label for="file" style="width:100%">请在系统中选择一张图片</label>
              <input
                type="file"
                accept="image/*"
                name="file"
                id="file"
                style="display:none"
                @change="preview($event)"
              >
            </div>

            <br>
          </mu-form>
        </mu-col>
      </mu-col>
      <mu-button slot="actions" flat color="primary" @click="submitDicussForm">确定</mu-button>
      <mu-button slot="actions" flat color="red" @click="cancleDicuss">取消</mu-button>
    </mu-dialog>

    <!-- 发表评论对话框 -->
    <mu-dialog title="发表评论" width="360" :open.sync="commentVisible">
      <mu-col gutter>
        <mu-col span="12" lg="4" sm="6">
          <mu-form
            ref="form"
            :model="form"
            class="mu-demo-form"
            :label-position="labelPosition"
            label-width="100"
          >
            <mu-form-item prop="commentText" :rules="commentTextRules">
              <mu-text-field multi-line :rows="1" :rows-max="6" v-model="form.commentText"></mu-text-field>
            </mu-form-item>
          </mu-form>
        </mu-col>
      </mu-col>
      <mu-button slot="actions" flat color="primary" @click="submitComment">确定</mu-button>
      <mu-button slot="actions" flat color="red" @click="cancleComment">取消</mu-button>
    </mu-dialog>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      options: [
        "透明比特流传输",
        "传输介质",
        "传输方案",
        "物理带宽",
        "物理层",
        "复用技术"
      ],
      labelPosition: "top",
      form: {
        input: "",
        select: "",
        textarea: "",
        commentText: ""
      },
      createDicussVisible: false,
      commentVisible: false,
      selectRules: [{ validate: val => !!val, message: "必须选择发帖主题" }],
      inputRules: [
        { validate: val => !!val, message: "必须填写帖子标题" },
        { validate: val => val.length >= 2, message: "帖子标题长度大于2" }
      ],
      textareaRules: [
        { validate: val => !!val, message: "必须填写帖子内容" },
        { validate: val => val.length >= 2, message: "帖子内容长度大于2" }
      ],
      commentTextRules: [
        { validate: val => !!val, message: "必须填写评论内容" },
        { validate: val => val.length >= 2, message: "评论内容长度大于2" }
      ],
      posts: [],
      currentCindex: 0,
      currentType: 0,
      itemIndex: 0,
      typeIndex: 0,
      listIndex: 0,
      addImgFile: "",
      imgUrl: "",
      postImg: ""
    };
  },
  methods: {
    // 点赞功能
    commentUp(event) {
      let objNode = event.target.parentNode.parentNode;
      let typeIndex = parseInt(objNode.getAttribute("typeindex"));
      let listIndex = parseInt(objNode.getAttribute("listindex"));
      this.posts[typeIndex].data[listIndex].upCount += 1;
      let itemIndex = parseInt(objNode.getAttribute("itemIndex"));
      // 上传数据到服务器
      axios
        .post("/api/updateUpCount", {
          itemIndex: itemIndex
        })
        .then(response => {
          console.log("点赞成功:", response);
        })
        .catch(response => {
          console.log(response);
        });
    },
    // 踩功能
    commentDown() {
      let objNode = event.target.parentNode.parentNode;
      let typeIndex = parseInt(objNode.getAttribute("typeindex"));
      console.log("typeIndex", this.typeIndex);
      let listIndex = parseInt(objNode.getAttribute("listindex"));
      this.posts[typeIndex].data[listIndex].downCount += 1;
      let itemIndex = parseInt(objNode.getAttribute("itemIndex"));
      // 上传数据到服务器
      axios
        .post("/api/updateDownCount", {
          itemIndex: itemIndex
        })
        .then(response => {})
        .catch(response => {
          console.log(response);
        });
    },
    // 增加评论
    commentAdd() {
      let objNode = event.target.parentNode.parentNode;
      let typeIndex = parseInt(objNode.getAttribute("typeindex"));
      let listIndex = parseInt(objNode.getAttribute("listindex"));
      this.itemIndex = parseInt(objNode.getAttribute("itemIndex"));
      this.currentCindex = listIndex;
      this.currentType = typeIndex;
      this.commentVisible = true;
    },

    // 点击打开“我要发帖”对话框
    openDiscussDialog() {
      this.createDicussVisible = true;
    },
    // 点击关闭“我要发帖”对话框,取消发帖
    cancleDicuss() {
      this.createDicussVisible = false;
    },
    // 提交“我要发帖”内容
    submitDicussForm() {
      this.$refs.form.validate().then(result => {
        if (result) {
          let formData = new FormData();
          formData.append("theme", this.form.select);
          formData.append("title", this.form.input);
          formData.append("content", this.form.textarea);
          formData.append("postImg", this.postImg);
          axios
            .post("/api/submitPost", formData)
            .then(response => {
              this.createDicussVisible = false;
              console.log(response);
              alert(response.data.msg);
            })
            .catch(response => {
              console.log(response);
            });
        }
      });
    },
    // “发表评论”对话框 点击提交评论
    submitComment() {
      this.$refs.form.validate().then(result => {
        if (result) {
          let commentText = this.form.commentText;
          this.posts[this.currentType].data[
            this.currentCindex
          ].commentCount += 1;
          this.posts[this.currentType].data[
            this.currentCindex
          ].comments.unshift({
            commenter: {
              userImg: require("../assets/images/girl.png"),
              name: sessionStorage.getItem("userName")
            },
            content: commentText
            // createdTime: "2019-01-12 09:30:12  "
          });
          // 关闭提交框
          this.commentVisible = false;
          // 上传数据到服务器
          axios
            .post("/api/submitCommentData", {
              content: commentText,
              itemIndex: this.itemIndex
            })
            .then(response => {
              alert(response.data.msg);
            })
            .catch(response => {
              console.log(response);
            });
        }
      });
    },
    // 点击关闭“发表评论”对话框,取消评论
    cancleComment() {
      this.commentVisible = false;
      this.form.commentText = "";
    },
    getObjectURL(file) {
      let url = null;
      if (window.createObjectURL != undefined) {
        // basic
        url = window.createObjectURL(file);
      } else if (window.webkitURL != undefined) {
        // webkit or chrome
        url = window.webkitURL.createObjectURL(file);
      } else if (window.URL != undefined) {
        // mozilla(firefox)
        url = window.URL.createObjectURL(file);
      }
      return url;
    },

    preview(event) {
      let files = document.getElementById("file").files[0];
      let imgDataUrl = this.getObjectURL(files);
      this.imgUrl = imgDataUrl;
      this.postImg = files;
    }
  },
  // 页面渲染前获取交流讨论历史数据
  created() {
    this.$parent.showNav = true;
    axios
      .post("/api/getPostData")
      .then(response => {
        this.posts = response.data.data;
        console.log("输出this.posts", this.posts);
      })
      .catch(response => {
        console.log(response);
      });
  }
};
</script>

<style lang="less">
.dicuss-icon {
  text-align: right;
}

.commemtImg {
  position: absolute;
  left: 0;
  width: 50px;
}
.commentContent {
  text-align: left;
  margin-left: 73px;
  border: 1px solid gray;
  padding: 10px;
  border-radius: 6px;
  background-color: #faf7f9;
  margin-bottom: 20px;
}
.commentContent-desc {
  border-bottom: 1px solid #e2cdcd;
  font-size: 10px;
  margin-bottom: 10px;
}

//小箭头
.commentContent::before {
  content: "";
  position: absolute;
  // top: 26px;
  left: 68px;
  width: 9px;
  height: 9px;
  border: 1px solid gray;
  transform: rotate(45deg);
  border-right: transparent;
  border-top: transparent;
  background: #faf7f9;
}
</style>

【PersonalCenter.vue】: 个人中心

个人中心页展示个人信息及测试、反思、发帖和评论情况。

<template>
  <mu-container>
    <mu-appbar
      class="header_title"
      style="width: 100%; margin-bottom:15px;"
      title="个人中心"
      color="#d81b60"
    ></mu-appbar>
    <!-- 顶部用户信息 -->
    <mu-row gutter>
      <mu-col span="4">
        <div class="grid-cell">
          <img style="width:60px;height:60px;" src="../assets/images/girl.png">
        </div>
      </mu-col>
      <mu-col span="8">
        <div class="grid-cell">
          <mu-list>
            <mu-list-item button :ripple="false">
              <mu-list-item-action>
                <mu-icon value="perm_identity"></mu-icon>
              </mu-list-item-action>
              <mu-list-item-title>{{user.name}}</mu-list-item-title>
            </mu-list-item>
            <mu-list-item button :ripple="false">
              <mu-list-item-action>
                <mu-icon value="mail_outline"></mu-icon>
              </mu-list-item-action>
              <mu-list-item-title>{{user.email}}</mu-list-item-title>
            </mu-list-item>
          </mu-list>
        </div>
      </mu-col>
    </mu-row>
    <!-- 最近活动 -->
    <h3 style="text-align:left; padding-left:10px;">最近的活动</h3>
    <mu-divider></mu-divider>
    <mu-tabs :value.sync="active1" inverse color="secondary" text-color="rgba(0, 0, 0, .54)" center>
      <mu-tab>测试</mu-tab>
      <mu-tab>反思</mu-tab>
      <mu-tab>发帖</mu-tab>
      <mu-tab>评论</mu-tab>
    </mu-tabs>
    <mu-divider></mu-divider>
    <!-- 测试 -->
    <div class="demo-text" v-if="active1 === 0">
      <div v-if="testList.length > 0" style="text-align:left">
        <div
          v-for="(titem,index) in testList"
          :key="index"
          style="border:1px solid rgb(235, 228, 228);padding:5px 10px;border-radius:4px;margin:10px 0px;"
        >
          <h3
            style="border:0px solid gray; background:#e9f6f9;width:100%;height:30px;line-height:30px;border-radius:2px;"
          >测试{{index+1}}:得分:{{titem.score}} 总分:{{titem.fullScore}}</h3>
          <h4 class="customTitle">开始时间:{{titem.startTime}}</h4>
          <h4 class="customTitle">交卷时间:{{titem.endTime}}</h4>
          <h4 class="customTitle">正确率:{{titem.score * 100 / titem.fullScore}}%</h4>
          <mu-row>
            <!-- 查看错题、重新测试、新建测试页面暂时没写 -->
            <mu-col span="4">
              <router-link class="test-router-link" to="#">查看错题</router-link>
            </mu-col>
            <mu-col span="4">
              <router-link class="test-router-link" to="#">重新测试</router-link>
            </mu-col>
            <mu-col span="4">
              <router-link class="test-router-link" to="#">新建测试</router-link>
            </mu-col>
          </mu-row>
        </div>
      </div>
      <router-link class="test-router-link" to="#" v-else>还没有任何测试哦,赶紧测试一下吧!</router-link>
    </div>
    <!-- 反思 -->
    <div class="demo-text" v-if="active1 === 1">
      <div v-if="reflectList.length > 0" style="text-align:left">
        <div
          v-for="(item,index) in reflectList"
          :key="index"
          style="border:1px solid rgb(235, 228, 228);padding:5px 10px;border-radius:4px;margin:10px 0px;"
        >
          <h3
            style=" text-align:center; border:0px solid gray; background:#e9f6f9;width:100%;height:30px;line-height:30px;border-radius:2px;"
          >{{item.title}}</h3>
          <h4 class="customTitle">{{item.content}}</h4>
          <h4 class="customTitle" style="color:red; font-size:10px;">等待管理员评定反思分数!</h4>
        </div>
      </div>
      <router-link class="test-router-link" to="/discuss" v-else>还没有任何反思,赶紧去学习反思吧!</router-link>
    </div>
    <!-- 发帖 -->
    <div class="demo-text" v-if="active1 === 2">
      <div v-if="postList.length > 0">
        <div
          v-for="(item,index) in postList"
          :key="index"
          style="border:1px solid rgb(235, 228, 228);padding:5px 10px;border-radius:4px;margin:10px 0px;"
        >
          <h3>{{item.title}}</h3>
          <p class="customTitle">{{item.content}}</p>
          <router-link to="/discuss" style="margin-right:-245px; color:#42797d">继续发帖</router-link>
        </div>
      </div>

      <router-link class="test-router-link" to="#" v-else>还没有发表过自己的想法哦,赶紧去发帖吧!</router-link>
    </div>
    <!-- 评论 -->
    <div class="demo-text" v-if="active1 === 3">
      <div v-if="commentList.length > 0" style="text-align:center">
        <div
          v-for="(item,index) in commentList"
          :key="index"
          style="border:1px solid rgb(235, 228, 228);padding:5px 10px;border-radius:4px;margin:10px 0px;"
        >
          <h3>{{item.content}}</h3>
          <p>{{item.createdTime}}</p>
          <router-link to="/discuss" style="margin-right:-245px; color:#42797d">继续评论</router-link>
        </div>
      </div>
      <router-link class="test-router-link" to="#" v-else>还没有评论过别人,赶紧去和别人互动吧!</router-link>
    </div>
  </mu-container>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      active1: 0,
      user: {
        name: "leimiao",
        email: "12233@ds.com"
      },
      levelSize: 2,
      testList: [
        // {
        //   score: 90,
        //   fullScore: 120,
        //   startTime: "2019-02-05 12:05:11",
        //   endTime: "2019-02-05 12:15:11",
        //   errorRate: "5%"
        // }
      ],
      // 反思
      reflectList: [],
      // 发帖
      postList: [],
      // 评论
      commentList: []
    };
  },
  created() {
    this.$parent.showNav = true;
    // 请求用户信息
    axios
      .post("/api/getUserInfo")
      .then(response => {
        this.user = response.data.userInfo;
      })
      .catch(response => {
        console.log(response);
      });

    // 请求考试数据
    axios
      .post("/api/getMyTestData")
      .then(response => {
        this.testList = response.data.testList;
      })
      .catch(response => {
        console.log(response);
      });
    // 请求反思数据
    axios
      .post("/api/getMyReflectData")
      .then(response => {
        this.reflectList = response.data.reflectList;
        console.log("请求反思数据", this.reflectList);
      })
      .catch(response => {
        console.log(response);
      });

    // 请求发帖数据
    axios
      .post("/api/getMyPostData")
      .then(response => {
        this.postList = response.data.postList;
      })
      .catch(response => {
        console.log(response);
      });

    // 请求评论数据
    axios
      .post("/api/getMyCommentData")
      .then(response => {
        this.commentList = response.data.commentList;
      })
      .catch(response => {
        console.log(response);
      });
  }
};
</script>

<style lang="less">
.grid-cell {
  border-radius: 4px;
  height: 86px;
  background: transparent;
  padding-top: 20px;
}
.mu-list {
  padding: 0px;
}
.mu-item {
  height: 25px;
}
.demo-text {
  padding: 16px;
  background: #fff;
  p {
    margin: 8px 0;
  }
}
.test-router-link {
  color: #42797d;
}
</style>

【router】-->【index.js】路由配置

import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Admin from '@/components/Admin'
import Student from '@/components/Student'
import Map from '@/components/Map'
import Discuss from '@/components/Discuss'
import StudyResource from '@/components/StudyResource'
import PersonalCenter from '@/components/PersonalCenter'
import MoreResource from '@/components/MoreResource'


Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Login',
      component: Login
    },
    {
      path: '/admin',
      name: 'Admin',
      component: Admin
    },
    {
      path: '/student',
      name: 'Student',
      component: Student
    },
    {
      path: '/map',
      name: 'Map',
      component: Map
    },
    {
      path: '/discuss',
      name: 'Discuss',
      component: Discuss
    },
    {
      path: '/studyResource',
      name: 'StudyResource',
      component: StudyResource
    },
    {
      path: '/personalCenter',
      name: 'PersonalCenter',
      component: PersonalCenter
    },
    {
      path: '/moreResource',
      name: 'MoreResource',
      component: MoreResource
    }
  ],
  mode: "history"
})

 

Logo

前往低代码交流专区

更多推荐