Springboot+vue 社团管理系统(前后端分离)
zero、项目功能设计图
这个网页是一个社团管理网页,是一个毕设,设计的技术比较简单,写这个博客主要是一
个回忆整理的过程,如果有更好的实现可以在评论区告知。如果发现过程有所错误,也请
不吝斧正。
代码在最后
一、数据库设计(项目准备)
1、建表
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80021
Source Host : localhost:3306
Source Schema : association
Target Server Type : MySQL
Target Server Version : 80021
File Encoding : 65001
Date: 02/12/2020 17:26:43
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for activity
-- ----------------------------
DROP TABLE IF EXISTS `activity`;
CREATE TABLE `activity` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '活动id',
`team_id` bigint(0) NULL DEFAULT NULL COMMENT '举办活动的社团id',
`teamname` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '社团名称',
`activity_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '活动名称',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`address` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '活动地点',
`money` int(0) NULL DEFAULT NULL COMMENT '活动经费',
`description` varchar(4000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '活动介绍',
`summary` varchar(400) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '活动简介',
`photos` varchar(4000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '活动图片',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for apply
-- ----------------------------
DROP TABLE IF EXISTS `apply`;
CREATE TABLE `apply` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '申请id',
`apply_from_id` bigint(0) NULL DEFAULT NULL COMMENT '申请人id',
`apply_username` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '申请人姓名',
`apply_to_id` bigint(0) NULL DEFAULT NULL COMMENT '申请的社团id',
`reason` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '申请理由',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '申请时间',
`contact_way` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '联系方式',
`is_pass` tinyint(0) NULL DEFAULT 0 COMMENT '是否通过申请(0:等待处理 1:拒绝 2:通过)',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for comments
-- ----------------------------
DROP TABLE IF EXISTS `comments`;
CREATE TABLE `comments` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '留言id',
`team_id` bigint(0) NULL DEFAULT NULL COMMENT '社团id',
`student_id` bigint(0) NULL DEFAULT NULL COMMENT '留言的用户id',
`student_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '留言的用户姓名',
`avatar` int(0) NULL DEFAULT NULL COMMENT '用户头像',
`is_manager` tinyint(1) NULL DEFAULT 0 COMMENT '是否是管理员',
`content` varchar(10000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '留言内容',
`support_count` int(0) NULL DEFAULT NULL COMMENT '获得的赞的数量',
`reply_count` int(0) NULL DEFAULT NULL COMMENT '获得的回复的数量',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for create_team
-- ----------------------------
DROP TABLE IF EXISTS `create_team`;
CREATE TABLE `create_team` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
`apply_from_id` bigint(0) NOT NULL COMMENT '申请人id',
`apply_to_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '申请创建的社团名称',
`team_type` tinyint(1) NULL DEFAULT NULL COMMENT '社团类别',
`reason` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '申请理由',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '申请时间',
`contact_way` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '联系方式',
`is_pass` tinyint(1) NULL DEFAULT 0 COMMENT '是否通过该请求 0未处理 1拒绝 2通过',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for reply
-- ----------------------------
DROP TABLE IF EXISTS `reply`;
CREATE TABLE `reply` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '回复id',
`student_id` bigint(0) NULL DEFAULT NULL COMMENT '回复的人的id',
`student_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '回复的用户姓名',
`avatar` int(0) NULL DEFAULT NULL COMMENT '用户头像',
`is_manager` tinyint(1) NULL DEFAULT NULL COMMENT '是否是管理员',
`content` varchar(10000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '回复的内容',
`to_which` bigint(0) NULL DEFAULT NULL COMMENT '针对的评论id',
`support_count` int(0) NULL DEFAULT NULL COMMENT '赞的数量',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '回复时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '学生id',
`s_no` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '学号',
`username` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
`avatar` tinyint(0) NULL DEFAULT 1 COMMENT '头像',
`introduce` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '个人简介',
`is_manager` tinyint(1) NULL DEFAULT 0 COMMENT '是否管理员(0不是 1是社长 2系统管理)',
`phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机',
`email` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`sex` tinyint(1) NULL DEFAULT 0 COMMENT '性别(0男,1女)',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
PRIMARY KEY (`id`, `s_no`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, 'admin', 'admin', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92', 1, '最高权限', 2, '13525415874', '8472193614@qq.com', 0, '2020-12-02 17:26:19');
-- ----------------------------
-- Table structure for student_login_log
-- ----------------------------
DROP TABLE IF EXISTS `student_login_log`;
CREATE TABLE `student_login_log` (
`id` bigint(0) NOT NULL COMMENT 'ID',
`student_id` bigint(0) NOT NULL COMMENT '学生ID',
`user_token` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '登录TOKEN',
`create_time` datetime(0) NOT NULL COMMENT '登录时间',
`oper_type` tinyint(1) NOT NULL COMMENT '操作类型:0-登录,1-登出',
`ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '登录IP',
`user_agent` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '登录UserAgentInfo',
`os_version` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'unknown' COMMENT '操作系统',
`browser_version` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'unknown' COMMENT '浏览器信息'
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for team
-- ----------------------------
DROP TABLE IF EXISTS `team`;
CREATE TABLE `team` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '社团id',
`teamname` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称',
`theme` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '宗旨',
`description` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '简介',
`persons` int(0) NULL DEFAULT 1 COMMENT '人数',
`team_manager_id` bigint(0) NULL DEFAULT NULL COMMENT '社长id',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '创建时间',
`type` tinyint(1) NULL DEFAULT NULL COMMENT '类别(1思想理论 2文艺体育 3就业创业 4公益服务 5学术科研 6网络信息)',
`level` tinyint(1) NULL DEFAULT 0 COMMENT '等级(1->5 每增加10人升星,10人2星)',
`theme_img` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '社团主题图',
`contact` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'QQ群或微信群',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for team_member
-- ----------------------------
DROP TABLE IF EXISTS `team_member`;
CREATE TABLE `team_member` (
`student_id` bigint(0) NULL DEFAULT NULL COMMENT '学生id',
`is_manager` tinyint(1) NULL DEFAULT 0 COMMENT '是否是社长:0不是 1是',
`student_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '学生姓名',
`team_id` bigint(0) NULL DEFAULT NULL COMMENT '社团id',
`team_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '社团名称',
`create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
2、表目录
activity:活动表
apply:申请加入社团的表
comments:评论表
create_team:申请创建社团的表
reply:回复表
student:学生表(就是用户表)
student_login_log:学生登录日志表
team:社团表
team:社团成员表
二、前端编写(vue)
1、搭建Vue框架
①装node.js (自行百度)
②安装vue脚手架 (自行百度)
③创建Vue项目
vue init webpack (项目名称)
然后回车回车,安装路由(instal vue-router)那里选择y,其余的是否开启ESLint语法检测什么的就选n,一路往下就可以了
④运行这个项目
输入 npm install,装了淘宝镜像的可以选择 cnpm install 快一点
安装成功后会有个node_modules目录
完成之后输入
npm run dev
出现这个界面说明项目启动成功
2、放入静态资源(assets文件包括static文件的静态文件)
3、修改配置文件
(1)修改package.json依赖文件
"dependencies": {
"axios": "^0.19.2",
"view-design": "^4.1.3",
"vue": "^2.5.2",
"vue-resource": "^1.5.1",
"vue-router": "^3.0.1",
"vuex": "^3.6.0"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-code-frame": "^6.26.0",
"babel-core": "^6.22.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.11",
"esutils": "^2.0.3",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"has-flag": "^4.0.0",
"html-webpack-plugin": "^2.30.1",
"less": "^3.12.2",
"less-loader": "^7.1.0",
"node-notifier": "^5.1.2",
"node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
"sass": "^1.29.0",
"sass-loader": "^7.3.1",
"sass-resources-loader": "^2.1.1",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"source-list-map": "^2.0.1",
"style-loader": "^2.0.0",
"stylus-loader": "^4.3.0",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
运行npm install 下载依赖
(2)修改build文件夹里的utils.js文件(css编译器 sass)
return {
scss: generateLoaders('sass').concat({
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/assets/css/common.scss')
}
}),
}
(3)修改config/index.js文件(可以编写完后端启动后再回来配置)
//配置代理
proxyTable: {
'/api': {
target: 'http://localhost:8081', //后端请求服务域名和端口
changeOrigin: true, //设置请求头
pathRewrite: {
'^/api': '' //路径重写
}
}
},
运行npm run dev项目依旧能正常运行
(4)配置vuex
在src目录下新建文件store.js
import Vue from "vue"
import Vuex from 'vuex'
Vue.use(Vuex)
const actions = {}
const state = {
token: localStorage.getItem('token') || null
}
const mutations = {
handleToken: (state, token) => {
state.token = token
localStorage.setItem('token', token); //把用户信息存储到localStorage中
},
deleteToken: () => {
localStorage.removeItem('token');
}
}
const getters = {
token: (state) => state.token
}
const store = new Vuex.Store({
actions,
mutations,
state,
getters
})
export default {
store
}
(5)修改main.js文件
// 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 './router'
import axios from 'axios'
import ViewUI from 'view-design';
import store from './store.js'
import 'view-design/dist/styles/iview.css';
import '@/assets/css/global.css'; //全局css
Vue.config.productionTip = false
Vue.prototype.$http = axios;
axios.defaults.withCredentials = true
Vue.use(ViewUI);
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: {
App
},
template: '<App/>'
})
4、编写页面和路由
(1)编写页面组件
index.html(首页)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="static/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="static/favicon.ico" type="image/x-icon" /><!-- 必须 -->
<title>泸职院社团联合会</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
App.vue (app页面)
<template>
<div id="app">
<!-- 顶部导航栏 -->
<div class="app_nav">
<div class="content">
<img class="logo" src="./assets/img/logo.png" alt="泸州职业技术学院社团联合会logo" />
<img src="./assets/img/title.png" alt="泸职院社团联合会" style="with:290px;" />
<ul style="flex:1;">
<li>
<router-link to="/index">首页</router-link>
</li>
<li>
<router-link to="/teams">社团</router-link>
</li>
<li>
<router-link to="/activity">活动</router-link>
</li>
<li>
<router-link to="/about_us">关于我们</router-link>
</li>
</ul>
<Login></Login>
</div>
</div>
<div style="margin-top:80px;">
<router-view />
</div>
<!-- 公众号 -->
<div class="home wechat">
<img
:src="wechat_url"
alt="微信logo"
@mouseover="wechat_url='./static/school_wechat.jpg'"
@mouseleave="wechat_url='./static/wechat_logo.png'"
/>
</div>
<div class="layout-copy">
2020.11.20-至今 © LZY
</div>
<Back-top :height="100"></Back-top>
</div>
</template>
<script>
import Login from "./components/view/login";
export default {
name: "App",
data() {
return {
wechat_url: "./static/wechat_logo.png"
};
},
components: {
Login
}
};
</script>
<style lang="scss">
.app_nav {
position: fixed;
top: 0;
width: 100%;
height: 80px;
box-shadow: 0px 7px 7px -7px #949494;
z-index: 100;
background-color: #eeeeee;
}
.app_nav .content {
width: 80%;
height: 100%;
margin: 0 auto;
display: flex;
align-items: center;
}
.app_nav .content .logo {
width: 80px;
height: 60px;
}
.app_nav .content ul li {
list-style: none; /* 将默认的列表符号去掉 */
padding: 0; /* 将默认的内边距去掉 */
margin: 0; /* 将默认的外边距去掉 */
float: left; /* 往左浮动 */
display: block;
}
.app_nav .content ul li a {
font-size: 20px;
font-weight: bold;
color: $base_color;
margin-left: 20px;
}
.app_nav .content ul li a:hover {
color: #007be7;
}
.home.wechat {
position: fixed;
top: 60%;
right: 0;
z-index: 1000;
cursor: pointer;
}
.layout-copy{
text-align: center;
padding: 10px 0 20px;
color: #9ea7b4;
}
</style>
在components目录里创建view用来登录组件和个人页面组件
view/login.vue (登录组件)
// 登录组件
<template>
<div class="login">
<Spin size="large" fix v-if="spinShow"></Spin>
<Button type="primary" @click="login_modal = true" v-if="!isLogin">登录</Button>
<!-- 登录&注册 -->
<Modal v-model="login_modal" :closable="false" width="420" class-name="vertical-center-modal">
<div class="login_content">
<p>
<span class="login_title">学 号:</span>
<Input
type="text"
placeholder="学号如:18205107"
style="width:200px;"
v-model="userAccount"
@on-blur="getAccount"
@on-focus="showUserNotice=false"
/>
</p>
<p class="notice" v-if="showUserNotice" style="margin-top:3px;">用户名格式错误</p>
<p>
<span class="login_title">密 码:</span>
<Input
type="password"
placeholder="如123456"
maxlength="16"
style="width:200px;"
v-model="password"
password
@on-blur="getPassword"
@on-focus="showPasswordNotice=false"
/>
</p>
<p class="notice" v-if="showPasswordNotice" style="margin-top:3px;">密码过短</p>
<!-- 注册时显示 -->
<p v-if="isRegister">
<span class="login_title">确认密码:</span>
<Input
type="password"
password
maxlength="16"
style="width:200px;"
v-model="surePassword"
@on-blur="getSurePassword"
@on-focus="showPasswordSameNotice=false"
/>
</p>
<p class="notice" v-if="showPasswordSameNotice" style="margin-top:3px;">密码输入不一致</p>
<p v-if="isRegister">
<span class="login_title">用户名:</span>
<Input type="text" maxlength="8" style="width:200px;" v-model="stuName" />
</p>
</div>
<div class="flex justify_content_around" style="margin-top:20px;">
<Button type="primary" style="width:100px;" @click="login" v-if="!isRegister">登录</Button>
<Button type="primary" style="width:100px;" @click="register" v-if="isRegister">注册</Button>
<Button type="primary" ghost style="width:100px;" @click="deleteLogin">取消</Button>
</div>
<div class="flex justify_content_between login_bottom">
<a
href="#"
style="text-decoration: underline;color: #ccc;"
@click="forgetPassword()"
v-if="!isRegister"
>忘记密码?</a>
<a href="#" style="color:#ccc;" @click="showRegister(true)" v-if="!isRegister">注册新用户</a>
<a href="#" style="color:#ccc;" @click="showRegister(false)" v-if="isRegister">返回登录</a>
</div>
<div slot="footer"></div>
</Modal>
<!-- 忘记密码 -->
<Modal
v-model="getPasswordModal"
:closable="false"
width="600"
class-name="vertical-center-modal"
>
<div class="login_content">
<p>
<span class="login_title">学 号:</span>
<Input type="text" placeholder="请输入您的学号..." style="width:200px;" v-model="userAccount" />
</p>
<!-- 发送验证码到邮箱 -->
<div v-if="verifying">
<p>
<span class="login_title">邮 箱:</span>
<Input
type="text"
placeholder="请输入您的邮箱..."
style="width:200px;"
v-model="email"
@on-blur="getEmail"
@on-focus="showEmailNotice=false"
/>
<Button type="primary" style="float:right;" @click="getVerifyCode">获取验证码</Button>
</p>
<p class="notice" v-if="showEmailNotice" style="margin-top:3px;">请输入正确的邮箱!</p>
<!-- 验证码 -->
<p>
<span class="login_title">验证码:</span>
<Input type="text" style="width:200px;" v-model="inputCode" />
</p>
<div style="text-align:center;" class="mt20">
<Button type="primary" style="width:100px;height:40px;" @click="verifyInputCode">验证</Button>
</div>
</div>
<!-- 重置密码 -->
<div v-else>
<p>
<span class="login_title">新密码:</span>
<Input
type="password"
placeholder="如123456"
maxlength="16"
style="width:200px;"
v-model="password"
password
@on-blur="getPassword"
@on-focus="showPasswordNotice=false"
/>
</p>
<p class="notice" v-if="showPasswordNotice" style="margin-top:3px;">密码过短</p>
<p>
<span class="login_title">确认密码:</span>
<Input
type="password"
password
maxlength="16"
style="width:200px;"
v-model="surePassword"
@on-blur="getSurePassword"
@on-focus="showPasswordSameNotice=false"
/>
</p>
<p class="notice" v-if="showPasswordSameNotice" style="margin-top:3px;">密码输入不一致</p>
<div style="text-align:center;" class="mt20">
<Button type="primary" style="width:100px;height:40px;" @click="updataPassword">确定</Button>
</div>
</div>
<div class="flex justify_content_between login_bottom">
<a href="#" style="color:#ccc;" @click="showRegister(false)">返回登录</a>
</div>
</div>
<div slot="footer"></div>
</Modal>
<!-- 已经登录:显示用户信息 -->
<router-link to="/person_center" title="点此进入个人中心">
<div v-if="isLogin" class="person_info flex align_items_centeer">
<img :src="'../../static/avatar_'+user.avatar+'.png'" alt="头像" class="avatar" />
<p class="username">
<img
src="../../assets/img/manager_logo.png"
alt="manager_logo"
style="width:20px;vertical-align: middle;"
v-if="user.isManager>0"
/>
{{user.username}}
</p>
</div>
</router-link>
</div>
</template>
<script>
import StudentService from "../../assets/js/student.js";
import LoginService from "../../assets/js/login.js";
export default {
name: "login",
data() {
return {
login_modal: false,
userAccount: "18205107", //用户名
password: "123456", //密码
showUserNotice: false, //用户名输入提示
showPasswordNotice: false, //密码输入提示
user: {}, //用户信息
isLogin: false, //判断是否登录
register_model: false, //注册
surePassword: "", //二次输入的密码
showPasswordSameNotice: false, //密码输入不一致提示
isRegister: false, //是否是注册
stuName: "", //注册的用户名
getPasswordModal: false, //忘记密码对话框
email: "", //邮箱
showEmailNotice: false, //邮箱格式提示
verifyCode: "", //验证码
inputCode: "", //输入的验证码
verifying: true, //是否处于验证阶段
spinShow: false
};
},
methods: {
// 验证邮箱
getEmail() {
let vm = this;
let regEmail = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
if (vm.email != "" && vm.email != null) {
if (!regEmail.test(vm.email)) {
vm.showEmailNotice = true;
}
}
},
// 验证用户名长短
getAccount() {
// if (this.userAccount.length != 8) {
// this.showUserNotice = true;
// }
},
//验证密码长短
getPassword() {
if (this.password.length < 6 && this.password.length > 0) {
this.showPasswordNotice = true;
}
},
//打开登录页面 / 注册页面
showRegister(isShow) {
this.isRegister = isShow;
this.login_modal = true;
this.getPasswordModal = false;
},
//验证二次输入密码是否一致
getSurePassword() {
if (this.password != this.surePassword) {
this.showPasswordSameNotice = true;
}
},
//登录
login() {
let vm = this;
if (vm.password.length < 6) {
vm.$Message.error("用户名或密码错误");
}
let params = {
sno: vm.userAccount,
password: vm.password
};
LoginService.login(params).then(res => {
if (res.code == 0) {
vm.$store.store.commit("handleToken", res.data.userToken); //把token存入vuex
vm.user = res.data.student; //当前用户信息
vm.$Message.success("欢迎你," + vm.user.username);
vm.login_modal = false;
vm.isLogin = true;
vm.$router.push("/index");
location.reload();
} else {
vm.$Message.error(res.data);
}
});
},
//验证输入信息
validateInput() {
let vm = this;
//用户名判断
if (vm.userAccount.length != 8) {
vm.$Message.error("用户名格式错误!");
return false;
}
//密码判断
if (vm.password.length < 6) {
vm.$Message.error("至少需要六位密码!");
return false;
}
if (this.password != this.surePassword) {
vm.$Message.error("两次密码输入不一致!");
return false;
}
//用户名判断
if (vm.stuName.length == 0) {
vm.$Message.error("用户名不得为空!");
return false;
}
},
//注册
register() {
let vm = this;
let flag = vm.validateInput();
let params = {
sno: vm.userAccount,
username: vm.stuName,
password: vm.password
};
if (flag){
StudentService.register(params).then(res => {
if (res.code == 0) {
//表示插入成功
vm.$Message.success("注册成功,请返回登录!");
} else {
vm.$Message.error(res.data);
}
});
}else {
vm.$Message.error("信息有误!注册失败!");
}
},
// 获取用户信息
getUserInfo() {
let vm = this;
LoginService.getLoginUserInfo().then(res => {
if (res.code == 0) {
vm.user = res.data;
vm.$Message.success("欢迎你," + vm.user.username);
} else {
vm.$Message.error(res.msg);
}
});
},
//取消登录
deleteLogin() {
this.login_modal = false;
},
// 打开忘记密码对话框
forgetPassword() {
this.login_modal = false;
this.getPasswordModal = true;
},
// 获取验证码
getVerifyCode() {
let vm = this;
LoginService.sendEmail(vm.email).then(res => {
if (res.code == 0) {
vm.verifyCode = res.data;
vm.$Message.success("验证码已发送至邮箱,请查收~");
} else {
vm.$Message.error(res.msg);
}
});
},
// 验证 验证码
verifyInputCode() {
let vm = this;
if (vm.inputCode == "") {
vm.$Message.error("请输入验证码!");
} else {
if (vm.inputCode != vm.verifyCode) {
vm.$Message.error("验证失败!");
} else {
vm.$Message.success("验证通过!");
vm.verifying = false;
}
}
},
// 更新密码
updataPassword() {
let vm = this;
vm.spinShow = true;
LoginService.updatePassword(vm.userAccount, vm.password).then(res => {
if (res.code == 0) {
vm.$Message.success("更新成功!");
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
}
},
created() {
// 已经登录
this.isLogin = window.localStorage.getItem("token") != (null || undefined);
if (this.isLogin) {
this.getUserInfo();
}
}
};
</script>
<style lang="scss">
.login_content {
margin: 0 auto;
width: 80%;
}
.login_content .login_title {
display: inline-block;
width: 100px;
font-size: 20px;
}
// 提示
.notice {
font-size: 14px;
color: red;
margin-left: 105px;
}
.login_content p {
margin-top: 20px;
}
.ivu-modal-footer {
border-top: none;
}
.vertical-center-modal {
display: flex;
align-items: center;
justify-content: center;
.ivu-modal {
top: 0;
}
}
.login_bottom {
width: 80%;
margin: 0 auto;
margin-bottom: -20px;
margin-top: 15px;
}
.person_info .avatar {
width: 50px;
height: 50px;
border: 3px solid $base_color;
border-radius: 50%;
}
.person_info .username {
margin-left: 10px;
font-size: 20px;
color: $base_color;
}
</style>
index.vue (首页组件)
// 首页
<template>
<div class="index">
<!-- 轮播 -->
<Carousel autoplay loop :height="450">
<CarouselItem>
<img src="../assets/img/carousel_1.jpg" alt="轮播图1" class="carouselImg" />
</CarouselItem>
<CarouselItem>
<img src="../assets/img/carousel_2.jpg" alt="轮播图2" class="carouselImg" />
</CarouselItem>
<CarouselItem>
<img src="../assets/img/carousel_3.jpg" alt="轮播图3" class="carouselImg" />
</CarouselItem>
<CarouselItem>
<img src="../assets/img/carousel_4.jpg" alt="轮播图4" class="carouselImg" />
</CarouselItem>
</Carousel>
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 信息展示 -->
<div class="main">
<!-- 栅格 -->
<Row type="flex" justify="space-between" class="code-row-bg row1" style="margin-top:20px;">
<!-- 社团列表 -->
<Col span="7">
<Card class="card" style="overflow:hidden;">
<div style="text-align:center;">
<img src="../assets/img/index_item_1.jpg" alt="社团列表" class="cardImg" />
</div>
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>社团世界</span>
<a href="/teams" class="a_button" style="float:right;">MORE</a>
</div>
<ul style="margin-top:10px;">
<li v-for="item in teamList" :key="item.id">
<img src="../assets/img/list_item_head.png" alt="·" style="width:15px;" />
<router-link
:to="{path:'team_detail',query:{itemId:item.id}}"
class="teamname"
>{{item.teamname}}</router-link>
<span style="float:right;">现有人数:{{item.persons}}</span>
</li>
</ul>
</Card>
</Col>
<Col span="7">
<Card class="card">
<div style="text-align:center;">
<img src="../assets/img/index_item_2.jpg" alt="活动列表" class="cardImg" />
</div>
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>热门活动</span>
<a href="/activity" class="a_button" style="float:right;">MORE</a>
</div>
<ul style="margin-top:10px;">
<li v-for="item in activityList" :key="item.id">
<img src="../assets/img/list_item_head.png" alt="·" style="width:15px;" />
<router-link
class="teamname"
:to="{path:'activity_detail',query:{activityId:item.id}}"
>{{item.activityName}}</router-link>
<span class="ac_time">{{item.createTime}}</span>
</li>
</ul>
</Card>
</Col>
<Col span="7">
<Card class="card">
<div style="text-align:center;">
<img src="../assets/img/index_item_3.png" alt="关于我们" class="cardImg" />
</div>
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>关于我们</span>
<a href="/about_us" class="a_button" style="float:right;">MORE</a>
</div>
<div style="width: 90%;margin: 10px auto;">
<p class="about_us_content">
社团联盟系统旨在为高校提供社团管理的平台,为学生、社团管理者、学校管理者提供多方面服务,
规范、高效地管理高校社团。学生可通过系统了解社团、查询社团、加入社团,并可以获取社团通知...
</p>
</div>
</Card>
</Col>
</Row>
</div>
</div>
</template>
<script>
import TeamService from "../assets/js/team";
import ActivityService from "../assets/js/activity";
export default {
name: "index",
data() {
return {
teamList: [], //社团列表
params: {
pageCurrent: 1,
pageSize: 6,
teamname: ""
}, //获取社团列表的参数
spinShow: false, //缓冲显示
ac_params: {
current: 1,
size: 6,
teamId: -1
}, //获取活动列表的参数
activityList: [] //活动列表
};
},
methods: {
//获取社团列表
getTeams() {
this.spinShow = true; //加载图案显示
TeamService.getAllTeam(this.params).then(res => {
if (res.code == 0) {
this.teamList = res.data.records;
} else {
this.$Message.error(res.msg);
}
this.spinShow = false;
});
},
// 获取活动列表
getActivity() {
this.spinShow = true;
ActivityService.getActivity(this.ac_params).then(res => {
if (res.code == 0) {
this.activityList = res.data.records;
} else {
this.$Message.error(res.msg);
}
this.spinShow = false;
});
}
},
created() {
this.getTeams();
this.getActivity();
}
};
</script>
<style lang="scss">
/* 轮播图 */
.index .carouselImg {
width: 100%;
height: 450px;
}
/* 信息卡片 */
.index .main .row1 .card {
width: 100%;
height: 310px;
}
.index .main .row1 .card .cardImg {
height: 100px;
margin: 0 auto;
}
.card .item_title span {
font-size: 20px;
vertical-align: bottom;
font-weight: bold;
margin-left: 10px;
}
.card li .teamname {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: $base_color;
display: inline-block;
width: 60%;
vertical-align: bottom;
}
.card li .ac_time {
width: 80px;
overflow: hidden;
display: inline-block;
height: 20px;
float: right;
}
.about_us_content {
height: 130px;
text-overflow: ellipsis;
overflow: hidden;
text-indent: 2em;
line-height: 26px;
}
</style>
teams.vue (社团页组件)
// 社团页
<template>
<div class="teams">
<!-- 图片 -->
<img src="../assets/img/teams.jpg" alt="社团展示" style="width:100%;height:300px;" />
<!-- 主体 -->
<div class="main">
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="18">
<!-- 社团九宫格 -->
<div>
<div class="flex flex_wrap_wrap justify_content_between">
<Card class="team_card" v-for="item in teamList" :key="item.id">
<router-link :to="{path:'team_detail',query:{itemId:item.id}}">
<div>
<img :src="item.themeImg||'/static/default_team_img.png'" alt="社团图片" />
</div>
<p class="title">{{item.teamname}}</p>
<p class="summary" v-if="item.theme!=null">
<strong>社团理念:</strong>
{{item.theme.substr(0,[34])}}
<span
v-if="item.theme.length>34"
>...</span>
</p>
</router-link>
</Card>
</div>
<div style="margin: 20px auto; text-align:center;">
<Page
:total="total"
:current="params.pageCurrent"
:page-size="params.pageSize"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</Col>
<Col span="5">
<Card class="mt20">
<div class="team_right">
<!-- 社团搜索 -->
<div class="flex align_items_centeer">
<div class="blue_column"></div>
<span class="title">搜索社团</span>
</div>
<Input
type="text"
v-model="params.teamname"
search
enter-button
class="input"
@on-search="getTeams"
/>
<!-- 社团分类 -->
<div class="flex align_items_centeer mt20">
<div class="blue_column"></div>
<span class="title">社团分类</span>
</div>
<div class="mt20">
<CheckboxGroup v-model="types" class="ml10" @on-change="getTeamsByType">
<Checkbox label="1" border>思想理论类</Checkbox>
<Checkbox label="2" border>文艺体育类</Checkbox>
<Checkbox label="3" border>就业创业类</Checkbox>
<Checkbox label="4" border>公益服务类</Checkbox>
<Checkbox label="5" border>学术科研类</Checkbox>
<Checkbox label="6" border>网络信息类</Checkbox>
</CheckboxGroup>
</div>
<!-- 关于我们 -->
<div class="flex align_items_centeer mt20">
<div class="blue_column"></div>
<span class="title">关于我们</span>
</div>
<div class="mt20 ml10" style="text-indent:2em;width:90%;">
社团联盟系统旨在为高校提供社团管理的平台,为学
生、社团管理者、学校管理者提供多方面服务,规范、高效地
管理高校社团。学生可通过系统了解社团、查询社团、加入社团,
并可以获取社团通知,及时了解社团活动。社团管理者可以进行成员管理、通
知发布等。系统管理员可以进行社团管理。
</div>
<!-- 创建社团 -->
<div class="flex align_items_centeer mt20">
<div class="blue_column"></div>
<span class="title">创建社团</span>
</div>
<div class="mt20 flex">
<Button type="primary" class="ml10" @click="showCreateTeamModal=true">创建社团</Button>
</div>
</div>
</Card>
</Col>
</Row>
</div>
<Modal
title="创建社团申请表"
v-model="showCreateTeamModal"
@on-ok="createNewTeam"
@on-cancel="showCreateTeamModal=false"
>
<ul class="create_team">
<li class="create_item">
<span class="create_title">社团名称:</span>
<Input
type="text"
style="width:300px;"
v-model="create_team_params.applyToName"
maxlength="16"
/>
</li>
<li class="create_item">
<span class="create_title">社团类别:</span>
<Select v-model="create_team_params.teamType" style="width:300px;">
<Option v-for="item in teamTypes" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</li>
<li class="create_item">
<span class="create_title">创建理由:</span>
<Input
type="textarea"
v-model="create_team_params.reason"
:rows="4"
:autosize="{maxRows:4,minRows: 4}"
style="width:300px;"
/>
</li>
<li class="create_item">
<span class="create_title">联系方式:</span>
<Input
type="text"
style="width:300px;"
v-model="create_team_params.contactWay"
maxlength="16"
/>
</li>
</ul>
</Modal>
</div>
</template>
<script>
import TeamService from "../assets/js/team";
export default {
name: "teams",
data() {
return {
teamList: [], //社团列表
total: 0, //社团总数
params: {
pageCurrent: 1, //每页显示的数量
pageSize: 9, //社团总数
teamname: "" //搜索框中输入的社团名称
},
types: ["1", "2", "3", "4", "5", "6"], //社团类型
showCreateTeamModal: false, //创建社团申请表
create_team_params: {
applyFromId: 0, //申请人id,后台获取
applyToName: "", //需要创建的社团名称
teamType: 1, //社团类别
reason: "", //创建理由
contactWay: "" //联系方式
},
teamTypes: [
{ value: 1, label: "思想理论类" },
{ value: 2, label: "文艺体育类" },
{ value: 3, label: "就业创业类" },
{ value: 4, label: "公益服务类" },
{ value: 5, label: "学术科研类" },
{ value: 6, label: "网络信息类" }
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.pageCurrent = page;
this.getTeams();
},
/*获取列表项*/
getTeams() {
TeamService.getAllTeam(this.params).then(res => {
if (res.code == 0) {
this.teamList = res.data.records; //社团列表
this.total = res.data.total; //社团总数
} else {
this.$Message.error(res.data);
}
});
},
/*根据社团类型获取社团列表 */
getTeamsByType() {
let str = "";
for (var i = 0; i < this.types.length; i++) {
str += this.types[i];
}
TeamService.getTeamsByType(str).then(res => {
if (res.code == 0) {
this.teamList = res.data.records; //社团列表
this.total = res.data.total; //社团总数
} else {
this.$Message.error(res.data);
}
});
},
/*验证创建社团的请求*/
validateCreateNewTeam() {
let vm = this;
if (vm.create_team_params.applyToName == "") {
vm.$Message.warning("请填写社团名称哦~");
return false;
}
if (vm.create_team_params.reason == "") {
vm.$Message.warning("请填写创建理由哦~");
return false;
}
if (vm.create_team_params.contactWay == "") {
vm.$Message.warning("请填写联系方式方便管理员联系小主哦~");
return false;
}
return true;
},
/*发起一个创建新社团的请求*/
createNewTeam() {
let vm = this;
if (!vm.validateCreateNewTeam()) {
return;
}
TeamService.createNewTeamApply(vm.create_team_params).then(res => {
if (res.code == 0) {
vm.$Message.success("申请已提交,请小主静候佳音~");
} else {
vm.$Message.error(res.msg);
}
});
}
},
created() {
this.getTeams();
}
};
</script>
<style lang="scss">
.team_card {
width: 31%;
height: 220px;
margin-top: 20px;
overflow: hidden;
text-overflow: ellipsis;
}
.team_card img {
height: 80px;
display: block;
margin: 0 auto;
}
.team_card .title {
text-align: center;
font-size: 18px;
font-weight: bold;
color: $base_color;
margin-top: 10px;
}
.team_card .summary {
font-size: 14px;
margin-top: 10px;
}
.team_right .title {
margin-left: 10px;
font-size: 18px;
}
.team_right .input {
margin-top: 10px;
margin-left: 10px;
}
// 创建社团申请表
.create_team li.create_item {
line-height: 50px;
}
.create_team li span.create_title {
display: inline-block;
width: 100px;
}
</style>
activity.vue(活动页组件)
<template>
<div class="activity">
<!-- 图片 -->
<img src="../assets/img/activity.jpg" alt="活动展示" style="width:100%;height:300px;" />
<!-- 缓冲 -->
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 主体 -->
<div class="main">
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="18">
<Row class="condition">
<Card class="mt20">
<ul class="flex">
<li>
<span class="title">举办社团:</span>
<Input type="text" style="width:150px" v-model="params.activity.teamname" />
</li>
<li class="ml10" style="flex:1;">
<span class="title">活动名称:</span>
<Input type="text" style="width:150px" v-model="params.activity.activityName" />
</li>
<li>
<Button type="primary" @click="getActivity">搜索</Button>
</li>
</ul>
</Card>
</Row>
<Card style="margin-top:10px;">
<Timeline>
<TimelineItem v-for="item in activityList" :key="item.id">
<p class="time">{{item.createTime}}</p>
<div class="content" style="line-height:80px;border-bottom:1px dashed #ccc;">
<router-link :to="{path:'activity_detail',query:{activityId:item.id}}">
<div class="flex align_items_centeer">
<img
:src="item.photos||'/static/default_team_img.png'"
alt="活动图片"
class="team_logo"
/>
<span class="ml10 title">{{item.activityName}}</span>
<span class="ml10">举办方:{{item.teamname}}</span>
<span class="ml10 address">举办地点:{{item.address}}</span>
</div>
</router-link>
</div>
</TimelineItem>
</Timeline>
</Card>
<div style="margin: 20px auto; text-align:center;">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</Col>
<Col span="5">
<Card class="mt20">
<div class="flex align_items_centeer">
<div class="blue_column"></div>
<span style="margin-left:10px;font-size:18px;">社团是什么?</span>
</div>
<div class="mt20">
<p style="text-indent:2em;">
社团是有一群有着共同的兴趣和爱好组成的团体,随着我国高等教育的不断发展,
大学生对丰富多彩的校园文化话生活充满了渴望,他们希望在学习之余,可以进行
一系列的社会实践活动,从而在事件中学习提高自己。为了满足心理、文化、生活、
社会需要,他们自发建立了具有一定目标和活动规范的非正式团体————社团。现在的
大学社团正迎来它的黄金时期,各种社团如雨后春笋办涌入大学生的视野。社团是
大学文化的重要组成部分,维系着学校与学生的平衡,肩负着满足大学生业余文化
的需求。
</p>
</div>
<div class="flex align_items_centeer mt20">
<div class="blue_column"></div>
<span style="margin-left:10px;font-size:18px;">活动意义</span>
</div>
<div class="mt20">
<p style="text-indent:2em;">
学生社团已渐渐成为校园文化生活中重要的组成部分,在
我校扮演着校园活动的主力军角色。社团为学生的互动搭造了舞台,
让同学们有了更好的发展空间。而社团的发展要不断地向前,
因此社团的队伍也要不断地壮大,所以招新是社团活动的一个关键步骤。
</p>
</div>
</Card>
</Col>
</Row>
</div>
</div>
</template>
<script>
import ActivityService from "../assets/js/activity";
export default {
name: "activity",
data() {
return {
spinShow: false, //缓冲
activityList: [], //活动列表
params: {
current: 1,
size: 10,
activity: {
teamname: "",
activityName: ""
}
}, //获取活动列表的参数
total: 0 //活动总数
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getActivity();
},
// 获取活动列表
getActivity() {
this.spinShow = true;
ActivityService.getManageActivity(this.params).then(res => {
if (res.code == 0) {
this.activityList = res.data.records;
this.total = res.data.total;
} else {
this.$Message.error(res.msg);
}
this.spinShow = false;
});
}
},
created() {
this.getActivity();
}
};
</script>
<style lang="scss">
.activity .main .team_logo {
width: 50px;
}
// 时间 轴 时间
.activity .main .time {
font-size: 18px;
}
.activity .main .content .title {
font-size: 18px;
color: $base_color;
font-weight: bold;
}
.activity .main .content .address {
color: #888;
}
.activity .main .content:hover {
margin-left: 40px;
transform: scale(1.1);
}
.activity .condition li span.title {
width: 80px;
}
</style>
about_us.vue(关于我们页组件)
// 关于我们
<template>
<div class="about_us">
<!-- 名片 -->
<Card class="header">
<div class="up_bg">
<img src="../assets/img/logo.png" alt />
<h1>泸州职业技术学院社团联合会</h1>
</div>
<div class="down_bg">
<p>
中文名:泸州职业技术学院社团联合会    
宗旨:丰富学生第二课堂,繁荣校园文化,陶冶学生情操,提升学生素质
</p>
<p>
外文名:Luzhou Vocational and Technical
College Association Federation
</p>
</div>
</Card>
<!-- 目录 -->
<Card class="catalogue mt20">
<div class="flex" style="justify-content:space-around">
<a href="#synopsis">①简介</a>
<a href="#preface">②前言</a>
<a href="#department">③部门职能</a>
<a href="#activity">④主办活动</a>
<a href="#music">⑤社联会歌</a>
<a href="#guide">⑥成立指南</a>
</div>
</Card>
<!-- 模块 -->
<Card id="synopsis" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>简介</span>
</div>
<p class="content">
泸州职业技术学院学生社团联合会以“丰富第二课堂、服务学生成才”为宗旨,以立足校园、营造氛围、服务社团、规范发展为工作思路,以规范管理、服务建设、品牌打造为工作方向,充分发挥学生社团的核心作用,着力自身组织建设,规范考核制度,指导、支持并帮助各学生社团开展各种思想性、学术性、创造性、趣味性、服务性的活动。以繁荣校园文化,陶冶学生情操,提高学生素质,丰富学生课余生活,构建和谐校园环境为使命。
</p>
</Card>
<Card id="preface" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>前言</span>
</div>
<p class="content">
 在学院领导高度重视下和学生社团联合会一心一意为为社团谋发展下,目前我院学生社团共有39个(截止至2017年9月),各学生社团按照社团章程独立地开展工作及其相关活动。“明星社团评选表彰”活动和每年度的“求实社团文化艺术节”成为校园文化建设的一道亮丽的风景线,对青年学生素质的提高起到了重要的作用。
<br /> 
另外,随着该校各项基础设施的进一步完善,为社团的发展提供了更为便捷的设施与广阔的空间,在这里,我们真诚期待着与我校各社团同生存、共发展,为促进我校丰富多彩的校园文化生活而贡献自己的力量。
</p>
</Card>
<Card id="department" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>部门职能</span>
</div>
<p class="content">
学生社团联合会直属部门共五个部,它们分别是:秘书处、策划部、传媒部、财务部和外联部。主要职责具体如下:
<br /> 主任(兼学生会副主席)
<br /> 1.积极认真落实好校团委交办的各项工作任务。
<br /> 2.围绕校团委的指导制订社团联合会工作的整体计划。
<br /> 3.了解社联内部的成员和社团的思想动态,并及时与校团委沟通,反馈意见。
<br /> 4.主持社团联合会的日常工作,协调各部之间的关系,并监督各部工作的落实与开展情况。
<br /> 5.认真负责社团经费使用的审批及监督有关人员搞好物品的管理和使用。
<br /> 6.主持社团联合会骨干成员会议,及时传达有关校团委重要指示。
<br /> 7.对有突出贡献或违反有关规定的学生干部提出表扬或批评。
<br /> 8.提名社团联合会干部。
<br /> 9.监督社团联合会全部经费的分配和使用。
<br /> 副主任
<br /> 1.主动配合主席的工作, 监督社团联合会各部门工作开展情况。
<br /> 2.审批社团大型活动申请,赞助申请及活动总策划等。
<br /> 3.代表主席和各部门出席各社团活动及会议。
<br /> 4.负责社团联合会各部工作及物品的保管和使用。
<br /> 5.负责社团联合会经费的使用与管理,做好记账工作。
<br /> 6.主席因故不在时,可行使主席权利,代理主持社团联合会全面工作。
<br /> 7.务必出席每周的干部会议,切实行驶表决权,请假需有正当理由。
<br /> 8.具有重要决策表决权,赞成票超过半数方可通过。
<br /> 秘书处
<br /> 1. 负责社团的评估、常务工作督促、社团负责人的奖励评定。
<br /> 2. 负责组织并完成社团联合会的日常事物(如:会议主持,会 议记录,人员签到,考勤等)。
<br /> 3. 负责社联内部档案文件的整理,归档,立卷工作。
<br /> 4. 完成主任安排的各项工作,包括材料汇总,各项申请表 的分类等。
<br /> 5. 负责学生社团组织的督促、监督工作,围绕学校的校园文化建设。监督社联各职能部门的工作开展情况。
<br /> 6. 与各个社团沟通联系,灵活处理社团日常事务。
<br /> 7. 熟练应用各种办公软件,负责社联文字工作。
<br /> 传媒部
<br /> 1. 全面负责学生社团联合会的宣传工作,并协同各部门完成学生社团联合会各项活动对内对外的宣传报道;
<br /> 2. 负责办好学生社联合会的自媒体、相关新闻报道,加强对校园海报宣传活动的监管,规划和管理学生社团宣传阵地;
<br /> 3. 统筹、协调各学生社团的宣传工作;
<br /> 4. 负责学生社团联合会的书刊、报刊的编辑工作;
<br /> 5. 完成学校、团委、社联交办的其他工作;
<br /> 策划部
<br /> 1.负责各学生社团活动策划书的审批和修改工作,并对各社团的活动开展进行协调,提出建议并做好登记备案;
<br /> 2.策划并指导学生社团联合会组织的大型社团活动,确保活动圆满成功
<br /> 3.根据社联的安排,对相关学生社团活动进行跟进和协调;
<br /> 4.每周定期安排人员在办公室值班,方便社团的成员能够及时递交策划书并审核修改;
<br /> 5.定期给协会策划部做培训,提高协会活动质量;
<br /> 财务部
<br /> 1. 负责社团联合会和各协会的经费收入、审核、使用监督,并为每个协会做好登记,定期向团委,社联检查;
<br /> 2. 定期抽查各协会的经费使用情况,保证经费的正常使用;
<br /> 3. 负责监督各部门的日常开支报销;
<br /> 4. 负责社联公共财产的维护和管理;
<br /> 外联部
<br /> 1. 加强社联与社团以及其它校内组织的交流与合作,促进相互之间的共同发展;
<br /> 2. 面向社会公关,提高学校,社团联与社团的知明度和美誉度;
<br /> 3. 负责联系,沟通其他高等院校,组织和开展各种联谊活动并保障其顺利有进行;
<br /> 4. 展现我校风采和学生社团联合会的品牌形象;
<br /> 5. 寻找各种商家与其联系,谈判争取赞助,筹集经费提高学生活动的水平和质量;
<br /> 6. 认真对待学校,团委,社团联安排的工作;
</p>
</Card>
<Card id="activity" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>主办活动</span>
</div>
<p class="content">
 由泸州职业技术学院学生社团联合会主导、各社团协办的诸多传统大型活动,塑造了青春健康、
昂扬向上的社团文化。每学年社联都开展了“社团风采月”,“社团文化节”,“校园文化节”,“
十佳社团”评估、答辩及网上投票,A级社团评定,社团干部培训会,迎新晚会,社团统一招新
,社联干部招聘会,权益接待日,新闻发布会,社团活动竞标会,文化节设计大赛,武汉高校歌
手大赛,武汉高校系列征文大赛,武汉高校外联联席会议,并参与了“大学开放日”等一系列大型
全校性的活动。
<br /> 社团文化节
<br /> 每年10月中下旬至11月,一年一度的泸州职业技术学院社团文化节更是全校师生共同期
待的文化盛宴,是社联携手全校所有社团举办一次独具特色、继往开来的盛会,一直以来受到校党
委、校团委的高度重视和全校各部门的大力支持,同时也逐渐受到社会各界特别是媒体的普遍关
注。举办社团文化节的目的在于整合现有的校园文化活动内容,集中在一段时间内形成声势和规
模,展示校园社团风采,提高会员的综合素质,打造新的社团品牌活动,创造有利于学生健康成长
的校园氛围。
<br /> 社团文化节一般由开幕式、诸多社团活动、闭幕式三个环节组成。各届文化节精
彩纷呈,特色各异:
<br /> 1.2003年第一届社团文化节以笛箫协会专场晚会开幕、以韵苑体育馆晚会闭幕,
期间有艺术设计协会大型作品展以及写生展、夏雨诗社诗会、喻园舞社锐舞专场舞会等特色活动;
<br /> 2.2004年第二届社团文化节以十佳社团、优秀社团和会旗、会标、文化衫征集
大赛的颁奖晚会开幕、以“超级盛典2005”新年晚会闭幕,闭幕式从2004年12月31日19:30开始
持续到2005年1月1日00:15,一起期待2005年第一分钟的到来。期间有笛箫协会十周年会庆系
列活动、武汉高校跆拳道联赛、电子竞技大赛(HEGC)等特色活动;
<br /> 3.2005年第三届社团文化节以西边篮球场游园会、韵苑体育馆“蓝色海洋——盛大
之夜”专题晚会开幕,以社团工作年度报告会闭幕。文化节由快乐之旅、健康之旅、成长之旅三
大主题构成,精品节目有:高等学校学生事务国际学术研讨会社团展示暨第三届社团文化节之“
灵动世界”社团风采展、第二届万圣节假面舞会、2005“快乐人生微笑心灵”之夜、模拟法庭等等。
<br /> 4.2006年第四届社团文化节以“青春流韵,梦翔喻园”为主题,以大雨中的“梦翔之
夜”大型露天晚会开幕,子活动分为分为“智之明,艺之魂,德之光,体之魄”四个环节,期间有新
生杯辩论赛、武汉市社团嘉年华、校园趣味长跑等专题活动。
<br /> 5.2007年第五届社团文化节以“放歌青春,畅想奥运”为主题,融合社团风采Sho
w、奥运主题园、互动游戏休闲吧的大型嘉年华,游园狂欢盛典和梦幻的虚拟童话城堡,在韵苑
足球场举办了为期两天的开幕式。文化节由“CreatYourWorld”科技创新类社团活动、“天地·人
和”科普公益类社团活动、“hust成长-ing”理论研究类社团活动、“箭在弦上”技能培养类社团活
动、“文化盛宴”文学艺术类社团活动、“放飞的理想·青春的活力”体育休闲类社团活动构成。期
间有计算机协会仿真机器人足球赛、碧水蓝天协会垃圾艺术品展、法律协会八校联合“德赛金台杯
”未来律师大赛等特色活动。
<br />  6.2011年第九届社团文化节以“时光海洋,蓝色梦想”为主题,其中开幕式游园
会以时光沙漏,穿越的形式吸引了大量的同学游览参与,其后一天的晚会以时光的变迁为主线,
美轮美奂。
<br /> 社团进班级
<br /> 每年4月至6月,由共青团泸州职业技术学院委员会、学生社团联合会联合主办,全校各学生社团承办的“社团进班级”活动,是泸州职业技术学院社团联合会的专项、品牌性活动。通过院系、班级或者团党支部与社团的紧密合作,保证社团这个学生成长的平台可以紧密的联系广大同学,并进一步营造浓厚的校园文化氛围,丰富学生课余文化生活,展示学生社团风采,深化社团文化的影响力,全面提高大学生综合素质。
<br /> 大学开放日
<br /> 每年6月,泸州职业技术学院面向各高中举办大学开放日,展示大学校园与文化。学生社团联合会组织各社团搭建社团展示区,全面展示泸州职业技术学院各类社团风采,让参观者充分体会到大学社团生活的丰富多彩,全面了解大学生的课余生活。社团展区通过新颖的布置、精彩的表演和新奇的互动活动吸引了众多前来参观的学生和家长。
<br /> 社团评估评优
<br /> 每年5月至6月,社联行政监察部组织对全校在册社团进行大型评估,由社联各部门部分成员组成的评估委员会按照最新评估制度进行公正公平的打分评估。而全校社团也借此机会对自己的工作与发展成果进行整体总结,积极为评估准备。
<br /> 6月中旬社联会举办大型优秀社团答辩会和优秀社团颁奖晚会。在前期评估中得分前三十名优秀社团将在优秀社团答辩会中进行答辩,由社员委员会、学生社团联合会和其他校级学生组织组成的评优委员会对其答辩评优,选出全校十佳社团。而随后进行的优秀社团颁奖晚会则对所有获奖社团进行颁奖,是所有社团人的分享荣誉与喜悦的时刻,是学校对社团工作的充分肯定。
<br /> 社团进军营
<br /> 每年9月初军训期间,社联便组织社团表演队深入到军训队伍中进行露天表演,每期活动累计表演20场左右。该活动在新生中产生强烈影响,并引发新生参与社团的高潮。
<br /> 社团迎新晚会
<br /> 2008年9月,社联在韵苑体育馆组织举办了第一届“社团盛典”大型社团迎新晚会,学生社团联合会文艺中心表演队和部分表演类学生社团给全校新生展现了激情昂扬的社团文化表演者的实力给众多学弟学妹留下了深刻的印象,赢得了满场观众的掌声,更收获了新生们对社团的期待。
<br /> 社团统一招新(百团大战)
<br /> 每年9月中旬,社联组织学校所有在册社团统一招新,各社团展台首尾相连,分成两列于韵苑、紫崧入口处,规模可观、气氛活跃。军训休息时间段,各社团新颖的宣传和各新生无限的热情营造了招新现场火爆的氛围。2008年的招新盛大场面给前来交流的湖南大学学生社团联合会成员留下了深刻印象。
</p>
</Card>
<Card id="music" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>社联会歌</span>
</div>
<p class="content">
《蓝色海洋》- 泸州职业技术学院社团联合会会歌
<br /> 作词:泸州职业技术学院社团联合会
<br /> 作曲:张波(吉他协会03级会长)
<br /> 01 是谁点亮了那座灯塔
<br /> 02 驱散我所有的迷茫
<br /> 03 在一个欢乐的乐园
<br /> 04 用汗水挥洒着热望
<br /> 05 心像自由的精灵
<br /> 06 游荡在浩瀚的海洋
<br /> 07 蓝色天空是我的向往
<br /> 08 朵朵白云在肆意张扬
<br /> 09 海风是多彩蜡笔
<br /> 10 描绘那未知的方向
<br /> 11 最简陋的那艘航船
<br /> 12 她教会我乘风破浪
<br /> 13 忘记我们的不同
<br /> 14 用快乐证明对生活的热爱
<br /> 15 只因为有着独特的理想
<br /> 15 才让我们学会了坚强
<br /> 16 灵动世界 我不再寂寞
<br /> 17 因为有你们左右陪伴我
<br /> 18 灵动世界 我不再沉默
<br /> 19 要让世界听到我的脉搏
<br /> 20 拥抱新的希望 忘掉昔日彷徨
<br /> 21 在蓝色海洋留下永恒的欢畅
<br /> 22拥抱新的希望 唤醒梦的力量
<br /> 23 给自己为冲动而拼搏的胆量
</p>
</Card>
<Card id="guide" class="mt20">
<!-- 标题 -->
<div class="item_title">
<!-- 蓝色竖条 -->
<div class="blue_column"></div>
<span>社团成立指南</span>
</div>
<p class="content">
 一 致社团朋友们
<br /> 亲爱的社团朋友们:
<br /> 你们好!
<br /> 首先,学生社团联合会对你们的到来表示由衷的欢迎!
<br /> 优秀的社团成立之初即应进行完备的准备工作,打造坚实的基础。这样才能使自身长久、稳定地运行和发展,使会员们能够更好地在其中娱乐、锻炼和学习,并不断为校园文化注入新的活力!
<br /> 因而,每一个进行筹备的社团都将接受社员联合会权益部的考核,只有优秀的社团才能走到最后。为了方便社团朋友及审批人员工作的开展,社团联合会权益部特别为大家制作了《社团成立指南》,希望能为你们予以方向性指导,以减少筹备中过多不必要的麻烦。
<br /> 最后,预祝你们在社团成立及后续的工作中一帆风顺,为我校社团文化做出贡献!
<br /> 学生社团联合会行政监察部
<br /> 2013年9月
<br /> 二 初期准备工作
<br /> 如果你们有:
<br /> 1、至少4名社团发起人。
<br /> 2、社团名称及主旨。
<br /> 3、对社团活动的初步规划。
<br /> 4、清晰的社团构想,明确的社团主题。
<br /> 请联系我们,行政监察部将派出工作人员与发起人进行初步沟通了解,并对初步筹备工作予以帮助指导。
<br /> 发起人在与行政监察部工作人员初步沟通后,开始着手拟定《社团筹建申请》。申请中应包括发起人对社团的初步构想,如社团的名称、宗旨、性质,及社团活动的初步规划等。
<br /> 《社团筹建申请》(附上社团发起人简历,及学生证复印件和社团主要成员通讯录)拟定后由发起人交至行政监察部,行政监察部将对申请予以审议,并派出工作人员与发起人进行进一步的筹建洽谈以了解社团的发展前景和发起人对社团发展的看法等。
<br /> 三 筹建洽谈简介
<br /> 行政监察在充分研究《社团筹建申请》的基础上,如果社团确有发展前景,将派出工作人员与发起人进行进一步的、面对面的洽谈,筹建洽谈的主要目的是双方交换社团理念并对整体社团成立工作进行说明和帮助指导。
<br /> 发起人在筹建洽谈前应该仔细思考以下两个问题:
<br /> 1、为什么发起该社团,社团在学校会有怎样的影响?社团内部有怎样的文化氛围?
<br /> 2、希望在社团里获得什么?社团又能带给会员什么?
<br /> 正式洽谈时,社团方面需要至少两名核心发起人到场。筹建洽谈将以沟通交流的方式全面且深入地了解发起人对社团的构想,并且共同探讨适合社团发展的运营模式。希望发起人能在洽谈过程中充分展示其成立协会的热情和发起人自身的组织才能。
<br /> 洽谈结束后,行政监察部将在认真研讨社团发展前景及发起人的初步规划后,于三天内给出筹建洽谈报告,在报告中确定社团是否有成立的资格。
<br /> 若社团有成立的资格,行政监察部将对该社团予以进一步帮助和指导并派出一名工作人员作为协会的临时副会长,全面协助协会筹建工作。
<br /> 四 试运行简介
<br /> 试运行时间为1至2个月。社团发起人在试运行期间需完成以下工作:
<br /> 1、管理层的招募与构建。
<br /> 2、各项规章制度的制定。
<br /> 3、挂靠院系与指导老师的联系。
<br /> 4、举办三次或三次以上活动。
<br /> 5、招收一定数量的的会员(志愿者),并举办一次会员大会对会员所拥有的权利和义务进行说明。
<br /> 6、归划具有社团特色的品牌活动。
<br /> 试运行期间,临时副会长将参与协会的各项筹建工作,并负责协会与社联相关的联系等事务。社团可通过临时副会长向社联申请教室、户外场地,或参与社联其他部门对正式社团做的外联干训、财务干训、宣传干训、会长干训等。
<br /> 社团在使用“泸州职业技术学院XX社团”的称呼时需要在社团名称后注明“筹建”字样。
<br /> 社团可以招募志愿者(即正式社团的会员)参与试运行期间的活动,但必须告知志愿者社团正处于筹建阶段,且社团不得收取活动成本以外的任何会费和其他费用。
<br /> 试运行结束前,社团发起人正式拟定好社团章程并提交试运行总结报告。
<br /> 五 社团成立审批简介
<br /> 筹建社团完成试运行,并提交完整成立申请材料后(准备材料如下),行政监察部将对社团管理层的构建、活动跟进了解得到情况以及社团章程等进行初步审议。如初步审议通过,将在一周内安排正式的成立审批。届时,社团方面需由主要管理层2-4名成员到场,其中必须包括会长。成立审批将以答辩的方式深入审查待建社团的各方面情况,以考察其是否具备成立的资质。审批结果会在一周内通知社团。一旦审批通过,社团即正式成立,进入正常运行阶段。
<br /> 附:社团成立申请材料:
<br /> 1、社团章程
<br /> 2、试运行总结报告
<br /> 3、社团挂靠协议
<br /> 4、《学生社团审批表》
<br /> 六 学生俱乐部帮扶计划
<br /> 学生社团联合会为充分发展校园文化,丰富校园生活,提出了对校园内学生俱乐部的帮扶计划,并呼吁我校各俱乐部成为正式校级注册社团,共同为校园文化注入新的活力。学生社团联合会权益部也制定了快速注册方案,帮助民间俱乐部快速转型并正式注册。
<br /> 如果你们有:
<br /> 1、20人以上的固定会员;
<br /> 2、已进行五个月以上的常规活动;
<br /> 3、较为完备的管理层;
<br /> 4、其他相关的成熟的社团发展模式。
<br /> 请联系我们,权益部将派出工作人员与管理层进行接洽,并由社团提交相应的社团章程、活动资料、发展历程和经验总结等资料,作为初步的评价标准。并耗时约两周进行转正前的准备工作,主要包括:
<br /> 1、联系挂靠院系与指导老师;
<br /> 2、举办一到两次活动;
<br /> 3、完善管理层的构建;
<br /> 4、完善各项规章制度。
<br /> 以上工作结束后,权益部将就社团管理模式的转型、活动跟进了解得到的情况以及社团章程决定准备工作是否合格。如合格,权益部将尽快对社团进行成立审批。
<br /> 正式注册校级社团将享有以下权利:
<br /> 1、可以对外使用“泸州职业技术学院XX社团”的称呼。
<br /> 2、社团可以参加社联的统一宣传和招新。(也可组织独立招新)
<br /> 3、向社联及团委申请横幅、使用教室、户外场地、社团发展基金等资源。
<br /> 4、可以接受团委指导老师的指导帮助。
<br /> 5、有社团或社联组织的相关干训、会长沙龙、校际交流出访等活动。
<br /> 6、年度社团评估评优资格。
<br /> 7、社联的橱窗、展板、社团网、人人主页等线上线下宣传平台的使用。
<br /> 8、其他资源、政策等方面的优势。
<br /> 激情澎湃 社团地带
<br /> 我们期待你们的加入!!
<br /> 学生社团联合会行政监察部
<br /> 2013年9月
<br /> 社团章程制定说明
<br /> 校级社团,区别于可以随时聚散的民间团队,必须有一定的组织性、传承性,能够稳定、长久的发展。因此,社团需要有一份完备的章程来予以保证。以下是社团章程模板:
<br /> 泸州职业技术学院XX协会章程
<br /> 一、总则
<br /> 此章主要说明社团的特色及创办目的,为社团的发展制定一个明确的方向。
<br /> 主要内容:社团名称、性质及宗旨,与社团的挂靠单位及指导老师
<br /> 二、组织框架
此章主要说明社团的管理机制。完善的管理层组织方式及职能分配是协会活动开展的前提。公平、公正、公开的干部产生机制能充分利用社团的人才资源。良好的会员培养计划与维权投诉机制也能减少后期的会员流失,使社团更加蓬勃发展。
<br /> 主要内容:社团管理层的结构及职能分配、社团干部产生机制、会员的权利与义务,与会员维权投诉机制
<br /> 三、活动规划
<br /> 良好的活动规划是社团稳定运行的基础,其中日常活动规划尤为重要。而其关键在于场地与内容。而品牌活动对增强社团内部凝聚力与扩大对外影响力有着极其重要的作用。
<br /> 主要内容:1、日常活动:活动周期、活动地点及主要活动形式
<br /> 2、品牌活动:活动时间、面向对象及活动形式
<br /> 四、财务外联
<br /> 社团必须有专人负责对财务的日常管理,并且定期向会员进行财务公示。社团应注意钱账分管,并且会长不得参与钱款管理。
<br /> 主要内容:社团经费使用制度、报账制度、财务监督制度、财务公开制度
<br /> 以上内容皆为行政监察部根据校内优秀社团章程总结而来,社团可在此基础上根据社团特色及试运行经验做适当调整,积极创新,做出符合社团特色的章程。
<br /> 学生社团联合会行政监察部
<br /> 2013年9月
</p>
</Card>
</div>
</template>
<script>
export default {};
</script>
<style lang="scss">
.about_us {
width: 80%;
margin: 0 auto;
}
.about_us .header .up_bg {
background-color: $base_color;
height: 100px;
border-radius: 5px 5px 0 0;
position: relative;
}
.about_us .header .up_bg img {
height: 140px;
width: 180px;
border-radius: 50%;
border: 5px solid #fff;
position: absolute;
left: 50px;
top: 30px;
}
.about_us .header .up_bg img:hover {
transform: scale(1.2);
}
.about_us .header .up_bg h1 {
color: #fff;
margin-left: 240px;
font-size: 30px;
font-weight: bold;
padding-top: 50px;
}
.about_us .header .down_bg {
background-color: $base_bg;
height: 100px;
border-radius: 0 0 5px 5px;
}
.about_us .header .down_bg p {
margin-left: 240px;
padding-top: 15px;
color: $base_color;
}
.about_us .item_title span {
font-size: 20px;
vertical-align: bottom;
font-weight: bold;
margin-left: 10px;
}
.about_us p.content {
line-height: 26px;
width: 96%;
margin: 10px auto;
}
</style>
team_detail.vue(社团详情页组件)
// 社团详情
<template>
<div class="team_detial">
<img src="../assets/img/teams.jpg" alt="社团展示" style="width:100%;height:300px;" />
<Spin size="large" fix v-if="spinShow"></Spin>
<div class="main">
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="18">
<!-- 导航 -->
<div class="nav flex align_items_centeer">
<a href="/index" style="padding-top:5px;">
<img src="../assets/img/home.png" alt="home" class="home_img" />
</a>
<span style="padding-left:10px;">>></span>
<a href="teams">社团世界</a>
<span style="padding-left:10px;">>></span>
<p style="color:#515a6e;margin-left:10px;">{{team.teamname}}</p>
</div>
<!-- 社团名片 -->
<Card class="detail">
<div class="up_bg">
<img :src="team.themeImg||'/static/default_team_img.png'" alt="社团主题图" />
<p class="teamname">{{team.teamname}}</p>
<Button
type="primary"
class="in_team_btn"
@click="showModal"
:disabled="disabled"
v-if="!is_in_team"
>加入社团</Button>
<Button type="warning" class="in_team_btn" v-if="is_in_team">退出社团</Button>
</div>
<div class="down_bg">
<p>
<img src="../assets/img/calender_logo.png" alt="创建时间_logo" />
创建时间:{{team.createTime}}
<span
style="display:inline-block;width:20px;"
></span>
<img src="../assets/img/person_logo.png" alt="成员_logo" />
当前成员:{{team.persons}}人
</p>
</div>
</Card>
<!-- 社团详情 -->
<Card class="content">
<ul>
<li>
<strong>社团名称</strong>
:{{team.teamname}}
</li>
<li>
<strong>社长大大</strong>
:
<img
:src="'/static/avatar_'+manager.avatar+'.png'"
alt="头像"
class="manager_avatar"
/>
{{manager.username}}
</li>
<li>
<strong>现有人数</strong>
:{{team.persons}}
</li>
<li>
<strong>创建时间</strong>
:{{team.createTime}}
</li>
<li>
<strong>社团等级</strong>
:
<Rate v-model="team.level" disabled />
</li>
<li>
<strong>社团类别</strong>
:
<span v-if="team.type==1">思想理论类</span>
<span v-else-if="team.type==2">文艺体育类</span>
<span v-else-if="team.type==3">就业创业类</span>
<span v-else-if="team.type==4">公益服务类</span>
<span v-else-if="team.type==5">学术科研类</span>
<span v-else>网络信息类</span>
</li>
<li>
<strong>社团宗旨</strong>
:
<span v-if="!isOperating">{{team.theme}}</span>
<Input v-else v-model="team.theme" type="text" style="width:500px" />
</li>
<li>
<strong>社团介绍</strong>
:
<span v-if="!isOperating">{{team.description}}</span>
<Input
v-else
v-model="team.description"
type="textarea"
:rows="6"
:autosize="{minRows: 6,maxRows: 6}"
/>
</li>
<li>
<strong>联系方式</strong>
:
<span v-if="!isOperating">{{team.contact||"无"}}</span>
<Input v-else v-model="team.contact" type="text" style="width:500px" />
</li>
<li v-if="isOperating">
<strong>主题图</strong>
:
<Input v-model="team.themeImg" type="text" style="width:500px;" />
</li>
</ul>
</Card>
<Collapse class="mt20" @on-change="loadComments">
<Panel>
评论区
<span style="float:right;margin-right:2%;" @click="showAddComment=true">
<Icon type="md-text" />
{{commentsTotal>0?commentsTotal:'*'}}
</span>
<div slot="content" style="width:86%;margin:10px auto;" class="comment_div">
<ul>
<li v-for="(item,index) in comments" :key="index" style="margin-bottom:20px;">
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="2">
<img
:src="'/static/avatar_'+item.avatar+'.png'"
alt="头像"
class="comment_avatar"
/>
</Col>
<Col span="22">
<p class="comment_name">
{{item.studentName}}
<Icon type="md-flower" v-if="item.isManager>0" title="管理员标志" />
<span style="float:right;" @click="addSupport(index,item.id)">
<Icon type="md-thumbs-up" class="support" />
{{item.supportCount}}
</span>
</p>
<p>{{item.content}}</p>
<p class="flex justify_content_between">
<span style="color:#ccc;">{{item.createTime}}</span>
<span>
<span
v-if="!item.showApply&&item.replyCount>0"
style="color:#ccc;cursor:pointer;margin-right:10px;"
@click="getReply(index,item.id)"
>
展开回复
<Icon type="ios-arrow-down" />
</span>
<span
v-if="item.showApply"
style="color:#ccc;cursor:pointer;margin-right:10px;"
@click="foldReply(index)"
>
收起回复
<Icon type="ios-arrow-up" />
</span>
<Icon
type="md-text"
@click="showAddReplyModal(item.id)"
style="cursor:pointer;"
/>
{{item.replyCount}}
</span>
</p>
<!-- 如果回复这是回复区 -->
<div class="reply_div" v-if="item.showApply">
<ul>
<li
v-for="(rep,ind) in item.applys"
:key="ind"
style="margin-top:20px;"
>
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="2">
<img
:src="'/static/avatar_'+rep.avatar+'.png'"
alt="头像"
class="comment_avatar"
/>
</Col>
<Col span="22">
<p class="comment_name">
{{rep.studentName}}
<Icon type="md-flower" v-if="rep.isManager>0" title="管理员标志" />
<span
style="float:right;"
@click="addReplySupport(index,ind,rep.id)"
>
<Icon type="md-thumbs-up" class="support" />
{{rep.supportCount}}
</span>
</p>
<p>{{rep.content}}</p>
<p style="color:#ccc;">{{rep.createTime}}</p>
</Col>
</Row>
</li>
</ul>
</div>
</Col>
</Row>
</li>
</ul>
<div style="margin:20px auto;text-align:center;">
<Page
:total="commentsTotal"
:current="comment_params.current"
:page-size="comment_params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</Panel>
</Collapse>
</Col>
<!-- 社团活动 -->
<Col span="5" class="team_activity">
<Card class="mt20">
<!-- 社团活动 -->
<div class="flex align_items_centeer">
<div class="blue_column"></div>
<span class="title">该社团最新活动</span>
</div>
<div>
<ul>
<li v-for="item in activityList" :key="item.id" style="margin:15px 0 0 15px;">
<router-link :to="{path:'activity_detail',query:{activityId:item.id}}">
<p>活动名称:{{item.activityName}}</p>
<p>活动地点:{{item.address}}</p>
<p>活动时间:{{item.createTime}}</p>
<p>活动简介:{{item.summary}}</p>
</router-link>
</li>
</ul>
</div>
<!-- 操作 -->
<div v-if="is_team_manager">
<div class="flex align_items_centeer mt20">
<div class="blue_column"></div>
<span class="title">操作</span>
</div>
<Button
v-if="!isOperating"
type="primary"
style="margin:15px 0 0 15px;"
@click="isOperating=true"
>编辑社团</Button>
<Button
v-else
type="success"
style="margin:15px 0 0 15px;"
@click="showSaveModal=true"
>保存编辑</Button>
<Button
type="primary"
style="margin:15px 0 0 15px;"
@click="showNeweAcModal=true"
>新增活动</Button>
</div>
</Card>
</Col>
</Row>
</div>
<!-- 加入社团申请表 -->
<Modal v-model="showApplyModal" title="入团申请表" @on-ok="applyTeam" @on-cancel="cancelApply">
<p>为什么想要加入我们?</p>
<Input
v-model="params.reason"
type="textarea"
:autosize="{minRows: 3,maxRows: 5}"
placeholder="请输入你的理由..."
/>
<p class="mt20">你的联系方式(请备注手机还是QQ或是微信):</p>
<Input
v-model="params.contactWay"
type="textarea"
:autosize="{minRows: 3,maxRows: 3}"
placeholder="给个联系方式呗..."
/>
</Modal>
<!-- 保存编辑提示框 -->
<Modal
v-model="showSaveModal"
title="操作提醒"
@on-ok="updateThisTeam"
@on-cancel="showSaveModal=false"
>
<h3>您确定要保存当前编辑吗?</h3>
</Modal>
<!-- 新活动信息填写 -->
<Modal
v-model="showNeweAcModal"
title="编辑活动信息"
@on-ok="addNewAc"
@on-cancel="showNeweAcModal=false"
width="600"
>
<div class="newAc" style="width:86%;margin:10px auto;">
<ul>
<li>
<span class="ac_title">活动名称:</span>
<Input type="text" v-model="newAc.activityName" style="width:200px" />
</li>
<li>
<span class="ac_title">活动时间:</span>
<DatePicker
type="datetime"
:value="newAc.createTime"
placeholder="Select date and time"
style="width: 200px"
></DatePicker>
</li>
<li>
<span class="ac_title">活动地点:</span>
<Input type="text" v-model="newAc.address" style="width:200px" />
</li>
<li>
<span class="ac_title">活动经费:</span>
<Input type="text" v-model="newAc.money" style="width:200px" />
</li>
<li>
<span class="ac_title">活动简介:</span>
<Input
type="textarea"
v-model="newAc.summary"
:rows="2"
:autosize="{minRows: 2,maxRows: 2}"
/>
</li>
<li>
<span class="ac_title">活动详情:</span>
<Input
type="textarea"
v-model="newAc.description"
:rows="5"
:autosize="{minRows: 5,maxRows: 5}"
/>
</li>
<li>
<span class="ac_title">活动图片:</span>
<Input type="text" v-model="newAc.photos" placeholder="请输入图片网络地址" />
</li>
</ul>
</div>
</Modal>
<!-- 评论信息填写 -->
<Modal
v-model="showAddComment"
title="发表评论"
@on-ok="addNewComment"
@on-cancel="showAddComment=false"
width="400"
>
<div class="newAc" style="width:86%;margin:10px auto;">
<Input
type="textarea"
maxlength="300"
show-word-limit
v-model="add_commment_params.content"
/>
</div>
</Modal>
<!-- 回复信息填写 -->
<Modal
v-model="showAddReply"
title="发表回复"
@on-ok="addReply"
@on-cancel="showAddReply=false"
width="400"
>
<div class="newAc" style="width:86%;margin:10px auto;">
<Input type="textarea" maxlength="300" show-word-limit v-model="add_reply_params.content" />
</div>
</Modal>
</div>
</template>
<script>
import TeamService from "../assets/js/team";
import StudentServicee from "../assets/js/student";
import ActivityService from "../assets/js/activity";
import CommentService from "../assets/js/comment";
export default {
name: "teamDetail",
data() {
return {
id: 0, //当前社团的id
team: {}, //当前社团
spinShow: false,
manager: {}, //管理员
disabled: false, //是否禁止点击加入社团
showApplyModal: false, //申请入社表
params: {
applyToId: 0, //社团id
reason: "", //申请理由
contactWay: "" //联系方式
},
act_params: {
current: 1,
size: 3,
teamId: -1
}, //获取社团活动的参数
activityList: [], //活动列表
is_in_team: false, //当前用户是否已经是该社团的成员
isOperating: false, //是否在进行操作
is_team_manager: false, //当前用户是否是该社团的社长
showSaveModal: false, //保存编辑提示框
showNeweAcModal: false, //活动信息填写
newAc: {
teamId: 0,
teamname: "",
activityName: "",
createTime: "",
address: "",
money: 0,
summary: "",
description: "",
photos: ""
}, //新活动参数
//关于评论的参数
showAddComment: false, //新增评论提示框
isLoadingComments: false, //是否加载评论
comment_params: {
current: 1,
size: 10,
comments: {
teamId: -1
}
}, //获取评论的参数
add_commment_params: {
teamId: -1,
content: ""
}, //新增评论的参数
comments: [], //得到的评论
commentsTotal: 0, //评论总数
showAddReply: false, //回复对话框
reply_params: {
current: 1,
size: 3,
reply: {
toWhich: -1
}
}, //获取回复的参数
add_reply_params: {
toWhich: -1,
content: ""
} //新增回复的参数
};
},
methods: {
// 获取社团信息
getTeam() {
let vm = this;
vm.spinShow = true;
TeamService.getTeamById(vm.id).then(res => {
if (res.code == 0) {
vm.team = res.data;
StudentServicee.getStudentById(vm.team.teamManagerId).then(resp => {
if (resp.code == 0) {
vm.manager = resp.data;
vm.isInThisTeam(); //判断用户是否在社团中
} else {
vm.$Message.error(resp.msg);
}
});
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
},
//显示申请表
showModal() {
let vm = this;
vm.showApplyModal = true; //显示表单
},
//取消申请
cancelApply() {
let vm = this;
vm.showApplyModal = false; //隐藏申请表
},
// 申请加入社团
applyTeam() {
let vm = this;
// 验证输入
if (vm.params.reason == "") {
this.$Message.error("理由一栏不可以为空哦~");
return;
}
if (vm.params.contactWay == "") {
this.$Message.error("小主可否留个联系方式~");
return;
}
vm.spinShow = true;
vm.params.applyToId = vm.team.id;
TeamService.createApply(vm.params).then(res => {
if (res.code == 0) {
vm.$Message.success("您的申请已成功提交,请小主静候佳音~");
vm.showApplyModal = false;
vm.disabled = true;
setTimeout(function() {
vm.disabled = false;
}, 1000 * 3);
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
},
//判断用户是否在该社团中
isInThisTeam() {
let vm = this;
let teamMember = {
studentId: 0,
teamId: vm.team.id
};
TeamService.isInThisTeam(teamMember).then(res => {
if (res.code == 0) {
vm.is_in_team = res.data;
} else {
console.log(res.msg);
}
});
},
//判断用户是否是该社团的社长
isTeamManager() {
let vm = this;
TeamService.isTeamManager(vm.id).then(res => {
if (res.code == 0) {
vm.is_team_manager = res.data;
} else {
console.log(res.msg);
}
});
},
// 获取社团的活动信息
getTeamActivitys() {
let vm = this;
vm.spinShow = true;
vm.act_params.teamId = vm.id;
ActivityService.getActivity(vm.act_params).then(res => {
if (res.code == 0) {
vm.activityList = res.data.records;
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
},
// 编辑社团
updateThisTeam() {
let vm = this;
vm.spinShow = true;
TeamService.updateTeamInfo(vm.team).then(res => {
if (res.code == 0) {
if (res.data) {
vm.$Message.success("保存成功!");
} else {
vm.$Message.error("保存失败!");
}
} else {
vm.$Message.error(res.msg);
}
vm.isOperating = false;
vm.spinShow = false;
});
},
// 新增一条活动信息
addNewAc() {
let vm = this;
vm.newAc.teamId = vm.team.id;
vm.newAc.teamname = vm.team.teamname;
ActivityService.addNewActivity(vm.newAc).then(res => {
if (res.code == 0) {
if (res.data) {
vm.$Message.success("新增成功,可前往活动页面查看!");
} else {
vm.$Message.error("新增失败!");
}
} else {
vm.$Message.error(res.msg);
}
});
},
// 显示评论区
loadComments() {
let vm = this;
if (!vm.isLoadingComments) {
vm.getComments();
}
vm.isLoadingComments = true;
},
// 获取关于这个社团的评论
getComments() {
let vm = this;
vm.spinShow = true;
vm.comment_params.comments.teamId = vm.id;
CommentService.getComments(vm.comment_params).then(res => {
if (res.code == 0) {
vm.comments = res.data.records;
vm.commentsTotal = res.data.total;
for (let i = 0; i < vm.comments.length; i++) {
vm.comments[i].applys = [];
vm.comments[i].hasGetApply = false;
vm.comments[i].showApply = false;
vm.comments[i].isSupported = false; //是否已经点赞
}
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
},
// 获取回复
getReply(index, commentId) {
let vm = this;
if (!vm.comments[index].hasGetApply) {
vm.reply_params.reply.toWhich = commentId;
CommentService.getReplys(vm.reply_params).then(resp => {
vm.comments[index].applys = resp.data.records;
vm.comments[index].hasGetApply = true;
vm.comments[index].showApply = true;
for (let i = 0; i < vm.comments[index].applys.length; i++) {
vm.comments[index].applys[i].isSupported = false; //是否已经点赞
}
vm.$forceUpdate();
});
} else {
vm.comments[index].showApply = true;
vm.$forceUpdate();
}
},
// 收起回复
foldReply(index) {
this.comments[index].showApply = false;
this.$forceUpdate();
},
// 给评论增加一个赞
addSupport(index, id) {
let vm = this;
if (vm.comments[index].isSupported) {
vm.$Message.warning("您已经点赞该评论");
return;
}
CommentService.addCommentSupport(id).then(res => {
if (res.code == 0 && res.data) {
vm.$Message.success("点赞成功");
vm.comments[index].supportCount++;
vm.comments[index].isSupported = true;
vm.$forceUpdate();
} else {
vm.$Message.error("点赞失败");
}
});
},
// 增加一条回复
addReply() {
let vm = this;
vm.spinShow = true;
CommentService.addNewReply(vm.add_reply_params).then(res => {
if (res.code == 0 && res.data) {
vm.$Message.success("新增成功!");
} else {
vm.$Message.error("新增失败!");
}
vm.spinShow = false;
location.reload();
});
},
// 给回复增加一个赞
addReplySupport(index, ind, id) {
let vm = this;
if (vm.comments[index].applys[ind].isSupported) {
vm.$Message.warning("您已经点赞该回复");
return;
}
CommentService.addReplySupport(id).then(res => {
if (res.code == 0 && res.data) {
vm.$Message.success("点赞成功");
vm.comments[index].applys[ind].supportCount++;
vm.comments[index].applys[ind].isSupported = true;
vm.$forceUpdate();
} else {
vm.$Message.error("点赞失败");
}
});
},
// 翻页
pageChange(page) {
this.comment_params.current = page;
this.getComments();
},
// 新增一条评论
addNewComment() {
let vm = this;
vm.spinShow = true;
vm.add_commment_params.teamId = vm.id;
CommentService.addNewComment(vm.add_commment_params).then(res => {
if (res.code == 0 && res.data) {
vm.$Message.success("新增成功!");
} else {
vm.$Message.error("新增失败!");
}
vm.spinShow = false;
location.reload();
});
},
// 打开新增回复的对话框
showAddReplyModal(id) {
this.showAddReply = true;
this.add_reply_params.toWhich = id;
}
},
created() {
this.id = this.$route.query.itemId; //接收传入的id
this.getTeam();
this.getTeamActivitys();
this.isTeamManager();
}
};
</script>
<style lang="scss">
.team_detial .nav {
margin-top: 20px;
border: 1px solid #dcdee2;
border-color: #e8eaec;
background: #fff;
border-radius: 4px;
font-size: 14px;
position: relative;
transition: all 0.2s ease-in-out;
color: $base_color;
}
.team_detial .nav a {
color: $base_color;
margin-left: 10px;
}
.team_detial .nav .home_img {
height: 20px;
}
// 社团名片
.team_detial .detail {
margin-top: 15px;
}
.team_detial .detail .up_bg {
background-color: $base_color;
height: 100px;
border-radius: 5px 5px 0 0;
position: relative;
}
// 社团主题图
.team_detial .detail .up_bg img {
height: 140px;
width: 140px;
border-radius: 50%;
border: 5px solid #fff;
position: absolute;
left: 50px;
top: 30px;
}
.team_detial .detail .up_bg img:hover {
transform: scale(1.2);
}
.team_detial .detail .up_bg .teamname {
color: #fff;
margin-left: 220px;
font-size: 20px;
font-weight: bold;
padding-top: 60px;
}
.team_detial .detail .down_bg {
background-color: $base_bg;
height: 100px;
border-radius: 0 0 5px 5px;
}
.team_detial .detail .down_bg img {
vertical-align: sub;
}
.team_detial .detail .down_bg p {
margin-left: 220px;
padding-top: 15px;
color: $base_color;
}
// 社团详情介绍
.team_detial .content {
margin-top: 15px;
}
.team_detial .content li {
margin-top: 10px;
line-height: 30px;
}
.team_detial .content li .manager_avatar {
height: 50px;
width: 50px;
border-radius: 50%;
border: 3px solid $base_color;
}
// 加入社团按钮
.team_detial .in_team_btn {
margin-top: -32px;
float: right;
margin-right: 20px;
}
// 右侧标题
.team_activity .title {
margin-left: 10px;
font-size: 18px;
}
// 活动填写
.newAc li {
line-height: 40px;
}
.newAc span.ac_title {
display: inline-block;
width: 100px;
}
// 评论区 头像
.team_detial .comment_div .comment_avatar {
height: 50px;
width: 50px;
border-radius: 50%;
border: 1px solid #ccc;
}
.team_detial .comment_div .comment_name {
color: orange;
font-size: 18px;
}
// 赞
.team_detial .comment_div .support {
vertical-align: text-top;
cursor: pointer;
}
.team_detial .comment_div .support:hover {
transform: scale(1.2);
}
</style>
activity_detail.vue(活动详情页组件)
// 活动详情
<template>
<div class="activity_detail">
<!-- 图片 -->
<img src="../assets/img/activity.jpg" alt="活动展示" style="width:100%;height:300px;" />
<Spin size="large" fix v-if="spinShow"></Spin>
<div class="main">
<Row type="flex" justify="space-between" class="code-row-bg row1">
<Col span="18">
<!-- 导航 -->
<div class="nav flex align_items_centeer">
<a href="/index" style="padding-top:5px;">
<img src="../assets/img/home.png" alt="home" class="home_img" />
</a>
<span style="padding-left:10px;">>></span>
<a href="activity">活动中心</a>
<span style="padding-left:10px;">>></span>
<p style="color:#515a6e;margin-left:10px;">{{activity.activityName}}</p>
</div>
<!-- 活动名片 -->
<Card class="detail">
<div class="up_bg">
<img :src="activity.photos||'/static/default_team_img.png'" alt="社团主题图" />
<p class="activity_name">{{activity.activityName}}</p>
</div>
<div class="down_bg">
<p>
<img src="../assets/img/calender_logo.png" alt="创建时间_logo" />
举办时间:{{activity.createTime}}
<span
style="display:inline-block;width:20px;"
></span>
<img src="../assets/img/person_logo.png" alt="成员_logo" />
举办社团:{{activity.teamname}}
</p>
</div>
</Card>
<!-- 活动详情 -->
<Card class="content">
<ul>
<li>
<strong>活动名称</strong>
:{{activity.activityName}}
</li>
<li>
<strong>举办方</strong>
:{{activity.teamname}}
</li>
<li>
<strong>活动地点</strong>
:{{activity.address}}
</li>
<li>
<strong>活动时间</strong>
:{{activity.createTime}}
</li>
<li>
<strong>活动简介</strong>
:{{activity.summary}}
</li>
<li>
<strong>活动详情</strong>
:{{activity.description}}
</li>
</ul>
</Card>
</Col>
<Col span="5">
<Card class="mt20">
<div class="flex align_items_centeer">
<div class="blue_column"></div>
<span style="margin-left:10px;font-size:18px;">热门活动</span>
</div>
<Timeline class="mt20">
<TimelineItem v-for="item in activityList" :key="item.id">
<p class="time">{{item.createTime}}</p>
<div style="line-height:20px;border-bottom:1px dashed #ccc;">
<router-link :to="{path:'activity_detail',query:{activityId:item.id}}">
<div>
<p class="ml10 activity_title">{{item.activityName}}</p>
<p class="ml10">举办方:{{item.teamname}}</p>
<p class="ml10 address">举办地点:{{item.address}}</p>
</div>
</router-link>
</div>
</TimelineItem>
</Timeline>
</Card>
</Col>
</Row>
</div>
</div>
</template>
<script>
import ActivityService from "../assets/js/activity";
export default {
name: "activity_detail",
data() {
return {
id: 0, //当前活动id
activity: {}, //当前活动
spinShow: false, //缓冲
params: {
current: 1,
size: 4,
teamId: -1
}, //获取活动列表的参数
activityList: [] //活动列表
};
},
methods: {
// 获取活动列表
getActivity() {
this.spinShow = true;
ActivityService.getActivity(this.params).then(res => {
if (res.code == 0) {
this.activityList = res.data.records;
this.total = res.data.total;
} else {
this.$Message.error(res.msg);
}
this.spinShow = false;
});
},
//获取当前活动详情
getActivityById() {
let vm = this;
vm.spinShow = true;
ActivityService.getActivityById(vm.id).then(res => {
if (res.code == 0) {
vm.activity = res.data;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.id = this.$route.query.activityId;
this.getActivityById();
this.getActivity();
},
watch: {
$route() {
this.id = this.$route.query.activityId;
this.getActivityById();
this.getActivity();
}
}
};
</script>
<style lang="scss">
.activity_detail .nav {
margin-top: 20px;
border: 1px solid #dcdee2;
border-color: #e8eaec;
background: #fff;
border-radius: 4px;
font-size: 14px;
position: relative;
transition: all 0.2s ease-in-out;
color: $base_color;
}
.activity_detail .nav a {
color: $base_color;
margin-left: 10px;
}
.activity_detail .nav .home_img {
height: 20px;
}
// 活动名片
.activity_detail .detail {
margin-top: 15px;
}
.activity_detail .detail .up_bg {
background-color: $base_color;
height: 100px;
border-radius: 5px 5px 0 0;
position: relative;
}
// 社团主题图
.activity_detail .detail .up_bg img {
height: 140px;
width: 140px;
border-radius: 50%;
border: 5px solid #fff;
position: absolute;
left: 50px;
top: 30px;
}
.activity_detail .detail .up_bg img:hover {
transform: scale(1.2);
}
.activity_detail .detail .up_bg .activity_name {
color: #fff;
margin-left: 220px;
font-size: 20px;
font-weight: bold;
padding-top: 60px;
}
.activity_detail .detail .down_bg {
background-color: $base_bg;
height: 100px;
border-radius: 0 0 5px 5px;
}
.activity_detail .detail .down_bg img {
vertical-align: sub;
}
.activity_detail .detail .down_bg p {
margin-left: 220px;
padding-top: 15px;
color: $base_color;
}
// 活动详情介绍
.activity_detail .content {
margin-top: 15px;
}
.activity_detail .content li {
margin-top: 10px;
line-height: 30px;
}
.activity_detail .activity_title {
color: $base_color;
font-weight: bold;
padding-top: 10px;
}
</style>
person_center.vue(个人中心组件)
// 个人中心:管理员
<template>
<div class="person_center">
<Row type="flex" justify="space-between" class="code-row-bg">
<Col span="4">
<Card class="mt20" style="min-width:300px;">
<Menu theme="light" style="z-index:1;" width="auto" activeName="person_info">
<MenuItem name="person_info" to="/person_info">
<Icon type="md-person" />个人资料
</MenuItem>
<MenuItem name="person_change" to="/person_change">
<Icon type="ios-brush" />修改资料
</MenuItem>
<MenuItem name="my_news" to="/my_news">
<Icon type="ios-chatbubbles" />消息通知
</MenuItem>
</Menu>
</Card>
</Col>
<Col span="19">
<Card class="mt20" style="min-height: 600px;">
<router-view></router-view>
</Card>
</Col>
</Row>
</div>
</template>
<script>
export default {};
</script>
<style lang="scss">
.person_center {
width: 90%;
margin: 20px auto;
}
</style>
manage.vue(管理页组件)
// 管理页
<template>
<div class="manage">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 如果不是管理员 -->
<div v-if="user.isManager!=2" class="flex align_items_centeer justify_content_around">
<img src="../assets/img/no_access.png" alt="您无权访问" style="width:400px;" />
</div>
<!-- 管理页面 -->
<div v-else style="width:80%;margin:20px auto;">
<Row type="flex" justify="space-between" class="code-row-bg">
<Col span="4">
<Card class="mt20" style="min-width:180px;">
<Menu theme="light" style="z-index:1;width:150px;">
<MenuItem name="m_student" to="/m_student">
<Icon type="md-contacts" />用户管理
</MenuItem>
<MenuItem name="m_team" to="/m_team">
<Icon type="ios-chatbubbles" />社团信息
</MenuItem>
<MenuItem name="m_activity" to="/m_activity">
<Icon type="ios-football" />活动管理
</MenuItem>
<MenuItem name="m_teamMember" to="/m_teamMember">
<Icon type="md-folder" />社团成员
</MenuItem>
<MenuItem name="m_createTeam" to="/m_createTeam">
<Icon type="md-settings" />社团管理
</MenuItem>
<MenuItem name="m_comment" to="/m_comment">
<Icon type="md-text" />评论管理
</MenuItem>
<MenuItem name="m_reply" to="/m_reply">
<Icon type="ios-text" />回复管理
</MenuItem>
</Menu>
</Card>
</Col>
<Col span="19">
<Card class="mt20">
<router-view></router-view>
</Card>
</Col>
</Row>
</div>
</div>
</template>
<script>
import LoginService from "../assets/js/login.js";
export default {
name: "manage",
data() {
return {
user: {}, //管理员信息
spinShow: false //缓冲
};
},
methods: {
// 获取用户信息
getUserInfo() {
let vm = this;
vm.spinShow = true;
LoginService.getLoginUserInfo().then(res => {
if (res.code == 0) {
vm.user = res.data;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.getUserInfo();
}
};
</script>
个人页面组件放view文件夹中
view/person_info.vue (个人-个人信息展示页组件)
// 个人中心->个人资料
<template>
<div class="person_info">
<Spin size="large" fix v-if="spinShow"></Spin>
<h3>个人资料</h3>
<div class="content">
<ul>
<li>
<span>头像:</span>
<img
:src="'../../static/avatar_'+user.avatar+'.png'"
alt="头像"
class="avatar"
@click="showBigAvatar=true"
/>
</li>
<li>
<span>学号:</span>
{{user.sno}}
</li>
<li>
<span>姓名:</span>
{{user.username}}
</li>
<li>
<span>性别:</span>
{{user.sex?"女":"男"}}
</li>
<li>
<span>手机号:</span>
{{user.phone||"您还没有设置手机号哦~"}}
</li>
<li>
<span>邮箱账号:</span>
{{user.email||"您还没有设置邮箱账号哦~"}}
</li>
<li>
<span>个人简介:</span>
{{user.introduce||"该用户很懒,什么也没留下~"}}
</li>
<li>
<span>创建时间:</span>
{{user.createTime}}
</li>
</ul>
</div>
<div style="text-align:center;" class="mt20">
<router-link to="/manage" v-if="user.isManager==2" class="go_manage">进入管理页</router-link>
<Button type="error" @click="showWarning=true">退出登录</Button>
</div>
<!-- 点击放大图片 -->
<Modal v-model="showBigAvatar" width="400">
<div slot="header"></div>
<img :src="'../../static/avatar_'+user.avatar+'.png'" alt="头像" />
<div slot="footer"></div>
</Modal>
<!-- 退出登录提示框 -->
<Modal v-model="showWarning" @on-cancel="showWarning=false" @on-ok="logout" title="操作提醒">
<h3>你确定要退出登录吗?</h3>
</Modal>
</div>
</template>
<script>
import StudentService from "../../assets/js/student.js";
import LoginService from "../../assets/js/login.js";
export default {
name: "person_info",
data() {
return {
user: {}, //用户信息
showBigAvatar: false, //显示大图头像
showWarning: false, //退出登录提示
spinShow: false
};
},
methods: {
// 获取用户信息
getUserInfo() {
let vm = this;
vm.spinShow = true;
LoginService.getLoginUserInfo().then(res => {
if (res.code == 0) {
vm.user = res.data;
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
},
// 退出登录
logout() {
let vm = this;
LoginService.logout().then(res => {
if (res.code == 0) {
vm.$store.store.commit("deleteToken"); //把删除token
vm.$router.push("/index");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
},
created() {
this.getUserInfo();
}
};
</script>
<style lang="scss">
// 标题
.person_info h3 {
text-align: center;
}
// 个人信息主体
.person_info .content {
margin-top: 10px;
border: 1px solid #ddd;
padding: 20px;
font-size: 18px;
}
// 个人资料 列表项
.person_info .content li {
line-height: 30px;
}
.person_info .content li span {
display: inline-block;
width: 100px;
}
.person_info .content li .avatar {
width: 50px;
height: 50px;
border: 1px solid $base_color;
border-radius: 50%;
cursor: pointer;
}
.person_info .go_manage {
display: inline-block;
background-color: $base_color;
color: white;
height: 32px;
margin-bottom: 0;
font-weight: 400;
text-align: center;
vertical-align: middle;
touch-action: auto;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
</style>
view/person_change.vue (个人-个人资料更改页组件)
// 个人中心->修改资料
<template>
<div class="person_change">
<h3>修改资料</h3>
<div class="content">
<ul>
<li>
<span>头像:</span>
<img
:src="'../../static/avatar_'+user.avatar+'.png'"
alt="头像"
class="avatar"
title="点击修改头像"
@click="showAvatarModal"
/>
</li>
<li>
<span>学号:</span>
{{user.sno}}
</li>
<li>
<span>密码:</span>
<Input type="text" v-model="password" maxlength="16" />
</li>
<li>
<span>姓名:</span>
<Input type="text" v-model="user.username" maxlength="5" />
</li>
<li>
<span>性别:</span>
{{user.sex?"女":"男"}}
</li>
<li>
<span>手机号:</span>
<Input type="text" v-model="user.phone" />
</li>
<li>
<span>邮箱账号:</span>
<Input type="text" v-model="user.email" />
</li>
<li>
<span>个人简介:</span>
<Input type="textarea" v-model="user.introduce" :autosize="false" :rows="4" />
</li>
<li>
<span>创建时间:</span>
{{user.createTime}}
</li>
<li style="justify-content:center;" class="mt20">
<Button type="primary" @click="sureChangeModal=true">保存修改</Button>
</li>
</ul>
</div>
<Modal v-model="showAvatarChangeModal" title="头像选择" @on-cancel="showAvatarChangeModal=false">
<ul class="avatat_list">
<li v-for="item in avatarList" :key="item.index" @click="choosedAvatar(item.index)">
<img
:src="'../../static/avatar_'+item.index+'.png'"
alt="头像"
:class=" item.checked?'choosed avatar':'avatar'"
/>
</li>
</ul>
</Modal>
<!-- 确认修改提醒框 -->
<Modal
v-model="sureChangeModal"
title="操作提醒"
@on-cancel="sureChangeModal=false"
@on-ok="personUpdate"
>
<h3>确认修改吗?</h3>
</Modal>
</div>
</template>
<script>
import StudentService from "../../assets/js/student.js";
import LoginService from "../../assets/js/login.js";
export default {
name: "person_change",
data() {
return {
user: {}, //用户信息
password: "", //密码
showAvatarChangeModal: false, //头像更换窗口
avatarList: [
{ index: 1, checked: false },
{ index: 2, checked: false },
{ index: 3, checked: false },
{ index: 4, checked: false },
{ index: 5, checked: false },
{ index: 6, checked: false }
], //头像列表
sureChangeModal: false //确认选择提示框
};
},
methods: {
// 获取用户信息
getUserInfo() {
let vm = this;
LoginService.getLoginUserInfo().then(res => {
if (res.code == 0) {
vm.user = res.data;
vm.avatarList[vm.user.avatar - 1].checked = true;
} else {
vm.$Message.error(res.msg);
}
});
},
// 打开头像更换 对话框
showAvatarModal() {
this.showAvatarChangeModal = true;
},
// 选中头像
choosedAvatar(index) {
let vm = this;
for (var i = 0; i < vm.avatarList.length; i++) {
vm.avatarList[i].checked = false;
}
vm.avatarList[index - 1].checked = true;
vm.user.avatar = index;
},
// 确认更换头像
sureChangeAvatar() {
this.showAvatarChangeModal = false;
},
// 验证输入
validateInput() {
let vm = this;
// 验证密码:不能小于6位
if (vm.password != "" && vm.password.length < 6) {
vm.$Message.error("密码长度不能小于6位!");
return false;
}
if (vm.password != "") {
vm.user.password = vm.password;
}
// 验证姓名
if (vm.user.username == "") {
vm.$Message.error("姓名不能为空!");
return false;
}
// 验证手机号
let reg = /^1[0-9]{10}$/;
if (vm.user.phone != "" && vm.user.phone != null) {
if (vm.user.phone.length <= 10 || !reg.test(vm.user.phone)) {
vm.$Message.error("请输入正确的手机号!");
return false;
}
}
// 验证邮箱账号
let regEmail = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
if (vm.user.email != "" && vm.user.email != null) {
if (!regEmail.test(vm.user.email)) {
vm.$Message.error("请输入正确的邮箱账号!");
return false;
}
}
return true;
},
//修改用户信息
personUpdate() {
let vm = this;
vm.validateInput();
StudentService.updateStudent(vm.user).then(res => {
if (res.code == 0) {
vm.$Message.success(res.msg);
} else {
vm.$Message.error(res.msg);
}
});
}
},
created() {
this.getUserInfo();
}
};
</script>
<style lang="scss">
// 标题
.person_change h3 {
text-align: center;
}
// 修改资料主体
.person_change .content {
margin-top: 10px;
border: 1px solid #ddd;
padding: 20px;
font-size: 18px;
}
// 修改改资 列表项
.person_change .content li {
line-height: 40px;
display: flex;
}
.person_change .content li span {
display: inline-block;
width: 100px;
}
.person_change .content li .avatar {
width: 50px;
height: 50px;
border: 1px solid $base_color;
border-radius: 50%;
cursor: pointer;
}
.avatat_list li {
display: inline-block;
margin-left: 20px;
}
.avatat_list .avatar {
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
.avatat_list .avatar.choosed {
border: 2px solid $base_color;
}
.avatat_list .avatar:hover {
transform: scale(1.5);
}
</style>
view/my_news.vue(个人->我的消息页面组件)
// 个人中心->我的消息
<template>
<div class="my_news">
<h3>我的消息</h3>
<div class="content mt20">
<Table stripe :columns="columns" :data="news"></Table>
</div>
<div style="margin: 20px auto; text-align:center;">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import LoginService from "../../assets/js/login.js";
import StudentService from "../../assets/js/student.js";
export default {
name: "my_news",
data() {
return {
params: {
current: 1,
size: 10
},
total: 0,
columns: [
{
title: "申请人",
key: "applyUsername"
},
{
title: "申请理由",
key: "reason"
},
{
title: "申请时间",
key: "createTime"
},
{
title: "联系方式",
key: "contactWay"
},
{
title: "状态",
key: "isPass",
render: (h, params) => {
//是否通过申请(0:等待处理 1:拒绝 2:通过)
let str = "";
switch (params.row.isPass) {
case 0: {
str = "等待处理";
break;
}
case 1: {
str = " 已拒绝";
break;
}
case 2: {
str = "已通过";
}
}
return h("div", str);
}
},
{
title: "操作",
render: (h, params) => {
let passBtn = h(
"Button",
{
props: {
type: "success",
size: "small"
},
on: {
click: () => {
StudentService.passApply(params.row).then(res => {
if (res.code == 0) {
this.$Message.success("已同意该用户的申请!");
location.reload();
} else {
this.$Message.error(res.msg);
}
});
}
}
},
"通过"
);
let refuseBtn = h(
"Button",
{
props: {
type: "warning",
size: "small"
},
on: {
click: () => {
StudentService.rejectApply(params.row).then(res => {
if (res.code == 0) {
this.$Message.success("已拒绝该用户的申请!");
location.reload();
} else {
this.$Message.error(res.msg);
}
});
}
}
},
"拒绝"
);
let delBtn = h(
"Button",
{
props: {
type: "error",
size: "small"
},
on: {
click: () => {
StudentService.deleteApply(params.row).then(res => {
if (res.code == 0) {
this.$Message.success("已删除该用户的申请!");
location.reload();
} else {
this.$Message.error(res.msg);
}
});
}
}
},
"删除"
);
let btns = [];
if (params.row.isPass != 0) {
btns.push(delBtn);
} else {
btns.push(passBtn);
btns.push(refuseBtn);
}
if (this.user.isManager > 0) {
return h("div", btns);
} else {
return h("div", "您没有权限进行操作");
}
}
}
],
news: [],
user: {}
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getTeams();
},
// 获取通知
getNews() {
LoginService.getApply(this.params).then(res => {
if (res.code == 0) {
this.news = res.data.records;
this.total = res.data.total;
} else {
// this.$Message.error(res.msg);
}
});
},
// 获取该用户信息
getUserInfo() {
let vm = this;
LoginService.getLoginUserInfo().then(res => {
if (res.code == 0) {
vm.user = res.data;
} else {
vm.$Message.error(res.msg);
}
});
}
},
created() {
this.getNews();
this.getUserInfo();
}
};
</script>
<style lang="scss">
// 标题
.my_news h3 {
text-align: center;
}
</style>
在components文件夹中新建manage_view文件夹
manage_view文件夹放后台页面组件
manage_view/student.vue(后台-用户管理组件)
// 用户管理
<template>
<div class="m_student">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 学号 管理员 姓名-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">学号:</span>
<Input type="text" style="width:150px" v-model="params.student.sno" />
</li>
<li class="ml10">
<span class="title">身份:</span>
<Select v-model="params.student.isManager" style="width:150px">
<Option
v-for="item in isManagerList"
:value="item.value"
:key="item.value"
>{{ item.label }}</Option>
</Select>
</li>
<li class="ml10" style="flex:1;">
<span class="title">姓名:</span>
<Input type="text" style="width:150px" v-model="params.student.username" />
</li>
<li>
<Button type="primary" @click="getAllStudent">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="students"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import StudentService from "../../assets/js/student.js";
import ConfirmModal from "./confirmModal";
export default {
name: "student",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
student: {
sno: "",
isManager: -1,
username: ""
}
},
students: [], //学生数据
spinShow: false, //缓冲
total: 0, //学生总数
isManagerList: [
{
value: -1,
label: "所有用户"
},
{
value: 0,
label: "普通用户"
},
{
value: 1,
label: "社团管理员"
},
{
value: 2,
label: "超级管理员"
}
],
columns: [
{
title: "id",
key: "id"
},
{
title: "学号",
key: "sno"
},
// {
// title: "密码",
// key: "password"
// },
{
title: "姓名",
key: "username"
},
{
title: "性别",
render: (h, params) => {
return h("div", params.row.sex ? "女" : "男");
}
},
{
title: "身份",
render: (h, params) => {
let str = "";
switch (params.row.isManager) {
case 0:
str = "普通成员";
break;
case 1:
str = "社团管理员";
break;
case 2:
str = "超级管理员";
break;
}
return h("div", str);
}
},
{
title: "手机号",
key: "phone"
},
{
title: "邮箱",
key: "email"
},
{
title: "个人简介",
key: "introduce"
},
{
title: "注册时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
if (params.row.isManager == 2) {
vm.$Message.error("无法删除超级管理员!");
return;
}
StudentService.deleteStudent(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getAllStudent();
},
// 获取学生信息
getAllStudent() {
let vm = this;
vm.spinShow = true;
StudentService.getAllStudent(vm.params).then(res => {
if (res.code == 0) {
vm.students = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.getAllStudent();
}
};
</script>
<style lang="scss">
// 检索条件
.m_student .condition li span.title {
width: 80px;
}
</style>
manage_view/team.vue(后台-社团信息管理组件)
// 社团信息管理
<template>
<div class="m_team">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 社团名称 类型 等级-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">社团名称:</span>
<Input type="text" style="width:150px" v-model="params.team.teamname" />
</li>
<li class="ml10">
<span class="title">类型:</span>
<Select v-model="params.team.type" style="width:150px">
<Option v-for="item in typeList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</li>
<li class="ml10" style="flex:1;">
<span class="title">等级:</span>
<Select v-model="params.team.level" style="width:150px">
<Option :value="0">所有等级</Option>
<Option v-for="item in levelList" :value="item" :key="item">{{item}}</Option>
</Select>
</li>
<li>
<Button type="primary" @click="getAllTeam">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="teams"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import TeamService from "../../assets/js/team.js";
import ConfirmModal from "./confirmModal";
export default {
name: "team",
data() {
return {
params: {
current: 1,
size: 10,
team: {
teamname: "",
type: 0,
level: 0
}
}, //查询参数
teams: [], //社团数据
spinShow: false, //缓冲
total: 0, //社团总数
typeList: [
{
value: 0,
label: "所有类型"
},
{
value: 1,
label: "思想理论类"
},
{
value: 2,
label: "文艺体育类"
},
{
value: 3,
label: "就业创业类"
},
{
value: 4,
label: "公益服务类"
},
{
value: 5,
label: "学术科研类"
},
{
value: 6,
label: "网络信息类"
}
], //社团类型列表
levelList: [1, 2, 3, 4, 5], //等级列表
columns: [
{
title: "id",
key: "id"
},
{
title: "社团名称",
key: "teamname"
},
{
title: "社团宗旨",
key: "theme"
},
{
title: "当前人数",
key: "persons"
},
{
title: "管理员id",
key: "teamManagerId"
},
{
title: "社团类型",
render: (h, params) => {
let str = "";
switch (params.row.type) {
case 1:
str = "思想理论类";
break;
case 2:
str = "文艺体育类";
break;
case 3:
str = "就业创业类";
break;
case 4:
str = "公益服务类";
break;
case 5:
str = "学术科研类";
break;
case 6:
str = "网络信息类";
break;
}
return h("div", str);
}
},
{
title: "社团等级",
key: "level"
},
{
title: "创建时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let detailBtn = h(
"Button",
{
props: {
type: "primary"
},
on: {
click: () => {
vm.$router.push({
path: "/team_detail",
query: { itemId: params.row.id }
});
}
}
},
"查看"
);
let btns = [];
btns.push(detailBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getAllTeam();
},
// 获取社团信息
getAllTeam() {
let vm = this;
vm.spinShow = true;
TeamService.getManageTeam(vm.params).then(res => {
if (res.code == 0) {
vm.teams = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.getAllTeam();
}
};
</script>
<style lang="scss">
// 检索条件
.m_team .condition li span.title {
width: 80px;
}
</style>
manage_view/activity.vue(后台-活动管理组件)
// 活动管理
<template>
<div class="m_activity">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 举办的社团名称 活动名称-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">举办社团:</span>
<Input type="text" style="width:150px" v-model="params.activity.teamname" />
</li>
<li class="ml10" style="flex:1;">
<span class="title">活动名称:</span>
<Input type="text" style="width:150px" v-model="params.activity.activityName" />
</li>
<li>
<Button type="primary" @click="getAllAct">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="acts"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import ActivityService from "../../assets/js/activity.js";
import ConfirmModal from "./confirmModal";
export default {
name: "activity",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
activity: {
teamname: "",
activityName: ""
}
},
acts: [], //活动数据
spinShow: false, //缓冲
total: 0, //活动总数
columns: [
{
title: "id",
key: "id"
},
{
title: "活动名称",
key: "activityName"
},
{
title: "活动地点",
key: "address"
},
{
title: "主办社团",
key: "teamname"
},
{
title: "简介",
key: "summary",
width: "300"
},
{
title: "活动资金",
key: "money"
},
{
title: "活动时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let detailBtn = h(
"Button",
{
props: {
type: "primary"
},
on: {
click: () => {
vm.$router.push({
path: "/activity_detail",
query: { activityId: params.row.id }
});
}
}
},
"查看"
);
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
ActivityService.deleteActivity(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
btns.push(detailBtn);
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getAllAct();
},
// 获取学生信息
getAllAct() {
let vm = this;
vm.spinShow = true;
ActivityService.getManageActivity(vm.params).then(res => {
if (res.code == 0) {
vm.acts = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.getAllAct();
}
};
</script>
<style lang="scss">
// 检索条件
.m_activity .condition li span.title {
width: 80px;
}
</style>
manage_view/teamMember.vue(后台-社团成员管理组件)
// 社团成员管理
<template>
<div class="m_teamMember">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 社团名称 成员名称-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">社团名称:</span>
<Input type="text" style="width:150px" v-model="params.teamMember.teamName" />
</li>
<li style="flex:1;">
<span class="title">学生名称:</span>
<Input type="text" style="width:150px" v-model="params.teamMember.studentName" />
</li>
<li>
<Button type="primary" @click="getManageTM">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="teamMembers"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import TeamService from "../../assets/js/team.js";
import ConfirmModal from "./confirmModal";
export default {
name: "team",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
teamMember: {
teamName: "",
studentName: ""
}
}, //查询参数
teamMembers: [], //社团成员数据
spinShow: false, //缓冲
total: 0, //社团总数
columns: [
{
title: "社团名称",
key: "teamName"
},
{
title: "学生姓名",
key: "studentName"
},
{
title: "职位",
render: (h, params) => {
return h("div", params.row.isManager == 0 ? "普通成员" : "社长");
}
},
{
title: "创建时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
let param = {
s_id: params.row.studentId,
t_id: params.row.teamId
};
TeamService.deleteRelate(param).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getManageTM();
},
// 获取社团信息
getManageTM() {
let vm = this;
vm.spinShow = true;
TeamService.getManageTM(vm.params).then(res => {
if (res.code == 0) {
vm.teamMembers = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
});
vm.spinShow = false;
}
},
created() {
this.getManageTM();
}
};
</script>
<style lang="scss">
// 检索条件
.m_teamMember .condition li span.title {
width: 80px;
}
</style>
manage_view/createTeam.vue(后台-创建社团的请求页组件)
// 创建社团的请求
// 用户管理
// 社团管理
<template>
<div class="m_createTeam">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 学号 管理员 姓名-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">社团名称:</span>
<Input type="text" style="width:150px" v-model="params.createTeam.applyToName" />
</li>
<li class="ml10">
<span class="title">社团类型:</span>
<Select v-model="params.createTeam.teamType" style="width:150px">
<Option v-for="item in typeList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</li>
<li class="ml10" style="flex:1;">
<span class="title">状态:</span>
<Select v-model="params.createTeam.isPass" style="width:150px">
<Option
v-for="item in isPassList"
:value="item.value"
:key="item.value"
>{{ item.label }}</Option>
</Select>
</li>
<li>
<Button type="primary" @click="getAllCreateApply">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="applys"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import TeamService from "../../assets/js/team.js";
import ConfirmModal from "./confirmModal";
export default {
name: "createTeam",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
createTeam: {
applyToName: "", //社团名称
teamType: 0, //社团类别
isPass: -1 //是否通过
}
},
applys: [], //请求数据
typeList: [
{
value: 0,
label: "所有类型"
},
{
value: 1,
label: "思想理论类"
},
{
value: 2,
label: "文艺体育类"
},
{
value: 3,
label: "就业创业类"
},
{
value: 4,
label: "公益服务类"
},
{
value: 5,
label: "学术科研类"
},
{
value: 6,
label: "网络信息类"
}
], //社团类型列表
isPassList: [
{
value: -1,
label: "全部状态"
},
{
value: 0,
label: "待处理"
},
{
value: 1,
label: "已拒绝"
},
{
value: 2,
label: "已通过"
}
],
spinShow: false, //缓冲
total: 0, //请求总数
columns: [
{
title: "id",
key: "id"
},
{
title: "申请人id",
key: "applyFromId"
},
{
title: "社团名称",
key: "applyToName"
},
{
title: "社团类型",
render: (h, params) => {
let str = "";
switch (params.row.teamType) {
case 1:
str = "思想理论类";
break;
case 2:
str = "文艺体育类";
break;
case 3:
str = "就业创业类";
break;
case 4:
str = "公益服务类";
break;
case 5:
str = "学术科研类";
break;
case 6:
str = "网络信息类";
break;
}
return h("div", str);
}
},
{
title: "申请理由",
key: "reason"
},
{
title: "联系方式",
key: "contactWay"
},
{
title: "申请时间",
key: "createTime"
},
{
title: "状态",
render: (h, params) => {
let str = "";
switch (params.row.isPass) {
case 0:
str = "待处理";
break;
case 1:
str = "已拒绝";
break;
case 2:
str = "已通过";
break;
}
return h("div", str);
}
},
{
title: "操作",
render: (h, params) => {
let vm = this;
// 通过申请
let passBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要通过该申请吗?",
btnType: "2"
},
on: {
func() {
TeamService.passCreateTeamApply(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
// 拒绝申请
let refuseBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要拒绝该申请吗?",
btnType: "3"
},
on: {
func() {
TeamService.refuseCreateTeamApply(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
// 删除申请
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
TeamService.deleteCreateTeamApply(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
if (params.row.isPass == 0) {
btns.push(passBtn);
btns.push(refuseBtn);
}
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getAllCreateApply();
},
// 获取请求信息
getAllCreateApply() {
let vm = this;
TeamService.getAllCreateApply(vm.params).then(res => {
if (res.code == 0) {
vm.applys = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
});
}
},
created() {
this.spinShow = true;
this.getAllCreateApply();
this.spinShow = false;
}
};
</script>
<style lang="scss">
// 检索条件
.m_createTeam .condition li span.title {
width: 80px;
}
</style>
manage_view/comment.vue(后台-评论管理组件)
// 评论管理
<template>
<div class="m_student">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 社团id 评论内容 学生姓名-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">社团id:</span>
<Input type="number" style="width:150px" v-model="params.comments.teamId" />
</li>
<li class="ml10">
<span class="title">评论内容:</span>
<Input type="text" style="width:150px" v-model="params.comments.content" />
</li>
<li class="ml10" style="flex:1;">
<span class="title">学生姓名:</span>
<Input type="text" style="width:150px" v-model="params.comments.studentName" />
</li>
<li>
<Button type="primary" @click="getComments">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="comments"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import CommentService from "../../assets/js/comment.js";
import ConfirmModal from "./confirmModal";
export default {
name: "student",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
comments: {
teamId: -1, //社团id
content: "", //评论内容
studentName: "" //学生姓名
}
},
comments: [], //评论数据
spinShow: false, //缓冲
total: 0, //评论总数
columns: [
{
title: "id",
key: "id"
},
{
title: "社团id",
key: "teamId"
},
{
title: "姓名",
key: "studentName"
},
{
title: "评论内容",
key: "content"
},
{
title: "获赞数量",
key: "supportCount"
},
{
title: "回复数量",
key: "replyCount"
},
{
title: "评论时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
CommentService.deleteComment(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getComments();
},
// 获取评论信息
getComments() {
let vm = this;
if (!vm.params.comments.teamId >= 0) {
vm.params.comments.teamId = -1;
}
vm.spinShow = true;
CommentService.getComments(vm.params).then(res => {
if (res.code == 0) {
vm.comments = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
}
},
created() {
this.getComments();
}
};
</script>
<style lang="scss">
// 检索条件
.m_student .condition li span.title {
width: 80px;
}
</style>
manage_view/reply.vue(后台-回复管理组件)
// 回复管理
<template>
<div class="m_student">
<Spin size="large" fix v-if="spinShow"></Spin>
<!-- 检索条件 回复id 评论内容 学生姓名-->
<Row class="condition">
<ul class="flex">
<li>
<span class="title">回复id:</span>
<Input type="number" style="width:150px" v-model="params.reply.toWhich" />
</li>
<li class="ml10">
<span class="title">评论内容:</span>
<Input type="text" style="width:150px" v-model="params.reply.content" />
</li>
<li class="ml10" style="flex:1;">
<span class="title">学生姓名:</span>
<Input type="text" style="width:150px" v-model="params.reply.studentName" />
</li>
<li>
<Button type="primary" @click="getReplys">搜索</Button>
</li>
</ul>
</Row>
<!-- 表格 -->
<Row class="mt20">
<Table stripe :columns="columns" :data="replys"></Table>
</Row>
<!-- 分页 -->
<div class="mdt20">
<Page
:total="total"
:current="params.current"
:page-size="params.size"
class="page"
@on-change="pageChange"
/>
</div>
</div>
</template>
<script>
import CommentService from "../../assets/js/comment.js";
import ConfirmModal from "./confirmModal";
export default {
name: "reply",
components: { ConfirmModal },
data() {
return {
params: {
current: 1,
size: 10,
reply: {
toWhich: -1, //评论id
content: "", //回复内容
studentName: "" //学生姓名
}
},
replys: [], //回复数据
spinShow: false, //缓冲
total: 0, //回复总数
columns: [
{
title: "id",
key: "id"
},
{
title: "评论id",
key: "toWhich"
},
{
title: "姓名",
key: "studentName"
},
{
title: "评论内容",
key: "content"
},
{
title: "获赞数量",
key: "supportCount"
},
{
title: "回复时间",
key: "createTime"
},
{
title: "操作",
render: (h, params) => {
let vm = this;
let delBtn = h(ConfirmModal, {
props: {
sureMsg: "您确认要删除该条数据吗?",
btnType: "1"
},
on: {
func() {
CommentService.deleteReply(params.row.id).then(res => {
if (res.code == 0) {
vm.$Message.success("操作成功!");
location.reload();
} else {
vm.$Message.error(res.msg);
}
});
}
}
});
let btns = [];
btns.push(delBtn);
return h("div", btns);
}
}
]
};
},
methods: {
/*页码改变*/
pageChange(page) {
this.params.current = page;
this.getReplys();
},
// 获取评论信息
getReplys() {
let vm = this;
if (!vm.params.reply.toWhich >= 0) {
vm.params.reply.toWhich = -1;
}
vm.spinShow = true;
CommentService.getReplys(vm.params).then(res => {
if (res.code == 0) {
vm.replys = res.data.records;
vm.total = res.data.total;
} else {
vm.$Message.error(res.msg);
}
vm.spinShow = false;
});
}
},
created() {
this.getReplys();
}
};
</script>
<style lang="scss">
// 检索条件
.m_student .condition li span.title {
width: 80px;
}
</style>
manage_view/confirmModal.vue(后台-审核-操作确认框页组件)
// 操作确认框
// 调用 <ConfirmModal sureMsg="确认删除吗?" @func="方法名" btnType="1"></ConfirmModal>
// 按钮类别 : 1-删除 2-通过请求 3-拒绝申请
<template>
<div class="sureOp">
<!-- 删除 -->
<Button @click="showOPModal=true" type="error" v-if="btnType=='1'">删除</Button>
<!-- 通过 -->
<Button @click="showOPModal=true" type="success" v-if="btnType=='2'">通过</Button>
<!-- 拒绝 -->
<Button @click="showOPModal=true" type="warning" v-if="btnType=='3'">拒绝</Button>
<Modal v-model="showOPModal" @on-cancel="showOPModal=false" @on-ok="sureOP" title="操作提醒">
<h3>{{sureMsg}}</h3>
</Modal>
</div>
</template>
<script>
export default {
name: "confirmModal",
props: {
sureMsg: {
type: String,
default: ""
},
btnType: {
type: String,
default: "1"
}
},
data() {
return {
showOPModal: false
};
},
methods: {
sureOP() {
this.$emit("func");
}
}
};
</script>
(2)编写路由
在router文件下的index.js
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/components/index'
import Teams from '@/components/teams'
import TeamDetail from '@/components/team_detail'
import PersonCenter from '@/components/person_center'
import PersonInfo from "@/components/view/person_info"
import PersonChange from "@/components/view/person_change"
import MyNews from "@/components/view/my_news"
import Activity from "@/components/activity"
import ActivityDetail from "@/components/activity_detail"
import AboutUs from "@/components/about_us"
import Manage from "@/components/manage"
import m_student from "@/components/manage_view/student"
import m_team from "@/components/manage_view/team"
import m_activity from "@/components/manage_view/activity"
import m_createTeam from "@/components/manage_view/createTeam"
import m_teamMember from "@/components/manage_view/teamMember"
import m_comment from "@/components/manage_view/comment"
import m_reply from "@/components/manage_view/reply"
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [{
path: '/',
redirect: '/index'
}, {
path: '/index',
name: 'index',
component: Index //主页
}, {
path: '/teams',
name: 'teams',
component: Teams //社团页
}, {
path: '/team_detail',
name: 'TeamDetail',
component: TeamDetail //社团详情页
}, {
path: '/person_center',
name: 'PersonCenter',
component: PersonCenter, //个人中心
children: [{
path: "/",
name: "",
component: PersonInfo //默认显示:个人资料
},
{
path: "/person_info",
name: "person_info",
component: PersonInfo //个人资料
}, {
path: "/person_change",
name: "person_change",
component: PersonChange //修改资料
}, {
path: "/my_news",
name: "my_news",
component: MyNews //修改资料
}
]
}, {
path: '/activity',
name: 'activity',
component: Activity //活动页
}, {
path: '/activity_detail',
name: 'activity_detail',
component: ActivityDetail //活动详情页
}, {
path: "/about_us",
name: "about_us",
component: AboutUs
}, {
path: "/manage",
name: "manage",
component: Manage, //管理页
children: [{
path: '/',
name: '',
component: m_student //默认显示学生管理页
},
{
path: '/m_student',
name: 'm_student',
component: m_student //学生管理页
},
{
path: '/m_team',
name: 'm_team',
component: m_team //社团管理页
},
{
path: '/m_activity',
name: 'm_activity',
component: m_activity //活动管理页
},
{
path: '/m_createTeam',
name: 'm_createTeam',
component: m_createTeam //管理员获取 创建社团 的请求
},
{
path: '/m_teamMember',
name: 'm_teamMember',
component: m_teamMember
},
{
path: '/m_comment',
name: 'm_comment',
component: m_comment
},
{
path: '/m_reply',
name: 'm_reply',
component: m_reply
}
]
}]
})
三、后端编写(Springboot)
1、搭建springboot项目
新建springboot项目
完成后如下图:
可直接删除上面的maven和git相关的文件
新建一个controller文件夹,新建一个HelloWorld.java,测试一下
运行后输入localhost:8080/hello
到此springboot项目搭建完成
后端项目图
2、配置
(1)、pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lgs</groupId>
<artifactId>association_back</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>association_back</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.2.6.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>jcl-over-slf4j</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- fastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--hutool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)、application.yml
在resources文件里新建application.yml 删除application.properties
编写application.yml文件
#配置DataSourceSpring
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
username: 数据库用户名
password: 数据库密码
tomcat:
initialSize: 5
maxActive: 100
minIdle: 3
maxWait: 50000
main:
banner-mode: "off"
#redis配置
redis:
host: 127.0.0.1
port: 6379
database: 0
password: redis密码
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 500
min-idle: 0
lettuce:
shutdown-timeout: 0
mail:
username: 邮箱名
password: 邮箱密钥
host: smtp.qq.com
default-encoding: utf-8
properties:
mail:
smtp:
ssl:
enable: true
debug: true
# properties:
# smtp:
# auth: true
# timeout: 30000
# ssl:
# enable: true
# required: true
# Mybatis-Plus
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
typeAliasesPackage: com.lgs.bean
global-config:
db-config:
capital-mode: true
logic-delete-value: 1
logic-not-delete-value: 0
server:
port: 8081
3、后端项目编写
(1)、common文件夹(统一规范返回的信息)
新建一个common文件夹,创建如图六个文件,主要作用是统一规范返回的信息。使得返回的信息不是单一的数据,而是包含状态码的对象。 LgsConstat是一个产量类。
ApiCode.java
package com.lgs.common;
/**
* <p>
* ApiCode
* </p>
*
*/
public interface ApiCode<Enum> {
public int getCode();
public String getCodeMsg();
}
ApiResponse.java
package com.lgs.common;
import lombok.Data;
/**
* @author lgs
**/
@SuppressWarnings("unchecked")
@Data
public class ApiResponse<T> implements java.io.Serializable {
/**
* 状态码
*/
private int code;
/**
* 错误消息
*/
private String msg;
/**
* 消息响应的对象,例如:列表
*/
private T data;
/**
* 时间戳
*/
private long time;
public ApiResponse() {
super();
}
public ApiResponse(ApiCode apiCode, String msg, T data) {
this.code = apiCode.getCode();
this.msg = msg;
this.data = data;
this.time = System.currentTimeMillis();
}
public ApiResponse(ApiCode apiCode, T data) {
this.code = apiCode.getCode();
this.msg = apiCode.getCodeMsg();
this.data = data;
this.time = System.currentTimeMillis();
}
public static ApiResponse success(Object data) {
return new ApiResponse(BaseApiCode.SUCCESS, BaseApiCode.SUCCESS.getCodeMsg(), data);
}
public static ApiResponse success() {
return new ApiResponse(BaseApiCode.SUCCESS, BaseApiCode.SUCCESS.getCodeMsg(), "");
}
public static ApiResponse failed(ApiCode code, String msg) {
return new ApiResponse(code, msg, "");
}
public static ApiResponse failed(String msg) {
return new ApiResponse(BaseApiCode.FAILED, msg, "");
}
public static ApiResponse failed() {
return new ApiResponse(BaseApiCode.FAILED, BaseApiCode.FAILED.getCodeMsg(), "");
}
public static ApiResponse failed(Object data) {
return new ApiResponse(BaseApiCode.FAILED, BaseApiCode.FAILED.getCodeMsg(), data);
}
}
BaseApiCode.java
package com.lgs.common;
/**
* @author lgs
**/
public enum BaseApiCode implements ApiCode<Enum> {
/**
* 操作成功
*/
SUCCESS(0, "操作成功"),
FAILED(-1, "操作失败"),
SYSTEM_EXCEPTION(500, "System Error"),
VALID_ERROR(-1001, "验证失败"),
OBJECT_NOT_EXISTS(-1002, "对象不存在"),
OBJECT_HAS_EXISTS(-1003, "对象已存在"),
NEED_LOGIN(401, "需要登录"),
RESOURCE_NOT_FOUND(404, "Not Found");
/**
* 错误码
*/
private int code;
/**
* 错误Msg
*/
private String codeMsg;
private BaseApiCode(int code, String codeMsg) {
this.code = code;
this.codeMsg = codeMsg;
}
@Override
public int getCode() {
return this.code;
}
@Override
public String getCodeMsg() {
return this.codeMsg;
}
}
BaseApiCodeImpl.java
package com.lgs.common;
import lombok.Builder;
import lombok.Data;
/**
* <p>
* BaseApiCodeImpl
* </p>
*
* @author lgs
* @date 2020/12/4 12:06
*/
@Data
@Builder
public class BaseApiCodeImpl implements ApiCode {
private Integer code;
private String codeMsg;
@Override
public int getCode() {
return this.code;
}
@Override
public String getCodeMsg() {
return this.codeMsg;
}
}
BaseController.java
package com.lgs.common;
import com.lgs.bean.Student;
import com.lgs.service.LoginService;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
/**
* <p>
* BaseController
* </p>
*
* @author lgs
* @date 2020/12/4 11:27
*/
@SuppressWarnings("unchecked")
public class BaseController {
@Resource
private LoginService loginService;
/**
* 获取登录用户信息
*
* @param request 请求对象
* @return Student
*/
protected Student getLoginStudent(HttpServletRequest request) {
return loginService.getLoginStudent(loginService.getUserTokenHeader(request));
}
/**
* 成功返回数据
*
* @return ApiResponse
*/
protected ApiResponse success() {
return ApiResponse.success();
}
/**
* 成功返回数据
*
* @param data 待返回数据
* @return ApiResponse
*/
protected ApiResponse success(Object data) {
return ApiResponse.success(data);
}
/**
* 成功返回消息
*
* @param message 待返回成功消息
* @return ApiResponse
*/
protected ApiResponse success(String message) {
return new ApiResponse(BaseApiCode.SUCCESS, message);
}
/**
* 成功返回数据和消息
*
* @param message 待返回消息
* @param data 带返回数据
* @return ApiResponse
*/
protected ApiResponse success(String message, Object data) {
return new ApiResponse(BaseApiCode.SUCCESS, message, data);
}
/**
* 失败返回
*
* @return ApiResponse
*/
protected ApiResponse failed() {
return ApiResponse.failed();
}
/**
* 失败返回数据
*
* @param data 待返回数据
* @return ApiResponse
*/
protected ApiResponse failed(Object data) {
return ApiResponse.failed(data);
}
/**
* 失败返回消息
*
* @param message 待返回成功消息
* @return ApiResponse
*/
protected ApiResponse failed(String message) {
return new ApiResponse(BaseApiCode.FAILED, message);
}
/**
* 失败返回数据和消息
*
* @param message 待返回消息
* @param data 带返回数据
* @return ApiResponse
*/
protected ApiResponse failed(String message, Object data) {
return new ApiResponse(BaseApiCode.FAILED, message, data);
}
/**
* 失败返回数据和消息
*
* @param apiCode 状态码
* @param data 带返回数据
* @return ApiResponse
*/
protected ApiResponse failed(BaseApiCode apiCode, Object data) {
return new ApiResponse(apiCode, apiCode.getCodeMsg(), data);
}
}
LgsConstant.java
package com.lgs.common;
/**
* <p>
* LgsConstant
* </p>
*
* @author lgs
* @date 2020/12/11 10:13
*/
public class LgsConstant {
/**
* 登录缓存KEY前缀
*/
public static final String USER_TOKEN_CACHE_KEY_PREFIX = "lgs:login_user_token:";
/**
* 登录TOKEN超时时间 7天
*/
public static final long USER_TOKEN_EXPIRE_TIMEOUT = 7 * 24 * 60 * 60;
/**
* 请求头TOKEN存放KEY
*/
public static final String USER_TOKEN_HEADER_KEY = "LgsAuthorization";
}
(2)、util包(工具类包)
(2)、bean包(实体类)
新建文件夹bean(存放我们的实体类,与数据库表对应)
Activity.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 活动表
*/
@TableName("activity")
@Data
public class Activity implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//活动id
private Integer teamId;//举办活动的社团id
private String teamname;//社团名称
private String activityName;//活动名称
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;
private String address;//活动地点
private int money;//经费
private String summary;//活动简介
private String description;//活动详情
private String photos;//活动图片
}
Apply.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 申请入团
*/
@TableName("apply")
@Data
public class Apply implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//申请表id
@TableField("apply_from_id")
private Integer applyFromId;//申请人id
@TableField("apply_username")
private String applyUsername;//申请人姓名
@TableField("apply_to_id")
private Integer applyToId;//申请的社团id
private String reason;//申请理由
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;//申请时间
private String contactWay;//联系方式
private Integer isPass;//是否通过 0:待处理 1:拒绝 2:通过
}
Comments.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 评论表
*/
@TableName("comments")
@Data
public class Comments implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//留言id
private Integer teamId;//社团id
@TableField("student_id")
private Integer studentId;//留言的学生id
private String studentName;//留言的学生姓名
private Integer avatar;//用户头像
private Integer isManager;//是否是管理员
private String content;//评论的内容
private Integer supportCount;//获得的赞的数量
private Integer replyCount;//获得的回复的数量
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;//留言时间
}
CreateTeam.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 创建社团申请表
*/
@TableName("create_team")
@Data
public class CreateTeam implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//申请表id
@TableField("apply_from_id")
private Integer applyFromId;//申请人id
@TableField("apply_to_name")
private String applyToName;//申请创建的社团名称
private Integer teamType;//社团类别
private String reason;//创建理由
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;
private String contactWay;//联系方式
private Integer isPass;//是否通过该请求 0未处理 1拒绝 2通过
}
Reply.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 回复表
*/
@TableName("reply")
@Data
public class Reply implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//回复id
@TableField("student_id")
private Integer studentId;//发表回复的学生id
private String studentName;//发表回复的学生姓名
private Integer avatar;//用户头像
private Integer isManager;//是否是管理员
private String content;//回复的内容
private Integer toWhich;//针对的评论id
private Integer supportCount;//获得的赞的数量
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;//发表时间
}
Student.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@TableName("student")
@Data
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("s_no")
private String sno;
private String username;
private String password;
private Integer avatar;
private String introduce;
/**
* 0-不是 1-是 2-系统管理
*/
@TableField("is_manager")
private Integer isManager;
private String phone;
private String email;
/**
* 0男 1女
*/
private Boolean sex;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;
}
StudentLoginLog.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.lgs.handler.LongJsonDeserializer;
import com.lgs.handler.LongJsonSerializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
*
* </p>
*
* @author lgs
* @since 2020-12-13
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("student_login_log")
public class StudentLoginLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@JsonSerialize(using = LongJsonSerializer.class)
@JsonDeserialize(using = LongJsonDeserializer.class)
@TableField("id")
private Long id;
/**
* 学生ID
*/
@JsonSerialize(using = LongJsonSerializer.class)
@JsonDeserialize(using = LongJsonDeserializer.class)
@TableField("student_id")
private Long studentId;
/**
* 登录TOKEN
*/
@TableField("user_token")
private String userToken;
/**
* 登录时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 操作类型:1-登录,-1-登出
*/
@TableField("oper_type")
private Integer opType;
/**
* 登录IP
*/
@TableField("ip")
private String ip;
/**
* 登录UserAgentInfo
*/
@TableField("user_agent")
private String userAgent;
/**
* 操作系统信息
*/
@TableField("os_version")
private String osVersion;
/**
* 浏览器信息
*/
@TableField("browser_version")
private String browserVersion;
}
Team.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@TableName("team")
@Data
public class Team implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;//社团id
@TableField("teamname")
private String teamname;//社团名称
private String theme;//社团宗旨
private String description;//社团描述
private Integer persons;//社团人数
private Integer teamManagerId;//社团社长id
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;//社团创建时间
private Integer type;//类别(1思想理论 2文艺体育 3就业创业 4公益服务 5学术科研 6网络信息)
private Integer level;//等级
private String themeImg;//图片
private String contact;//社团联系方式:qq群或者wechat
}
TeamMember.java
package com.lgs.bean;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@TableName("team_member")
@Data
public class TeamMember implements Serializable {
@TableField("student_id")
private Integer studentId;//学生id
@TableField("is_manager")
private Integer isManager;//是否是管理员 0不是 1是
private String studentName;//学生姓名
@TableField("team_id")
private Integer teamId;//社团id
private String teamName;//社团名称
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField("create_time")
private LocalDateTime createTime;
}
有关dto和vo和bean的区别:百度链接
(3)、新建dto包
SmsSendDto.java
package com.lgs.dto;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
* SmsSendDto
* </p>
*
* @author lgs
* @date 2020/12/2 12:39
*/
@Data
public class SmsSendDto implements Serializable {
private static final long serialVersionUID = 1L;
private String fromUser;
private String toUser;
private String subject;
private String textContent;
}
(4)、新建vo包
StudentLoginVo.java
package com.lgs.vo;
import com.lgs.bean.Student;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
* StudentLoginVo 学生登录信息
* </p>
*
* @author lgs
* @date 2020/4/11 9:52
*/
@Data
public class StudentLoginVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 登录学生信息
*/
private Student student;
/**
* 登录Token
*/
private String userToken;
public static com.lgs.vo.StudentLoginVo factory(Student student, String userToken) {
com.lgs.vo.StudentLoginVo studentLoginVo = new com.lgs.vo.StudentLoginVo();
studentLoginVo.setStudent(student);
studentLoginVo.setUserToken(userToken);
return studentLoginVo;
}
}
(3)、mapper包(dao层)
ActivityMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Activity;
public interface ActivityMapper extends BaseMapper<Activity> {
}
ApplyMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Apply;
public interface ApplyMapper extends BaseMapper<Apply> {
}
CommentsMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Comments;
public interface CommentsMapper extends BaseMapper<Comments> {
}
CreateTeamMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.CreateTeam;
public interface CreateTeamMapper extends BaseMapper<CreateTeam> {
}
ReplyMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Reply;
public interface ReplyMapper extends BaseMapper<Reply> {
}
StudentLoginLogMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.StudentLoginLog;
/**
* <p>
* Mapper 接口
* </p>
*
* @author lgs
* @since 2020-12-13
*/
public interface StudentLoginLogMapper extends BaseMapper<StudentLoginLog> {
}
StudentMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
public interface StudentMapper extends BaseMapper<Student> {
/**
* 根据 s_no获取 student
* @param sNo
* @return
*/
@Select("select * from student where s_no=#{sno}")
Student getStudentBySno(String sNo);
/**
* 新增一个新用户
* @param sno
* @param username
* @param password
* @return
*/
@Insert("INSERT INTO student(s_no,username,password,avatar,is_manager) VALUES (#{sno},#{username},#{password},1,0)")
Boolean addNewStu(String sno, String username, String password);
}
TeamMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.Team;
public interface TeamMapper extends BaseMapper<Team> {
}
TeamMemberMapper.java
package com.lgs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lgs.bean.TeamMember;
public interface TeamMemberMapper extends BaseMapper<TeamMember> {
}
(3)、service包(service层)
四、总结
由于本人要准备专升本考试 后面的就没有写了 等后面有空了再补上;
直接上源码
前端:链接:https://pan.baidu.com/s/1AR10SIwhDXoAzkyt0t_JXw
提取码:c0d9
后端:链接:https://pan.baidu.com/s/1fTmvU0zbb0fkYs4E3i8rJA
提取码:biqw
sql文件:链接:https://pan.baidu.com/s/1hS1eAivaRWCoBg-weC77xw
提取码:ruxi
更多推荐