├── static └── .gitkeep ├── src ├── assets │ ├── css │ │ ├── common │ │ │ ├── article.less │ │ │ ├── index.less │ │ │ ├── layout.css │ │ │ ├── index.css │ │ │ ├── layout.less │ │ │ ├── layout_2.less │ │ │ ├── layout_top.less │ │ │ ├── layout_top_3.less │ │ │ └── layout_3.less │ │ ├── mixins │ │ │ ├── index.less │ │ │ └── labels.less │ │ ├── components │ │ │ ├── tag.less │ │ │ ├── alerts.less │ │ │ ├── index.less │ │ │ ├── badge.less │ │ │ ├── list-group.less │ │ │ ├── button.less │ │ │ ├── labels.less │ │ │ ├── modal.less │ │ │ ├── check-label.less │ │ │ └── table.less │ │ └── app.less │ ├── icon │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.css │ ├── image │ │ ├── loginbg.png │ │ └── global │ │ │ └── notice-icon │ │ │ ├── plus.png │ │ │ ├── mailer.png │ │ │ ├── notice.png │ │ │ ├── shoucang.png │ │ │ └── no-notice.svg │ ├── js │ │ ├── time_format.js │ │ ├── config.js │ │ ├── notice.js │ │ ├── file_format.js │ │ ├── http.js │ │ ├── storage.js │ │ ├── notify.js │ │ └── date_time.js │ └── svg-loaders │ │ ├── oval.svg │ │ ├── hearts.svg │ │ ├── tail-spin.svg │ │ ├── audio.svg │ │ ├── puff.svg │ │ ├── three-dots.svg │ │ ├── rings.svg │ │ ├── circles.svg │ │ ├── ball-triangle.svg │ │ ├── grid.svg │ │ ├── bars.svg │ │ └── spinning-circles.svg ├── const │ └── common.js ├── store │ ├── modules │ │ ├── common.js │ │ └── menu.js │ ├── state.js │ ├── mutations.js │ ├── index.js │ └── actions.js ├── router │ ├── personal.js │ ├── home.js │ ├── index.js │ ├── user.js │ ├── team.js │ ├── project.js │ └── system.js ├── api │ ├── other.js │ ├── common.js │ ├── team.js │ ├── user.js │ └── system.js ├── components │ ├── editor.vue │ ├── socket.vue │ ├── check-label.vue │ ├── menu-slide.vue │ ├── wrapper-content.vue │ └── editor_2.0.vue ├── main.js ├── views │ ├── system │ │ ├── setting │ │ │ └── base │ │ │ │ └── system-setting-base.vue │ │ └── auth │ │ │ ├── auth-rule-add.vue │ │ │ ├── menu-model-add.vue │ │ │ ├── auth-rule-edit.vue │ │ │ ├── menu-model-edit.vue │ │ │ ├── auth-menu-add.vue │ │ │ └── auth-menu-edit.vue │ ├── user │ │ └── profile │ │ │ └── user-ass-group-access.vue │ ├── team │ │ └── user │ │ │ ├── level │ │ │ └── detail.vue │ │ │ └── position │ │ │ └── detail.vue │ └── project │ │ └── task │ │ └── task-overview.vue └── App.vue ├── .eslintignore ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── .gitignore ├── .editorconfig ├── .postcssrc.js ├── .babelrc ├── index.html ├── .eslintrc.js ├── package.json └── README.md /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/css/common/article.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/css/mixins/index.less: -------------------------------------------------------------------------------- 1 | @import "labels"; 2 | @import "check-label"; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log* 3 | yarn-debug.log* 4 | yarn-error.log* 5 | -------------------------------------------------------------------------------- /src/const/common.js: -------------------------------------------------------------------------------- 1 | export const COMMON = { 2 | PAGE_SIZE: 20, 3 | PAGE_NUM: 1, 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/icon/iconfont.eot -------------------------------------------------------------------------------- /src/assets/icon/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/icon/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/image/loginbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/image/loginbg.png -------------------------------------------------------------------------------- /src/assets/icon/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/icon/iconfont.woff -------------------------------------------------------------------------------- /src/assets/css/common/index.less: -------------------------------------------------------------------------------- 1 | @import "base"; 2 | @import "article"; 3 | @import "layout_top_3"; 4 | @import "layout_3"; -------------------------------------------------------------------------------- /src/assets/css/components/tag.less: -------------------------------------------------------------------------------- 1 | /* TAG*/ 2 | .ivu-tag{ 3 | line-height: 20px; 4 | } 5 | .tag-circle{ 6 | border-radius: 25px; 7 | } -------------------------------------------------------------------------------- /src/store/modules/common.js: -------------------------------------------------------------------------------- 1 | const common = { 2 | state: { 3 | }, 4 | mutations: { 5 | 6 | } 7 | } 8 | export default common -------------------------------------------------------------------------------- /src/assets/image/global/notice-icon/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/image/global/notice-icon/plus.png -------------------------------------------------------------------------------- /src/assets/css/components/alerts.less: -------------------------------------------------------------------------------- 1 | .alert-danger { 2 | color: @error-color; 3 | background-color: #ffebe6; 4 | border-color: #ffd6cc; 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/image/global/notice-icon/mailer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/image/global/notice-icon/mailer.png -------------------------------------------------------------------------------- /src/assets/image/global/notice-icon/notice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/image/global/notice-icon/notice.png -------------------------------------------------------------------------------- /src/assets/image/global/notice-icon/shoucang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gytai/projectManage/master/src/assets/image/global/notice-icon/shoucang.png -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /src/assets/css/app.less: -------------------------------------------------------------------------------- 1 | @import "./custom"; 2 | @import '~iview/src/styles/index.less'; 3 | @import "./mixins/index"; 4 | @import "common/index"; 5 | @import "components/index"; 6 | 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserlist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/assets/css/mixins/labels.less: -------------------------------------------------------------------------------- 1 | // Labels 2 | 3 | .label-variant(@color) { 4 | background-color: @color; 5 | 6 | &[href] { 7 | &:hover, 8 | &:focus { 9 | background-color: darken(@color, 10%); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/assets/css/components/index.less: -------------------------------------------------------------------------------- 1 | @import "check-label"; 2 | @import "labels"; 3 | @import "tag"; 4 | //@import "alerts"; 5 | @import "badge"; 6 | @import "button"; 7 | @import "table"; 8 | //@import "list-group"; 9 | @import "modal"; 10 | @import "task"; -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }], 4 | "stage-2" 5 | ], 6 | "plugins": ["transform-runtime"], 7 | "comments": false, 8 | "env": { 9 | "test": { 10 | "presets": ["env", "stage-2"], 11 | "plugins": [ "istanbul" ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/router/personal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 个人 3 | */ 4 | export default [ 5 | { 6 | name: 'personal_notice_list', 7 | path: '/personal/notice/list', 8 | component: resolve => require(['@/views/personal/notice/list'], resolve), 9 | meta: {model: 'Project'}, 10 | }, 11 | ]; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | projectManage 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/api/other.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | export function getYiYan(callback, type) { 3 | if (type === undefined) { 4 | type = 'f'; 5 | } 6 | let api = 'https://v1.hitokoto.cn/?c=' + type + '&encode=json'; 7 | $.get({ 8 | url: api, 9 | success: function (data) { 10 | callback(data); 11 | } 12 | }) 13 | } -------------------------------------------------------------------------------- /src/assets/js/time_format.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by vilson on 17/6/4. 3 | */ 4 | import moment from 'moment' 5 | export const showBeforeTime = (time,format) => { 6 | if(format === undefined) { 7 | return moment(time,'YYYYMMDDHHmm').locale('zh-cn').fromNow() 8 | }else{ 9 | return moment(time).locale('zh-cn').format("YYYY年MMMDo HH:mm"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/assets/css/components/badge.less: -------------------------------------------------------------------------------- 1 | 2 | /* BADGE COLOR*/ 3 | .badge-success{ 4 | background: @primary-color; 5 | color: #fff; 6 | } 7 | .badge-info{ 8 | background: @info-color; 9 | color: #fff; 10 | } 11 | .badge-warning{ 12 | background: @warning-color; 13 | color: #fff; 14 | } 15 | .badge-error{ 16 | background: @error-color; 17 | color: #fff; 18 | } -------------------------------------------------------------------------------- /src/assets/js/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2017/6/10. 3 | */ 4 | module.exports = { 5 | VERSION: '1.2.1', 6 | NODE_ENV: 'development',//production,development 7 | DEV_URL: 'http://127.0.0.1/ApiForProjectManage/public', 8 | PROD_URL: 'https://project.vilson.xyz/public', 9 | WEB_URL: 'http://127.0.0.1/ApiForProjectManage' 10 | }; 11 | -------------------------------------------------------------------------------- /src/assets/css/components/list-group.less: -------------------------------------------------------------------------------- 1 | .list-group{ 2 | margin: 10px 0; 3 | } 4 | .list-group.clear-list .list-group-item { 5 | border-top: 1px solid #e7eaec; 6 | border-bottom: 0; 7 | border-right: 0; 8 | border-left: 0; 9 | padding: 10px 0; 10 | } 11 | .list-group-item { 12 | background-color: inherit; 13 | border: 1px solid #e7eaec; 14 | display: block; 15 | margin-bottom: -1px; 16 | padding: 10px 15px; 17 | position: relative; 18 | } 19 | .fist-item { 20 | border-top: none !important; 21 | } -------------------------------------------------------------------------------- /src/router/home.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Home 3 | */ 4 | export default [ 5 | { 6 | path: '/', 7 | name: 'index', 8 | redirect: '/project/overview', 9 | meta: {model: 'login'}, 10 | }, 11 | { 12 | name: 'login', 13 | path: '/login', 14 | component: resolve => require(['@/views/user/login'], resolve), 15 | meta: {model: 'login'}, 16 | }, 17 | { 18 | name: 'account_info', 19 | path: '/account/info', 20 | component: resolve => require(['@/views/account/info'], resolve), 21 | meta: {}, 22 | }, 23 | ]; -------------------------------------------------------------------------------- /src/assets/css/components/button.less: -------------------------------------------------------------------------------- 1 | @btn-padding-large : 6px 15px 6px 15px; 2 | .middle-btn{ 3 | min-width: 100px; 4 | } 5 | .small-btn{ 6 | min-width: 75px; 7 | } 8 | .ivu-btn:active, .ivu-btn.active { 9 | outline: 0; 10 | background-image: none; 11 | -webkit-box-shadow: none; 12 | box-shadow: none; 13 | } 14 | .member-task-row-class{ 15 | cursor: pointer; 16 | border-left: 3px solid #FFF; 17 | } 18 | .member-task-row-class:hover{ 19 | border-left-color: orange; 20 | } 21 | .member-task-row-class.ivu-table-row-hover td{ 22 | background-color:#f5f5f5 !important; 23 | } 24 | .member-task-row-class td{ 25 | border:none; 26 | } -------------------------------------------------------------------------------- /src/store/state.js: -------------------------------------------------------------------------------- 1 | import {getStore} from "../assets/js/utils"; 2 | 3 | export default { 4 | socketAction: '', 5 | logged : false, 6 | page_loading: false, // 页面加载loading 7 | list_reload: false, // 返回上级是否重新加载列表 8 | show_menu_slide: true, // 是否显示侧边的导航栏 9 | user_info: getStore('user_info', true) ? getStore('user_info', true) : null,// 当前用户信息 10 | online_user: [],//在线用户 11 | notify_no_read_list: [], //未读消息列表 12 | notify_no_read_count: 0, 13 | system_info: getStore('system_info', true) ? getStore('system_info', true) : {'site_name': ''}, // 站点信息 14 | last_path: getStore('last_path') ? getStore('last_path') : '/project/overview', // 上次访问地址 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/css/common/layout.css: -------------------------------------------------------------------------------- 1 | .layout { 2 | /*width: 1200px !important;*/ 3 | margin: auto; 4 | background: #efeff4; 5 | } 6 | .page-content { 7 | top: 60px; 8 | bottom: 0; 9 | position: fixed; 10 | width: 100%; 11 | overflow-x: auto; 12 | } 13 | .wrapper-content { 14 | padding: 0 0 0 200px; 15 | /*margin-left: 240px;*/ 16 | margin-top: 60px; 17 | position: absolute; 18 | width: 100%; 19 | } 20 | .layout-content { 21 | min-height: 200px; 22 | padding: 25px 20px; 23 | overflow: hidden; 24 | background: #fff; 25 | } 26 | .layout-copy { 27 | text-align: center; 28 | padding: 10px 0 20px; 29 | color: #9ea7b4; 30 | } 31 | /*Slide*/ 32 | .ivu-menu-item-active .ivu-menu-submenu-title { 33 | color: #2d8cf0; 34 | font-weight: 700; 35 | } 36 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/oval.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import store from '@/store' 3 | import Router from 'vue-router' 4 | import Home from './home'; 5 | import Project from './project'; 6 | import System from './system'; 7 | import Team from './team'; 8 | import User from './user'; 9 | import Personal from './personal'; 10 | 11 | Vue.use(Router); 12 | const router = new Router({ 13 | routes: [].concat( 14 | Home, 15 | Project, 16 | System, 17 | Team, 18 | User, 19 | Personal 20 | ) 21 | }); 22 | 23 | router.beforeEach((to, from, next) => { 24 | next(); 25 | }); 26 | router.afterEach(route => { 27 | //预留 28 | if (route.name !== 'login') { 29 | store.dispatch('SET_LAST_PATH', route.fullPath); 30 | } 31 | }); 32 | 33 | export default router 34 | -------------------------------------------------------------------------------- /src/assets/css/common/index.css: -------------------------------------------------------------------------------- 1 | .text-default { 2 | color: #383838; 3 | } 4 | .layout { 5 | /*width: 1200px !important;*/ 6 | margin: auto; 7 | background: #efeff4; 8 | } 9 | .page-content { 10 | top: 60px; 11 | bottom: 0; 12 | position: fixed; 13 | width: 100%; 14 | overflow-x: auto; 15 | } 16 | .wrapper-content { 17 | padding: 0 0 0 200px; 18 | /*margin-left: 240px;*/ 19 | margin-top: 60px; 20 | position: absolute; 21 | width: 100%; 22 | } 23 | .layout-content { 24 | min-height: 200px; 25 | padding: 25px 20px; 26 | overflow: hidden; 27 | background: #fff; 28 | } 29 | .layout-copy { 30 | text-align: center; 31 | padding: 10px 0 20px; 32 | color: #9ea7b4; 33 | } 34 | /*Slide*/ 35 | .ivu-menu-item-active .ivu-menu-submenu-title { 36 | color: #2d8cf0; 37 | font-weight: 700; 38 | } 39 | -------------------------------------------------------------------------------- /src/router/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户 3 | */ 4 | export default [ 5 | { 6 | name: 'user_list', 7 | path: '/user/list', 8 | component: resolve => require(['@/views/user/profile/user-list'], resolve), 9 | meta: {model: 'Project'}, 10 | children: [ 11 | { 12 | name: 'ass_group_access', 13 | path: '/user/ass_group_access/:user_id', 14 | component: resolve => require(['@/views/user/profile/user-ass-group-access'], resolve), 15 | meta: {model: 'Project', parent: '/user/list'}, 16 | } 17 | ] 18 | }, 19 | { 20 | name: 'user_base_setting', 21 | path: '/user/base_setting', 22 | component: resolve => require(['@/views/user/setting/base/user-base-setting'], resolve), 23 | meta: {model: 'Project'} 24 | } 25 | ]; -------------------------------------------------------------------------------- /src/components/editor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 13 | // extends: 'standard', 14 | extends: 'eslint:recommended', 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'html' 18 | ], 19 | // add your custom rules here 20 | 'rules': { 21 | // allow paren-less arrow functions 22 | 'arrow-parens': 0, 23 | // allow console 24 | 'no-console': 'off', 25 | // allow unused 26 | 'no-unused-vars': 0, 27 | // allow async-await 28 | 'generator-star-spacing': 0, 29 | 30 | 'no-undef': 0, 31 | // allow debugger during development 32 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/store/mutations.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET_LOGGED(state, {token, user_info}) { 3 | state.logged = true; 4 | state.user_info = user_info; 5 | }, 6 | SET_LOGOUT(state) { 7 | state.logged = false; 8 | state.user_info = null; 9 | }, 10 | SET_PAGE_LOADING(state, status) { 11 | state.page_loading = status 12 | }, 13 | SET_LIST_RELOAD(state, reload) { 14 | state.list_reload = reload 15 | }, 16 | SET_MENU_SLIDE(state, status) { 17 | state.show_menu_slide = status 18 | }, 19 | UPDATE_ONLINE_USER(state, data) { 20 | state.online_user = data; 21 | }, 22 | UPDATE_NOTIFY_NO_READ_LIST(state, data) { 23 | state.notify_no_read_list = data; 24 | }, 25 | UPDATE_NOTIFY_NO_READ_COUNT(state, num) { 26 | state.notify_no_read_count = num; 27 | }, 28 | SET_SYSTEM_INFO(state, data) { 29 | state.system_info = data; 30 | }, 31 | SET_LAST_PATH(state, path) { 32 | state.last_path = path; 33 | }, 34 | catchSocketAction(state, data) { 35 | state.socketAction = data; 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/api/common.js: -------------------------------------------------------------------------------- 1 | import $http from '../assets/js/http' 2 | 3 | export function getNotifyList(page_size = 5, data = {}) { 4 | let params = {page_size: page_size}; 5 | params = Object.assign(params, data); 6 | return $http.post('Common_Notify.getList', params); 7 | } 8 | 9 | export function getNotifyListForUser() { 10 | return $http.post('Common_Notify.getListForUser'); 11 | } 12 | 13 | export function getTicketRead(id) { 14 | return $http.post('Common_Notify.ticketRead', {id: id}); 15 | } 16 | 17 | export function batchTicketRead() { 18 | return $http.post('Common_Notify.batchTicketRead'); 19 | } 20 | 21 | export function setFinallySendTime(ids) { 22 | return $http.post('Common_Notify.setFinallySendTime', {ids: ids}); 23 | } 24 | 25 | export function getNotifyTypeList(ids) { 26 | return $http.post('Common_Notify.getNotifyTypeList', {ids: ids}); 27 | } 28 | 29 | export function Search(keyword) { 30 | return $http.post('Common_Search.search', {keyword: keyword}); 31 | } 32 | export function bindClientId(client_id, uid) { 33 | return $http.post('Common_Notify.bindClientId', {client_id: client_id, uid: uid}); 34 | } 35 | -------------------------------------------------------------------------------- /src/assets/js/notice.js: -------------------------------------------------------------------------------- 1 | import {Message,Notice} from 'iview' 2 | 3 | export default (content, type = 'message', action = 'warning', duration = 2) => { 4 | let config = {}; 5 | config.duration = duration; 6 | if (type === 'message') { 7 | config.content = content; 8 | switch (action) { 9 | case 'info': 10 | return Message.info(config); 11 | case 'success': 12 | return Message.success(config); 13 | case 'error': 14 | return Message.success(config); 15 | case 'loading': 16 | return Message.loading(config); 17 | default: 18 | return Message.warning(config); 19 | } 20 | } else { 21 | config.title = content.title; 22 | config.desc = content.desc || ''; 23 | switch (action) { 24 | case 'open': 25 | return Notice.open(config); 26 | case 'info': 27 | return Notice.info(config); 28 | case 'success': 29 | return Notice.success(config); 30 | case 'error': 31 | return Notice.success(config); 32 | default: 33 | return Notice.warning(config); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console,no-unused-vars */ 2 | // The Vue build version to load with the `import` command 3 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 4 | import Vue from 'vue' 5 | import VueRouter from 'vue-router' 6 | import iView from 'iview' 7 | import VueDND from 'awe-dnd' 8 | import App from './App' 9 | import store from './store' 10 | import router from './router' 11 | import 'iview/dist/styles/iview.css' 12 | import vuescroll from 'vuescroll'; 13 | import 'vuescroll/dist/vuescroll.css'; 14 | import '@/assets/css/app.less' 15 | import '@/assets/icon/iconfont' 16 | import CheckLabel from '@/components/check-label'; 17 | 18 | Vue.use(VueRouter); 19 | Vue.use(store); 20 | 21 | Vue.config.productionTip = false; 22 | Vue.use(iView); 23 | Vue.use(VueDND); 24 | 25 | Vue.component('CheckLabel', CheckLabel); 26 | 27 | Vue.use(vuescroll); 28 | Vue.prototype.$vuescrollConfig = { 29 | vuescroll: { 30 | mode: 'native' 31 | }, 32 | scrollPanel: { 33 | scrollingX: false, 34 | }, 35 | bar: { 36 | delayTime: 500, 37 | onlyShowBarOnScroll: true, 38 | background: "#cecece", 39 | } 40 | }; 41 | 42 | new Vue({ 43 | el: '#app', 44 | store, 45 | router, 46 | template: '', 47 | components: {App} 48 | }); 49 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/hearts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import state from './state' 4 | import mutations from './mutations' 5 | import actions from './actions' 6 | import common from './modules/common' 7 | import menu from './modules/menu' 8 | import {getStore, setStore} from '@/assets/js/storage' 9 | 10 | Vue.use(Vuex) 11 | // const state2 = { 12 | // menu_model: '', // 当前选中的菜单模块 13 | // menu_top: false, 14 | // menu_slide: false, 15 | // menu_data: { 16 | // menu_list: [], 17 | // menu_list_old: [], //未格式化前的列表 18 | // menu_model_list: [], 19 | // menu_model_list_all: [], 20 | // menu_model: '', 21 | // } 22 | // } 23 | // state.user_info = getStore('user_info', true) ? getStore('user_info', true) : state.user_info 24 | // state.system_info = getStore('system_info', true) ? getStore('system_info', true) : state.system_info 25 | // 26 | // state.menu_data.menu_list = getStore('menu_list', true) 27 | // state.menu_data.menu_list_old = getStore('menu_list_old', true) 28 | // state.menu_data.menu_model_list = getStore('menu_model_list', true) 29 | // state.menu_data.menu_model_list_all = getStore('menu_model_list_all', true) 30 | // state.menu_data.menu_model = getStore('menu_model') 31 | 32 | 33 | const store = new Vuex.Store({ 34 | modules: { 35 | common, 36 | menu 37 | }, 38 | state, 39 | mutations, 40 | actions 41 | }); 42 | export default store 43 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/tail-spin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/assets/icon/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1496642611968'); /* IE9*/ 4 | src: url('iconfont.eot?t=1496642611968#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('iconfont.woff?t=1496642611968') format('woff'), /* chrome, firefox */ 6 | url('iconfont.ttf?t=1496642611968') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1496642611968#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-img:before { content: "\e657"; } 19 | 20 | .icon-excel:before { content: "\e61c"; } 21 | 22 | .icon-word:before { content: "\e61f"; } 23 | 24 | .icon-file:before { content: "\e689"; } 25 | 26 | .icon-js:before { content: "\e6b2"; } 27 | 28 | .icon-MP:before { content: "\e670"; } 29 | 30 | .icon-txt:before { content: "\e668"; } 31 | 32 | .icon-file_csv:before { content: "\e724"; } 33 | 34 | .icon-file_ppt:before { content: "\e726"; } 35 | 36 | .icon-file_word:before { content: "\e729"; } 37 | 38 | .icon-pdf:before { content: "\e72c"; } 39 | 40 | .icon-zip:before { content: "\e661"; } 41 | 42 | .icon-rar:before { content: "\e662"; } 43 | 44 | .icon-file_css:before { content: "\e6bd"; } 45 | 46 | .icon-file_video:before { content: "\e6bf"; } 47 | 48 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/audio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 15 | 16 | 17 | 21 | 22 | 23 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/assets/css/components/labels.less: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Labels 4 | // -------------------------------------------------- 5 | 6 | 7 | .label { 8 | display: inline; 9 | padding: .3em .8em; 10 | font-size: 75%; 11 | //font-weight: bold; 12 | line-height: 1; 13 | color: #FFF; 14 | text-align: center; 15 | white-space: nowrap; 16 | vertical-align: baseline; 17 | border-radius: .25em; 18 | background-color: #d1dade; 19 | //font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 20 | text-shadow: none; 21 | 22 | // Add hover effects, but only for links 23 | a& { 24 | &:hover, 25 | &:focus { 26 | color: #FFF; 27 | text-decoration: none; 28 | cursor: pointer; 29 | } 30 | } 31 | 32 | // Empty labels collapse automatically (not available in IE8) 33 | &:empty { 34 | display: none; 35 | } 36 | 37 | // Quick fix for labels in buttons 38 | .btn & { 39 | position: relative; 40 | top: -1px; 41 | } 42 | } 43 | 44 | // Colors 45 | // Contextual variations (linked labels get darker on :hover) 46 | 47 | .label-default { 48 | //background-color(@default-color); 49 | } 50 | 51 | .label-primary { 52 | background-color:(@primary-color); 53 | } 54 | 55 | .label-success { 56 | background-color:(@success-color); 57 | } 58 | 59 | .label-info { 60 | background-color:(@info-color); 61 | } 62 | 63 | .label-warning { 64 | background-color:(@warning-color); 65 | } 66 | 67 | .label-danger { 68 | background-color:(@error-color); 69 | } -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import {getStore, setStore,removeStore} from '@/assets/js/storage' 2 | 3 | export default { 4 | SET_LOGGED({commit, state}, data) { 5 | setStore('token', data.token, true, data.duration); 6 | setStore('user_info', data.user_info); 7 | commit('SET_LOGGED', data); 8 | }, 9 | SET_LOGOUT({commit}) { 10 | removeStore('token'); 11 | removeStore('token'); 12 | removeStore('menu_list'); 13 | removeStore('menu_model_list'); 14 | removeStore('menu_model'); 15 | removeStore('user_info'); 16 | removeStore('user_name'); 17 | commit('SET_LOGOUT'); 18 | }, 19 | SET_PAGE_LOADING({commit}, status) { 20 | commit('SET_PAGE_LOADING', status); 21 | }, 22 | SET_LIST_RELOAD({commit}, status) { 23 | commit('SET_LIST_RELOAD', status); 24 | }, 25 | SET_MENU_SLIDE({commit}, status) { 26 | commit('SET_MENU_SLIDE', status); 27 | }, 28 | UPDATE_ONLINE_USER({commit}, data) { 29 | commit('UPDATE_ONLINE_USER', data); 30 | }, 31 | UPDATE_NOTIFY_NO_READ_LIST({commit}, data) { 32 | commit('UPDATE_NOTIFY_NO_READ_LIST', data); 33 | }, 34 | UPDATE_NOTIFY_NO_READ_COUNT({commit}, num) { 35 | commit('UPDATE_NOTIFY_NO_READ_COUNT', num); 36 | }, 37 | SET_SYSTEM_INFO({commit}, data) { 38 | setStore('system_info', data); 39 | commit('SET_SYSTEM_INFO', data); 40 | }, 41 | SET_LAST_PATH({commit}, path) { 42 | setStore('last_path', path); 43 | commit('SET_LAST_PATH', path); 44 | }, 45 | } -------------------------------------------------------------------------------- /src/assets/svg-loaders/puff.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/three-dots.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 13 | 14 | 18 | 22 | 23 | 24 | 28 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/router/team.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 团队 3 | */ 4 | export default [ 5 | { 6 | name: 'team_list', 7 | path: '/team/list', 8 | component: resolve => require(['@/views/team/list'], resolve), 9 | meta: {model: 'Project'} 10 | }, 11 | { 12 | name: 'team_user_list', 13 | path: '/team/user/list/:team_id', 14 | component: resolve => require(['@/views/team/user/list'], resolve), 15 | meta: {model: 'Project', parent: '/team/list'}, 16 | }, 17 | { 18 | name: 'team_user_detail', 19 | path: '/team/user/detail/:user_id', 20 | component: resolve => require(['@/views/team/user/detail'], resolve), 21 | meta: {model: 'Project', parent: '/user/list'}, 22 | }, 23 | { 24 | name: 'team_user_level_list', 25 | path: '/team/user/level/list', 26 | component: resolve => require(['@/views/team/user/level/list'], resolve), 27 | meta: {model: 'Project'}, 28 | }, 29 | { 30 | name: 'team_user_level_detail', 31 | path: '/team/user/level/detail/:id', 32 | component: resolve => require(['@/views/team/user/level/detail'], resolve), 33 | meta: {model: 'Project', parent: '/team/user/level/list'}, 34 | }, 35 | { 36 | name: 'team_user_position_list', 37 | path: '/team/user/position/list', 38 | component: resolve => require(['@/views/team/user/position/list'], resolve), 39 | meta: {model: 'Project'}, 40 | }, 41 | { 42 | name: 'team_user_position_detail', 43 | path: '/team/user/position/detail/:id', 44 | component: resolve => require(['@/views/team/user/position/detail'], resolve), 45 | meta: {model: 'Project', parent: '/team/user/position/list'}, 46 | }, 47 | ]; -------------------------------------------------------------------------------- /src/assets/js/file_format.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by vilson on 17/6/4. 3 | */ 4 | export const format = (file_ext) => { 5 | const format = file_ext || ''; 6 | let type = '#icon-file'; 7 | 8 | if (['gif','jpg','jpeg','png','bmp','webp'].indexOf(format) > -1) { 9 | type = '#icon-img'; 10 | } 11 | if (['mp4','m3u8','rmvb','avi','swf','3gp','mkv','flv'].indexOf(format) > -1) { 12 | type = '#icon-file_video'; 13 | } 14 | if (['mp3','wav','wma','ogg','aac','flac'].indexOf(format) > -1) { 15 | type = '#icon-MP'; 16 | } 17 | if (['js'].indexOf(format) > -1) { 18 | type = '#icon-js'; 19 | } 20 | if (['css'].indexOf(format) > -1) { 21 | type = '#icon-file_css'; 22 | } 23 | if (['txt'].indexOf(format) > -1) { 24 | type = '#icon-txt'; 25 | } 26 | if (['pdf'].indexOf(format) > -1) { 27 | type = '#icon-pdf'; 28 | } 29 | if (['zip'].indexOf(format) > -1) { 30 | type = '#icon-zip'; 31 | } 32 | if (['rar'].indexOf(format) > -1) { 33 | type = '#icon-rar'; 34 | } 35 | if (['doc','docx','wps'].indexOf(format) > -1) { 36 | type = '#icon-word'; 37 | } 38 | if (['pages','epub'].indexOf(format) > -1) { 39 | type = '#icon-file'; 40 | } 41 | if (['numbers','xls','xlsx'].indexOf(format) > -1) { 42 | type = '#icon-excel'; 43 | } 44 | if (['csv'].indexOf(format) > -1) { 45 | type = '#icon-file_csv'; 46 | } 47 | if (['keynote','ppt','pptx'].indexOf(format) > -1) { 48 | type = '#icon-file_ppt'; 49 | } 50 | 51 | return type; 52 | } 53 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/rings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 14 | 18 | 19 | 20 | 25 | 29 | 33 | 34 | 35 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/circles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/css/components/modal.less: -------------------------------------------------------------------------------- 1 | .ivu-modal-footer{ 2 | border-top: none; 3 | } 4 | .ivu-modal-header { 5 | border-bottom: none; 6 | } 7 | .ivu-modal-footer .ivu-btn{ 8 | min-width: 96px; 9 | } 10 | 11 | .form-modal .ivu-modal-body { 12 | padding-top: 22px; 13 | } 14 | 15 | .form-modal .footer-item .ivu-form-item { 16 | margin-bottom: 0; 17 | } 18 | 19 | .form-modal .footer-item .ivu-btn.ivu-btn-long { 20 | margin-bottom: 10px; 21 | } 22 | 23 | .form-modal .ivu-modal-footer { 24 | border-top: none; 25 | padding: 0; 26 | } 27 | 28 | .team-user { 29 | cursor: pointer; 30 | } 31 | .team-user .user-item { 32 | display: inline-block; 33 | float: left; 34 | margin-right: 10px; 35 | } 36 | .team-user .user-detail { 37 | } 38 | .team-user .ivu-table-cell { 39 | padding-top: 10px; 40 | padding-bottom: 10px; 41 | } 42 | 43 | .team-user .ivu-table tr:last-child td { 44 | border-bottom: none; 45 | } 46 | 47 | .user-modal .ivu-modal-body { 48 | padding: 0 16px; 49 | } 50 | 51 | .user-modal .ivu-modal-footer { 52 | border: none; 53 | } 54 | 55 | .user-modal .ivu-modal-content { 56 | min-height: 450px; 57 | max-height: 600px !important; 58 | overflow-y: auto !important; 59 | } 60 | 61 | .user-modal .list-title { 62 | padding: 0 0 10px 0; 63 | border-bottom: 1px solid #e5e5e5; 64 | } 65 | 66 | .user-modal .user-list { 67 | margin-top: 15px; 68 | } 69 | 70 | .user-modal .user-list > li { 71 | line-height: 35px; 72 | list-style: none; 73 | } 74 | 75 | .name-label { 76 | vertical-align: middle; 77 | margin-left: 5px; 78 | } 79 | 80 | .user-modal .tip { 81 | color: #808080; 82 | } 83 | 84 | .user-modal .illustration { 85 | width: 132px; 86 | height: 97px; 87 | background-size: 132px 97px; 88 | margin: 60px auto 22px auto; 89 | background-image: url(https://dn-st.teambition.net/teambition/images/illustration-baton@3x.e5f44865.png); 90 | } 91 | 92 | .date-time-modal .ivu-modal{ 93 | width: 250px !important; 94 | } 95 | .date-time-modal .ivu-modal-content{ 96 | height: 415px; 97 | } -------------------------------------------------------------------------------- /src/api/team.js: -------------------------------------------------------------------------------- 1 | import $http from '../assets/js/http' 2 | 3 | export async function getTeamUser(team_id = 0, page_size = 50, page_num = 1, keyword = '') { 4 | return $http.post('Team_Team.getTeamUser', { 5 | team_id: team_id, 6 | page_size: page_size, 7 | page_num: page_num, 8 | keyword: keyword 9 | }); 10 | } 11 | 12 | 13 | export function getList(pid = 0, page_size, page_num, keyword) { 14 | return $http.post('Team_Team.getList', { 15 | pid: pid, 16 | page_size: page_size, 17 | page_num: page_num, 18 | keyword: keyword, 19 | }); 20 | } 21 | 22 | export function getNoInTeamUser(team_id = 0, page_size = 20, page_num = 1, keyword = '') { 23 | return $http.post('Team_Team.getNoInTeamUser', { 24 | team_id: team_id, 25 | page_size: page_size, 26 | page_num: page_num, 27 | keyword: keyword 28 | }); 29 | } 30 | 31 | export function addTeamUser(team_id, user_id) { 32 | return $http.post('Team_Team.addTeamUser', { 33 | team_id: team_id, 34 | user_id: user_id 35 | }); 36 | } 37 | export function delTeamUser(team_id, user_id) { 38 | return $http.post('Team_User.delTeamUser', { 39 | team_id: team_id, 40 | user_id: user_id 41 | }); 42 | } 43 | 44 | export function editLeader(team_id, user_id, state) { 45 | return $http.post('Team_Team.editLeader', { 46 | team_id: team_id, 47 | user_id: user_id, 48 | state: state 49 | }); 50 | } 51 | 52 | export function getInfo(team_id) { 53 | return $http.post('Team_Team.getInfo', {team_id: team_id}); 54 | } 55 | 56 | export function delTeam(ids) { 57 | return $http.post('Team_Team.delTeam', {ids: ids}); 58 | } 59 | 60 | export function changeState(team_id, state) { 61 | return $http.post('Team_Team.changeState', {team_id: team_id, state: state}); 62 | } 63 | 64 | export function doTeam(action = 'add', data) { 65 | let url = 'Team_Team.addTeam'; 66 | if (action === 'edit') { 67 | url = 'Team_Team.editTeam' 68 | } 69 | return $http.post(url, data); 70 | } 71 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: 'https://static.vilson.xyz/project/', // 部署到生产环境的时候的CDN地址 11 | productionSourceMap: false, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8050, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: { 31 | '/api': { 32 | // target: 'http://dev.phalapi.com/', 33 | target: 'http://127.0.0.1/ApiForProjectManage/public/', 34 | changeOrigin: true, 35 | secure: false, 36 | pathRewrite: { 37 | '^/api': '' 38 | } 39 | } 40 | }, 41 | // CSS Sourcemaps off by default because relative paths are "buggy" 42 | // with this option, according to the CSS-Loader README 43 | // (https://github.com/webpack/css-loader#sourcemaps) 44 | // In our experience, they generally work as expected, 45 | // just be aware of this issue when enabling this option. 46 | cssSourceMap: false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/ball-triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 17 | 18 | 19 | 25 | 31 | 32 | 33 | 38 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 13 | 14 | 15 | 19 | 20 | 21 | 25 | 26 | 27 | 31 | 32 | 33 | 37 | 38 | 39 | 43 | 44 | 45 | 49 | 50 | 51 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/assets/js/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by vilson on 2017/5/8. 3 | */ 4 | import {Message,Notice} from 'iview' 5 | import Axios from "axios" 6 | import * as utils from './utils' 7 | import $store from '../../store'; 8 | import $router from '../../router'; 9 | import $notice from './notice'; 10 | 11 | const $http = Axios.create(); 12 | // Before request 13 | $http.interceptors.request.use( 14 | config => { 15 | config.url = utils.getApiUrl(config.url); 16 | if (config.method === 'post') { 17 | const querystring = require('querystring'); 18 | config.data = querystring.stringify(config.data) 19 | } 20 | let token = utils.getStore('token'); 21 | if (token) { 22 | config.headers.Authorization = token; 23 | config.headers.Token = token; 24 | } 25 | 26 | 27 | return config; 28 | }, 29 | error => { 30 | return Promise.reject(error); 31 | } 32 | ); 33 | // After request 34 | $http.interceptors.response.use( 35 | response => { 36 | response = response.data; 37 | let data = response.data; 38 | if (response.ret < 300) { 39 | response.msg !== '' && $notice(response.msg); 40 | return response; 41 | } else if (response.ret === 499 || response.ret === 401) { 42 | // $notice('登录超时,请重新登录'); 43 | $router.replace('/login?redirect=' + $router.currentRoute.fullPath); 44 | $store.dispatch('SET_LOGOUT'); 45 | return new Promise(() => { 46 | }); 47 | } else if (response.ret < 500) { 48 | $notice({ 49 | title: '请求错误 ' + response.ret, 50 | desc: response.msg 51 | }, 'notice', 'warning', 5); 52 | // $router.back(); 53 | return new Promise(() => { 54 | }); 55 | } else { 56 | $notice({ 57 | title: '请求错误 ' + response.ret, 58 | desc: '路径:' + self.url + ',' + 59 | response.msg || '未知错误,请联系管理员或稍后重试' + 60 | '。' 61 | }, 'notice', 'warning', 5); 62 | return new Promise(() => { 63 | }); 64 | } 65 | }, 66 | error => { 67 | Message.destroy(); 68 | $notice(response.data.msg); 69 | return Promise.reject(error); 70 | } 71 | ); 72 | 73 | export default $http; 74 | -------------------------------------------------------------------------------- /src/assets/js/storage.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 存储localStorage 4 | * @param name 5 | * @param content 6 | * @param duration Storage有效时间,单位:小时 7 | * @param set_time 是否设置时间 8 | * @returns {boolean} 9 | */ 10 | export const setStore = (name, content, set_time = false, duration = 0) => { 11 | if (!name) return false 12 | if (typeof content !== 'string') { 13 | content = JSON.stringify(content) 14 | } 15 | if (set_time) { 16 | let date = new Date 17 | if (duration > 0) { 18 | content += '&' + (date.getTime() + duration * 3600 * 1e3) 19 | } else { 20 | content += '&0' 21 | } 22 | content += '&' + (date.getTime()) 23 | } 24 | window.localStorage.setItem(name, content) 25 | } 26 | 27 | /** 28 | * 获取localStorage 29 | * @param name 30 | * @param parse // 是否json格式化 31 | * @returns {boolean} 32 | */ 33 | export const getStore = (name, parse = false) => { 34 | if (!name) return false 35 | if (parse) { 36 | return JSON.parse(window.localStorage.getItem(name)) 37 | } 38 | return window.localStorage.getItem(name) 39 | } 40 | 41 | /** 42 | * 删除localStorage 43 | */ 44 | export const removeStore = name => { 45 | if (!name) return false 46 | window.localStorage.removeItem(name) 47 | } 48 | 49 | /** 50 | * 生成cookie 51 | * @param name cookie名称 52 | * @param value cookie值 53 | * @param duration cookie有效时间,单位:小时 54 | */ 55 | export const addCookie = (name, value, duration) => { 56 | let n = name + '=' + escape(value) + '; path=/' 57 | if (duration > 0) { 58 | let date = new Date 59 | date.setTime(date.getTime() + duration * 3600 * 1e3) 60 | n = n + ';expires=' + date.toGMTString() 61 | } 62 | document.cookie = n 63 | } 64 | 65 | /** 66 | * 获取cookie 67 | * @param name cookie名称 68 | * @returns {null} 69 | */ 70 | export const getCookie = (name) => { 71 | let t = document.cookie 72 | let a = t.split('; ') 73 | for (let n = 0; n < a.length; n++) { 74 | let r = a[n].split('=') 75 | if (r[0] === name) { 76 | return unescape(r[1]) 77 | } 78 | } 79 | return null 80 | } 81 | 82 | /** 83 | * 移除cookie 84 | * @param name cookie名称 85 | */ 86 | export const delCookie = (name) => { 87 | let t = new Date 88 | t.setTime(t.getTime() - 1) 89 | let a = getCookie(name) 90 | if (a !== null) document.cookie = name + '=' + a + '; path=/;expires=' + t.toGMTString() 91 | } -------------------------------------------------------------------------------- /src/assets/svg-loaders/bars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 12 | 13 | 17 | 21 | 22 | 23 | 27 | 31 | 32 | 33 | 37 | 41 | 42 | 43 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/router/project.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目 3 | */ 4 | export default [ 5 | { 6 | name: 'project_statistics', 7 | path: '/project/statistics', 8 | component: resolve => require(['@/views/project/statistics/statistics'], resolve), 9 | meta: {model: 'Project'}, 10 | }, 11 | { 12 | name: 'project_overview', 13 | path: '/project/overview', 14 | component: resolve => require(['@/views/project/overview/overview'], resolve), 15 | meta: {model: 'Project'}, 16 | }, 17 | { 18 | name: 'all_project_list', 19 | path: '/project/all_project/list', 20 | component: resolve => require(['@/views/project/allProject/list'], resolve), 21 | meta: {model: 'Project'}, 22 | }, 23 | { 24 | name: 'my_project_list', 25 | path: '/project/my_project/list', 26 | component: resolve => require(['@/views/project/myProject/list'], resolve), 27 | meta: {model: 'Project'}, 28 | }, 29 | { 30 | name: 'project_file_list', 31 | path: '/project/file/:project_id', 32 | component: resolve => require(['@/views/project/file/file'], resolve), 33 | meta: {model: 'Project'}, 34 | }, 35 | { 36 | name: 'project_build_list', 37 | path: '/project/build/:project_id', 38 | component: resolve => require(['@/views/project/build/build'], resolve), 39 | meta: {model: 'Project'}, 40 | }, 41 | { 42 | name: 'project_type_list', 43 | path: '/project/project_type/list', 44 | component: resolve => require(['@/views/project/projectType/list'], resolve), 45 | meta: {model: 'Project'}, 46 | }, 47 | { 48 | name: 'project_level_list', 49 | path: '/project/level/list', 50 | component: resolve => require(['@/views/project/level/list'], resolve), 51 | meta: {model: 'Project'}, 52 | }, 53 | { 54 | name: 'project_task', 55 | path: '/project/task/:project_id', 56 | component: resolve => require(['@/views/project/task/task'], resolve), 57 | meta: {model: 'Project'}, 58 | }, 59 | { 60 | name: 'project_task_overview', 61 | path: '/project/taskoverview/:team_id', 62 | component: resolve => require(['@/views/project/task/task-overview'], resolve), 63 | meta: {model: 'Project', parent: '/project/taskoverview/0'}, 64 | }, 65 | { 66 | name: 'project_task_type_template', 67 | path: '/project/task_type_template/:type_id', 68 | component: resolve => require(['@/views/project/task/task_type_template_list'], resolve), 69 | meta: {model: 'Project', parent: '/project/project_type/list'}, 70 | }, 71 | ]; -------------------------------------------------------------------------------- /src/components/socket.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 73 | -------------------------------------------------------------------------------- /src/components/check-label.vue: -------------------------------------------------------------------------------- 1 | 11 | 79 | -------------------------------------------------------------------------------- /src/components/menu-slide.vue: -------------------------------------------------------------------------------- 1 | 19 | 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "projectManage", 3 | "version": "1.0.0", 4 | "description": "A projectManage project for vue", 5 | "author": "vilson", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js", 11 | "lint": "eslint --ext .js,.vue src" 12 | }, 13 | "dependencies": { 14 | "awe-dnd": "^0.3.1", 15 | "axios": "latest", 16 | "iview": "^3.1.3", 17 | "jquery": "^3.2.1", 18 | "lodash": "^4.17.4", 19 | "moment": "latest", 20 | "vue": "latest", 21 | "vue-echarts": "latest", 22 | "vue-router": "^2.3.1", 23 | "vue-wangeditor": "^1.3.9", 24 | "vue-socket.io": "latest", 25 | "vuescroll": "^4.6.24", 26 | "vuex": "latest", 27 | "vue-slicksort": "^0.1.8", 28 | "wangeditor": "^2.1.23", 29 | "socket.io-client": "latest" 30 | }, 31 | "devDependencies": { 32 | "autoprefixer": "^6.7.2", 33 | "babel-core": "^6.22.1", 34 | "babel-eslint": "^7.1.1", 35 | "babel-loader": "^6.2.10", 36 | "babel-plugin-transform-runtime": "^6.22.0", 37 | "babel-polyfill": "^6.26.0", 38 | "babel-preset-env": "^1.3.2", 39 | "babel-preset-stage-2": "^6.22.0", 40 | "babel-register": "^6.22.0", 41 | "chalk": "^1.1.3", 42 | "connect-history-api-fallback": "^1.3.0", 43 | "copy-webpack-plugin": "^4.0.1", 44 | "css-loader": "^0.28.7", 45 | "eslint": "^3.19.0", 46 | "eslint-config-standard": "^6.2.1", 47 | "eslint-friendly-formatter": "^2.0.7", 48 | "eslint-loader": "^1.7.1", 49 | "eslint-plugin-html": "^2.0.0", 50 | "eslint-plugin-promise": "^3.4.0", 51 | "eslint-plugin-standard": "^2.0.1", 52 | "eventsource-polyfill": "^0.9.6", 53 | "express": "^4.14.1", 54 | "extract-text-webpack-plugin": "^2.0.0", 55 | "file-loader": "^0.11.1", 56 | "friendly-errors-webpack-plugin": "^1.1.3", 57 | "html-webpack-plugin": "^2.28.0", 58 | "http-proxy-middleware": "^0.17.3", 59 | "less": "^2.7.2", 60 | "less-loader": "^4.0.3", 61 | "opn": "^4.0.2", 62 | "optimize-css-assets-webpack-plugin": "^1.3.0", 63 | "ora": "^1.2.0", 64 | "proxy-polyfill": "latest", 65 | "rimraf": "^2.6.0", 66 | "semver": "^5.3.0", 67 | "shelljs": "^0.7.6", 68 | "url-loader": "^0.5.8", 69 | "vue-loader": "^13.0.5", 70 | "vue-style-loader": "^3.0.3", 71 | "vue-template-compiler": "^2.2.6", 72 | "webpack": "^3.6.0", 73 | "webpack-bundle-analyzer": "^2.2.1", 74 | "webpack-dev-middleware": "^1.10.0", 75 | "webpack-hot-middleware": "^2.18.0", 76 | "webpack-merge": "^4.1.0" 77 | }, 78 | "engines": { 79 | "node": ">= 4.0.0", 80 | "npm": ">= 3.0.0" 81 | }, 82 | "browserslist": [ 83 | "> 1%", 84 | "last 2 versions", 85 | "not ie <= 8" 86 | ] 87 | } 88 | -------------------------------------------------------------------------------- /src/assets/svg-loaders/spinning-circles.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 16 | 17 | 18 | 22 | 23 | 24 | 28 | 29 | 30 | 34 | 35 | 36 | 40 | 41 | 42 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/assets/js/notify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by vilson on 17/6/4. 3 | */ 4 | export const showMsgNotification = (title, msg, $opt = {}) => { 5 | let options = { 6 | body: msg, 7 | icon: $opt.icon || "http://static.vilson.xyz/preview.jpg", 8 | showTime: $opt.showTime || 15000, 9 | onclick: $opt.onclick, 10 | onshow: $opt.onshow, 11 | onerror: $opt.onerror, 12 | onclose: $opt.onclose, 13 | }; 14 | let Notification = window.Notification || window.mozNotification || window.webkitNotification; 15 | console.log(Notification.permission) 16 | if (Notification && Notification.permission === "granted") { 17 | let instance = new Notification(title, options); 18 | instance.onclick = function () { 19 | // Something to do 20 | if (typeof options.onclick === 'function') { 21 | options.onclick(instance) 22 | } 23 | // window.location.href = instance.icon 24 | }; 25 | instance.onerror = function () { 26 | // Something to do 27 | if (typeof options.onerror === 'function') { 28 | options.onerror(instance) 29 | } 30 | }; 31 | instance.onshow = function () { 32 | // Something to do 33 | if (typeof options.onshow === 'function') { 34 | options.onshow(instance) 35 | } 36 | setTimeout(function () { 37 | instance.close(); 38 | }, options.showTime) 39 | }; 40 | instance.onclose = function () { 41 | // Something to do 42 | if (typeof options.onclose === 'function') { 43 | options.onclose(instance) 44 | } 45 | }; 46 | } else if (Notification && Notification.permission !== "denied") { 47 | Notification.requestPermission(function (status) { 48 | if (Notification.permission !== status) { 49 | Notification.permission = status; 50 | } 51 | // If the user said okay 52 | if (status === "granted") { 53 | let instance = new Notification(title, options); 54 | instance.onclick = function () { 55 | // Something to do 56 | if (typeof options.onclick === 'function') { 57 | options.onclick(instance) 58 | } 59 | }; 60 | instance.onerror = function () { 61 | // Something to do 62 | if (typeof options.onerror === 'function') { 63 | options.onerror(instance) 64 | } 65 | }; 66 | instance.onshow = function () { 67 | // Something to do 68 | if (typeof options.onshow === 'function') { 69 | options.onshow(instance) 70 | } 71 | setTimeout(function () { 72 | instance.close(); 73 | }, options.showTime) 74 | }; 75 | instance.onclose = function () { 76 | // Something to do 77 | if (typeof options.onclose === 'function') { 78 | options.onclose(instance) 79 | } 80 | }; 81 | } else { 82 | return false 83 | } 84 | }); 85 | } else { 86 | return false; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/assets/css/common/layout.less: -------------------------------------------------------------------------------- 1 | .layout{ 2 | /*width: 1200px !important;*/ 3 | margin: auto; 4 | background: #efeff4; 5 | } 6 | .page-title{ 7 | font-size: 18px; 8 | color: #464c5b; 9 | line-height: 24px; 10 | padding-bottom: 15px; 11 | font-weight: 400; 12 | } 13 | .page-action + .page-title { 14 | padding-top: 55px; 15 | } 16 | .page-content{ 17 | top: 60px; 18 | bottom: 0; 19 | position: fixed; 20 | width:100%; 21 | overflow-x: auto; 22 | } 23 | .wrapper-content{ 24 | padding: 60px 0 0 200px; 25 | /*margin-left: 240px;*/ 26 | position: absolute; 27 | width:100%; 28 | } 29 | .layout-content{ 30 | min-height: 200px; 31 | padding: 25px 20px; 32 | overflow: hidden; 33 | background: #fff; 34 | } 35 | .has-header-content .wrapper-content{ 36 | box-shadow: 0 2px 8px 0 #e3e8ee; 37 | padding: 135px 20px 0 220px; 38 | background: #f7f8f8; 39 | margin-top: 0; 40 | height: 100%; 41 | } 42 | .has-header-content .layout-content { 43 | box-shadow: 0 2px 8px 0 #e3e8ee; 44 | padding: 45px 50px 55px 50px; 45 | } 46 | .layout-content .content-header { 47 | background: #fff; 48 | height: 56px; 49 | position: fixed; 50 | top: 60px; 51 | left: 0; 52 | z-index: 5; 53 | width: 100%; 54 | line-height: 56px; 55 | box-shadow: 0 1px 4px 0 #e3e8ee; 56 | padding-left: 220px; 57 | overflow: hidden; 58 | border-bottom: 1px solid #e3e8ee; 59 | } 60 | .layout-content .content-header h1:first-child { 61 | cursor: pointer; 62 | color: @primary-color; 63 | } 64 | .layout-content .content-header h1 { 65 | font-size: 12px; 66 | float: left; 67 | line-height: 56px; 68 | font-weight: 400; 69 | } 70 | .layout-copy{ 71 | text-align: center; 72 | padding: 10px 0 20px; 73 | color: #9ea7b4; 74 | } 75 | /*Slide*/ 76 | .menu-top{ 77 | position: fixed; 78 | top: 0; 79 | width: 100%; 80 | z-index: 999; 81 | } 82 | .menu-top .ivu-menu-horizontal .ivu-menu-item{ 83 | padding: 0 10px; 84 | margin-right: 20px; 85 | } 86 | .menu-top .ivu-menu-horizontal .ivu-menu-item .ivu-icon{ 87 | font-size: 18px; 88 | } 89 | .menu-slide{ 90 | position: fixed; 91 | height: 100%; 92 | padding-top: 10px; 93 | top: 60px; 94 | z-index: 40; 95 | background: #FFF; 96 | border-right: 1px solid #d7dde4; 97 | } 98 | .menu-slide .ivu-menu-item{ 99 | font-size: 12px; 100 | } 101 | .menu-slide .ivu-menu-vertical.ivu-menu-light:after{ 102 | background: initial !important; 103 | } 104 | .menu-slide .ivu-menu-submenu-title{ 105 | font-weight: 700; 106 | font-size: 12px; 107 | } 108 | .menu-slide .ivu-menu-submenu-title .ivu-icon{ 109 | font-size: 14px; 110 | } 111 | .menu-slide .ivu-menu-item.ivu-menu-item-active{ 112 | font-weight: 700; 113 | } 114 | .menu-slide .ivu-menu-item-active .ivu-menu-submenu-title { 115 | color: @primary-color; 116 | } 117 | .ivu-dropdown-item-menu{ 118 | padding-left: 10px !important; 119 | } 120 | .ivu-select-dropdown-menu{ 121 | width: inherit; 122 | max-height: 200px; 123 | overflow: hidden; 124 | margin: 5px 0; 125 | padding: 5px 0; 126 | background-color: #fff; 127 | box-sizing: border-box; 128 | border-radius: 4px; 129 | box-shadow: 0 1px 6px rgba(0,0,0,.2); 130 | position: absolute; 131 | z-index: 900; 132 | } -------------------------------------------------------------------------------- /src/components/wrapper-content.vue: -------------------------------------------------------------------------------- 1 | 19 | 87 | -------------------------------------------------------------------------------- /src/store/modules/menu.js: -------------------------------------------------------------------------------- 1 | import {getStore, setStore} from '@/assets/js/storage' 2 | 3 | const menu = { 4 | state: { 5 | menu_model: '', // 当前选中的菜单模块 6 | menu_top: false, 7 | menu_slide: false, 8 | active_key: '', 9 | active_key_top: '', 10 | open_items: [], 11 | menu_data: { 12 | menu_list: getStore('menu_list', true) ? getStore('menu_list', true) : [], 13 | menu_list_old: getStore('menu_list_old', true) ? getStore('menu_list_old', true) : [], //未格式化前的列表 14 | menu_model_list: getStore('menu_model_list', true) ? getStore('menu_model_list', true) : [], 15 | menu_model_list_all: getStore('menu_model_list_all', true) ? getStore('menu_model_list_all', true) : [], 16 | menu_model: getStore('menu_model', true) ? getStore('menu_model', true) : '', 17 | } 18 | }, 19 | mutations: { 20 | UPDATE_OPEN_ITEMS(state, data) { 21 | state.open_items = data 22 | }, 23 | UPDATE_ACTIVE_KEY(state, key) { 24 | state.active_key = key 25 | }, 26 | UPDATE_ACTIVE_KEY_TOP(state, key) { 27 | state.active_key_top = key 28 | }, 29 | UPDATE_MENU_DATA(state, {menu_list, menu_list_old, menu_model_list, menu_model_list_all, menu_model}) { 30 | state.menu_data.menu_list = menu_list; 31 | state.menu_data.menu_list_old = menu_list_old; 32 | state.menu_data.menu_model_list = menu_model_list; 33 | state.menu_data.menu_model_list_all = menu_model_list_all; 34 | state.menu_data.menu_model = menu_model; 35 | }, 36 | UPDATE_MENU_SLIDE(state, status) { 37 | state.menu_slide = status 38 | }, 39 | UPDATE_MENU_TOP(state, status) { 40 | state.menu_top = status 41 | }, 42 | UPDATE_MENU_MODEL(state, model) { 43 | state.menu_model = model 44 | }, 45 | }, 46 | actions: { 47 | UPDATE_OPEN_ITEMS({commit}, data) { 48 | commit('UPDATE_OPEN_ITEMS', data); 49 | }, 50 | UPDATE_ACTIVE_KEY({commit}, key) { 51 | commit('UPDATE_ACTIVE_KEY', key); 52 | }, 53 | UPDATE_ACTIVE_KEY_TOP({commit}, key) { 54 | commit('UPDATE_ACTIVE_KEY_TOP', key); 55 | }, 56 | UPDATE_MENU_DATA({commit}, {menu_list, menu_list_old, menu_model_list, menu_model_list_all, menu_model}) { 57 | setStore('menu_list', menu_list); 58 | setStore('menu_list_old', menu_list_old); 59 | setStore('menu_model_list', menu_model_list); 60 | setStore('menu_model_list_all', menu_model_list_all); 61 | setStore('menu_model', menu_model); 62 | commit('UPDATE_MENU_DATA', {menu_list, menu_list_old, menu_model_list, menu_model_list_all, menu_model}); 63 | }, 64 | UPDATE_MENU_SLIDE({commit}, status) { 65 | commit('UPDATE_MENU_SLIDE', status); 66 | }, 67 | UPDATE_MENU_TOP({commit}, status) { 68 | commit('UPDATE_MENU_TOP', status); 69 | }, 70 | UPDATE_MENU_MODEL({commit}, model) { 71 | setStore('menu_model', model); 72 | commit('UPDATE_MENU_MODEL', model); 73 | }, 74 | } 75 | }; 76 | export default menu -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-projectManage 2 | 基于Vue.js实现的项目管理系统 3 | 4 | 需要配合[后端接口](https://github.com/a54552239/projectManageApi)使用,链接:https://github.com/a54552239/projectManageApi 5 | 6 | 有不明白的地方的可以加群:275264059,或者联系我,QQ:545522390 7 | ### 演示地址 8 | > [https://project.vilson.xyz](https://project.vilson.xyz) 9 | 10 | ### 登陆 ### 11 | 账号:admin 密码:123456 12 | ### 界面截图 13 | ![1](https://static.vilson.xyz/1.png) 14 | ![1](https://static.vilson.xyz/2.png) 15 | ![1](https://static.vilson.xyz/3.png) 16 | ![1](https://static.vilson.xyz/4.png) 17 | ![1](https://static.vilson.xyz/5.png) 18 | ![1](https://static.vilson.xyz/6.png) 19 | ![1](https://static.vilson.xyz/7.png) 20 | ![1](https://static.vilson.xyz/8.png) 21 | 22 | ### 完整部署步骤 ### 23 | ``` 24 | 需要环境:php 5.6或者以上版本,mysql 5.6 25 | ``` 26 | - 可以直接下载[phpstudy](http://phpstudy.php.cn/phpstudy/PhpStudy20180211.zip)部署环境 27 | 1. 下载后端接口,解压到网站目录 28 | ![1](https://static.vilson.xyz/help/图片1.png) 29 | 2. 安装依赖 30 | 1. 进入项目目录 31 | 2. 方式一:Composer 32 | ![1](https://static.vilson.xyz/help/图片2.png) 33 | ![1](https://static.vilson.xyz/help/图片3.png) 34 | ![1](https://static.vilson.xyz/help/图片4.png) 35 | 3. 方式二:下载[vendor.zip](https://static.vilson.xyz/help/vendor.zip),直接解压到项目根目录,覆盖原有的vender文件夹 36 | 3. 将data目录下面的最新版本的sql文件(project_sql.sql)导入数据库 37 | 4. 修改config目录下的dbs.php文件,配置数据库信息 38 | 5. 访问项目,如:http://localhost/ApiForProjectManage/public 出现如下提示则表示部署成功 39 | ![1](https://static.vilson.xyz/help/图片5.png) 40 | 6. 下载前端项目 41 | ![1](https://static.vilson.xyz/help/图片6.png) 42 | 7. 安装node.js 43 | 1. 地址:http://nodejs.cn/download/ 根据情况选择版本 44 | 2. 安装npm淘宝镜像 45 | 1. 运行cmd 46 | 2. 输入:npm install -g cnpm --registry=https://registry.npm.taobao.org 47 | 8. 安装项目 48 | 1. 进入项目目录,运行cmd 49 | ![1](https://static.vilson.xyz/help/图片7.png) 50 | 2. 安装依赖:cnpm install 51 | ![1](https://static.vilson.xyz/help/图片8.png) 52 | 3. 启动项目:npm run dev 53 | ![1](https://static.vilson.xyz/help/图片9.png) 54 | 9. 打包项目(有必要的话) 55 | 1. 修改/src/assets/js/config.js,修改PRO_URL地址 56 | ![1](https://static.vilson.xyz/help/图片11.png) 57 | 2. 修改config/index.js,将assetsPublicPath 值改为‘/’。如果有CDN的话改为CDN地址 58 | ![1](https://static.vilson.xyz/help/图片12.png) 59 | 3. 运行cmd,输入 npm run build 60 | 4. 运行dist目录下的index.html,或者将dist目录下的文件部署到服务器上 61 | 10. 部署消息推送 62 | 1. 推送项目内成员的操作动态 63 | ![1](https://static.vilson.xyz/help/图片13.png) 64 | 2. 进入后端接口目录 65 | 3. 修改 66 | src\App\Plugins\GateWayWorker\start_register.php 67 | src\App\Plugins\GateWayWorker\start_gateway.php 68 | src\App\Plugins\GateWayWorker\start_businessworker.php 69 | src\App\Plugins\MessageService.php 70 | 4. 将以上4个文件中的ip地址修改为内网ip地址 71 | 5. Windows环境下,直接运行gate_start_for_win.bat文件 72 | ![1](https://static.vilson.xyz/help/图片14.png) 73 | 6. Linux环境下,运行 bash start.sh 启动服务,运行 bash stop.sh 终止服务 74 | 7. 进入前端目录 75 | 8. 修改 src/components/socket.vue,将initWebSocket 函数内的ws地址修改为相应的ip地址。如果使用wss,不能写ip需要写域名 76 | ![1](https://static.vilson.xyz/help/图片15.png) 77 | 9. 注意服务器要放行对应的端口(默认2345、2346) 78 | 10. 部署成功 79 | ![1](https://static.vilson.xyz/help/图片16.png) 80 | 11. 使用七牛云存储 81 | 1. 进入后端目录 ./config/constant.php 82 | 2. 将USE_QINIU的值修改为true 83 | 3. 将APP_URL的值修改为网站地址 84 | 4. 进入后端目录 ./config/app.php 85 | 5. 将Qiniu需改改为对应的值 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/views/system/setting/base/system-setting-base.vue: -------------------------------------------------------------------------------- 1 | 29 | 86 | -------------------------------------------------------------------------------- /src/assets/css/components/check-label.less: -------------------------------------------------------------------------------- 1 | @check-label-prefix-cls: ~"@{css-prefix}check-label"; 2 | 3 | .@{check-label-prefix-cls} { 4 | .check-label; 5 | .check-label-default; 6 | 7 | 8 | &-long{ 9 | width: 100%; 10 | } 11 | 12 | & > .ivu-icon + span, & > span + .ivu-icon{ 13 | margin-left: 4px; 14 | } 15 | 16 | &-primary { 17 | .check-label-primary; 18 | 19 | .@{check-label-prefix-cls}-group:not(.@{check-label-prefix-cls}-group-vertical) &:not(:first-child):not(:last-child) { 20 | border-right-color: @check-label-group-border; 21 | border-left-color: @check-label-group-border; 22 | } 23 | 24 | .@{check-label-prefix-cls}-group:not(.@{check-label-prefix-cls}-group-vertical) &:first-child { 25 | &:not(:last-child) { 26 | border-right-color: @check-label-group-border; 27 | &[disabled] { 28 | border-right-color: @check-label-default-border; 29 | } 30 | } 31 | } 32 | 33 | .@{check-label-prefix-cls}-group:not(.@{check-label-prefix-cls}-group-vertical) &:last-child:not(:first-child), 34 | .@{check-label-prefix-cls}-group:not(.@{check-label-prefix-cls}-group-vertical) & + .@{check-label-prefix-cls} { 35 | border-left-color: @check-label-group-border; 36 | &[disabled] { 37 | border-left-color: @check-label-default-border; 38 | } 39 | } 40 | 41 | .@{check-label-prefix-cls}-group-vertical &:not(:first-child):not(:last-child) { 42 | border-top-color: @check-label-group-border; 43 | border-bottom-color: @check-label-group-border; 44 | } 45 | 46 | .@{check-label-prefix-cls}-group-vertical &:first-child { 47 | &:not(:last-child) { 48 | border-bottom-color: @check-label-group-border; 49 | &[disabled] { 50 | border-top-color: @check-label-default-border; 51 | } 52 | } 53 | } 54 | 55 | .@{check-label-prefix-cls}-group-vertical &:last-child:not(:first-child), 56 | .@{check-label-prefix-cls}-group-vertical & + .@{check-label-prefix-cls} { 57 | border-top-color: @check-label-group-border; 58 | &[disabled] { 59 | border-bottom-color: @check-label-default-border; 60 | } 61 | } 62 | } 63 | 64 | &-ghost { 65 | .check-label-ghost; 66 | } 67 | 68 | &-dashed{ 69 | .check-label-dashed; 70 | } 71 | 72 | &-text{ 73 | .check-label-text; 74 | } 75 | 76 | &-success { 77 | .check-label-color(@success-color); 78 | } 79 | 80 | &-warning { 81 | .check-label-color(@warning-color); 82 | } 83 | 84 | &-error { 85 | .check-label-color(@error-color); 86 | } 87 | 88 | &-info { 89 | .check-label-color(@info-color); 90 | } 91 | 92 | &-circle, 93 | &-circle-outline { 94 | .check-label-circle(@check-label-prefix-cls); 95 | } 96 | 97 | &:before { 98 | position: absolute; 99 | top: -1px; 100 | left: -1px; 101 | bottom: -1px; 102 | right: -1px; 103 | background: #fff; 104 | opacity: 0.35; 105 | content: ''; 106 | border-radius: inherit; 107 | z-index: 1; 108 | transition: opacity @transition-time; 109 | pointer-events: none; 110 | display: none; 111 | } 112 | 113 | &&-loading { 114 | pointer-events: none; 115 | position: relative; 116 | 117 | &:before { 118 | display: block; 119 | } 120 | } 121 | 122 | &-group { 123 | .check-label-group(@check-label-prefix-cls); 124 | } 125 | 126 | &-group-vertical { 127 | .check-label-group-vertical(@check-label-prefix-cls); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/assets/css/components/table.less: -------------------------------------------------------------------------------- 1 | .ivu-table { 2 | color: #657180; 3 | clear: both; 4 | } 5 | .ivu-table th{ 6 | background-color: inherit !important; 7 | } 8 | .ivu-table tr:last-child td { 9 | border-bottom: none; 10 | } 11 | .ivu-table thead tr { 12 | border-top: 1px solid #eee; 13 | } 14 | .ivu-table-row { 15 | color: #464c5b; 16 | } 17 | .table-edit { 18 | text-align: right; 19 | padding-bottom: 20px; 20 | } 21 | 22 | .table-edit .left-actions { 23 | display: inline-block; 24 | float: left; 25 | } 26 | 27 | .table-edit .right-actions .ivu-input { 28 | width: 160px; 29 | border-radius: 40px; 30 | } 31 | .table-edit .right-actions .select .ivu-btn-ghost:hover { 32 | //border-left-color: transparent; 33 | //border-top-color: #e4e5e7; 34 | //border-bottom-color: #e4e5e7; 35 | //border-right-color: transparent; 36 | } 37 | .table-edit .left-actions .ivu-select-selection { 38 | border-radius: 40px; 39 | } 40 | .search-input{ 41 | display: inline-block; 42 | margin-left: 5px; 43 | } 44 | .table-page{ 45 | padding-top: 15px; 46 | text-align: right; 47 | } 48 | .table-page .total{ 49 | margin-left: 10px; 50 | } 51 | .action-item { 52 | margin-right: 10px; 53 | } 54 | 55 | /*使table宽度再wrapper为absolute时展开*/ 56 | .ivu-table table{ 57 | width: 100%; 58 | } 59 | 60 | .no-border-table.ivu-table-wrapper{ 61 | border: none !important; 62 | } 63 | .no-border-table .ivu-table:after{ 64 | width: 0 !important; 65 | } 66 | .no-border-table .ivu-table:before{ 67 | width: 0 !important; 68 | } 69 | .no-border-table .ivu-table-border th,.no-border-table .ivu-table-border td { 70 | border-right: none; 71 | } 72 | .no-border-table .ivu-checkbox-wrapper{ 73 | margin-bottom: 0; 74 | margin-right: 0; 75 | } 76 | 77 | .user-task-row-class{ 78 | cursor: pointer; 79 | } 80 | .user-task-row-class .ivu-table-cell{ 81 | height: 100%; 82 | display: flex; 83 | align-items: center; 84 | padding-left: 0; 85 | } 86 | .user-task-row-class .user-task-content{ 87 | width: 100%; 88 | height: 100%; 89 | display: flex; 90 | align-items: center; 91 | padding-left: 18px; 92 | margin-bottom: 5px; 93 | border-left: 3px solid #FFF; 94 | transition: all 0.4s; 95 | } 96 | .user-task-row-class .user-task-content.warning{ 97 | border-left: 3px solid #ff9900; 98 | } 99 | .user-task-row-class .user-task-content.error{ 100 | border-left: 3px solid #ed3f14; 101 | } 102 | .user-task-row-class.ivu-table-row-hover td{ 103 | background-color:#f5f5f5 !important; 104 | } 105 | .user-task-row-class td{ 106 | border:none; 107 | } 108 | 109 | .file-row-class{ 110 | //cursor: pointer; 111 | //border-left: 3px solid #FFF; 112 | } 113 | .file-row-class:hover{ 114 | //border-left-color: @warning-color; 115 | } 116 | .file-row-class.ivu-table-row-hover td{ 117 | background-color:#f5f5f5 !important; 118 | } 119 | .file-row-class td{ 120 | border:none; 121 | } 122 | 123 | .table-row-icon{ 124 | font-size: 18px; 125 | cursor:pointer; 126 | color: #A6A6A6; 127 | width: 25px; 128 | } 129 | .table-row-icon:hover{ 130 | color: #2d8cf0; 131 | } 132 | 133 | .table-state{ 134 | position: relative; 135 | } 136 | .table-state:before { 137 | content: ' '; 138 | position: absolute; 139 | top: 6px; 140 | left: -15px; 141 | width: 6px; 142 | height: 6px; 143 | border-radius: 50%; 144 | background-color: #2d8cf0; 145 | } 146 | .table-state.gray:before { 147 | background-color: #808080; 148 | } 149 | .table-state.default:before { 150 | background-color: #80848f; 151 | } 152 | .table-state.warning:before { 153 | background-color: #ff9900; 154 | } 155 | .table-state.success:before { 156 | background-color: #19be6b; 157 | } 158 | .table-state.danger:before { 159 | background-color: #ed3f14; 160 | } 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/api/user.js: -------------------------------------------------------------------------------- 1 | import $http from '../assets/js/http' 2 | 3 | export async function Login({account, password, remember = false}) { 4 | return $http.post('User_User.Login', { 5 | account, 6 | password, 7 | remember 8 | }); 9 | } 10 | 11 | export function getUser(user_id) { 12 | return $http.post('User_User.getUser', {user_id: user_id}); 13 | } 14 | 15 | export function changeUserState(id, state) { 16 | return $http.post('User_User.changeState', {id: id, state: state}); 17 | } 18 | 19 | export function delUser(ids) { 20 | return $http.post('User_User.delUser', {ids: ids}); 21 | } 22 | 23 | export function getUserList(page_size, page_num, keyword) { 24 | return $http.post('User_User.getUserList', {page_size: page_size, page_num: page_num, keyword: keyword}); 25 | } 26 | 27 | export function doUserInfo(action = 'add', data) { 28 | let url = 'User_User.addUser'; 29 | if (action === 'edit') { 30 | url = 'User_User.editUser' 31 | } 32 | return $http.post(url, data); 33 | } 34 | 35 | export function getUserMenu() { 36 | return $http.post('User_User.getUserMenu'); 37 | } 38 | 39 | export function getUserAuth() { 40 | return $http.post('User_User.getUserAuth'); 41 | } 42 | 43 | export function getInfoByToken() { 44 | return $http.post('User_User.getInfoByToken'); 45 | } 46 | 47 | export function editUser(data) { 48 | return $http.post('User_User.editUser', data); 49 | } 50 | 51 | export function doUser(data) { 52 | return $http.post('User.doUser', data); 53 | } 54 | 55 | export function changePassword(data) { 56 | return $http.post('User_User.changePassword', data); 57 | } 58 | 59 | export function getPositionList(page_size, page_num = 1, keyword = '') { 60 | return $http.post('User_Position.getList', {page_size: page_size, page_num: page_num, keyword: keyword}); 61 | } 62 | 63 | export function getPositionInfo(position_id) { 64 | return $http.post('User_Position.getInfo', {position_id: position_id}); 65 | } 66 | 67 | export function getPositionUserList(position_id, page_size, page_num, keyword) { 68 | return $http.post('User_Position.getUserList', { 69 | position_id: position_id, 70 | page_size: page_size, 71 | page_num: page_num, 72 | keyword: keyword 73 | }); 74 | } 75 | 76 | export function delPosition(ids) { 77 | return $http.post('User_Position.delPosition', {ids: ids}); 78 | } 79 | 80 | export function doPosition(action = 'add', data) { 81 | let url = 'User_Position.addPosition'; 82 | if (action === 'edit') { 83 | url = 'User_Position.editPosition' 84 | } 85 | return $http.post(url, data); 86 | } 87 | 88 | 89 | export function getUserLevelList(level_id, page_size, page_num, keyword) { 90 | return $http.post('User_Level.getUserList', { 91 | level_id: level_id, 92 | page_size: page_size, 93 | page_num: page_num, 94 | keyword: keyword 95 | }); 96 | } 97 | 98 | export function getLevelList(page_size, page_num = 1, keyword = '') { 99 | return $http.post('User_Level.getList', {page_size: page_size, page_num: page_num, keyword: keyword}); 100 | } 101 | 102 | export function delLevel(ids) { 103 | return $http.post('User_Level.delLevel', {ids: ids}); 104 | } 105 | 106 | export function getLevelInfo(level_id) { 107 | return $http.post('User_Level.getInfo', {level_id: level_id}); 108 | } 109 | 110 | export function doLevel(action = 'add', data) { 111 | let url = 'User_Level.addLevel'; 112 | if (action === 'edit') { 113 | url = 'User_Level.editLevel' 114 | } 115 | return $http.post(url, data); 116 | } 117 | 118 | export function getUserSetting(set_name) { 119 | return $http.post('User_UserSetting_Setting.getSetting', {name: set_name}); 120 | } 121 | 122 | export function doUserSetting(set_name, data) { 123 | return $http.post('User_UserSetting_Setting.doSetting', {name: set_name, value: data}); 124 | } -------------------------------------------------------------------------------- /src/assets/css/common/layout_2.less: -------------------------------------------------------------------------------- 1 | .layout{ 2 | /*width: 1200px !important;*/ 3 | margin: auto; 4 | background: #efeff4; 5 | } 6 | .page-title{ 7 | font-size: 18px; 8 | color: #464c5b; 9 | line-height: 35px; 10 | padding-bottom: 15px; 11 | font-weight: 400; 12 | border-bottom: 1px solid #e5e5e5; 13 | } 14 | .page-action + .page-title { 15 | //padding-top: 55px; 16 | } 17 | .page-content{ 18 | top: 60px; 19 | bottom: 0; 20 | position: fixed; 21 | width:100%; 22 | overflow-x: auto; 23 | } 24 | .wrapper-content{ 25 | padding: 80px 20px 20px 240px; 26 | position: absolute; 27 | width:100%; 28 | transition: all 368ms; 29 | } 30 | .layout-content{ 31 | min-height: 200px; 32 | padding: 15px 30px; 33 | overflow: hidden; 34 | background: #fff; 35 | box-shadow: 0 2px 3px 0 rgba(0,0,0,.047); 36 | } 37 | .has-header-content .wrapper-content{ 38 | padding: 80px 20px 0 240px; 39 | background: #f1f1f1; 40 | margin-top: 0; 41 | height: 100%; 42 | } 43 | .wrapper-content.hide { 44 | padding-left: 20px; 45 | transition-delay: 0ms; 46 | } 47 | .has-header-content .layout-content { 48 | box-shadow: 0 2px 3px 0 rgba(0,0,0,.047); 49 | padding: 5px 30px 15px 30px; 50 | } 51 | .wrapper-content .data-content { 52 | margin-top: 30px; 53 | } 54 | .layout-content .content-header { 55 | height: 56px; 56 | z-index: 5; 57 | width: 100%; 58 | line-height: 56px; 59 | overflow: hidden; 60 | border-bottom: 1px solid #e5e5e5; 61 | margin-bottom: 35px; 62 | } 63 | .layout-content .content-header h1:first-child { 64 | cursor: pointer; 65 | color: @primary-color; 66 | } 67 | .layout-content .content-header h1 { 68 | font-size: 14px; 69 | float: left; 70 | line-height: 56px; 71 | font-weight: 400; 72 | } 73 | .layout-copy{ 74 | text-align: center; 75 | padding: 10px 0 20px; 76 | color: #9ea7b4; 77 | } 78 | /*Slide*/ 79 | .menu-top{ 80 | position: fixed; 81 | top: 0; 82 | width: 100%; 83 | z-index: 999; 84 | } 85 | .menu-top .ivu-menu-horizontal .ivu-menu-item{ 86 | padding: 0 10px; 87 | margin-right: 20px; 88 | } 89 | .menu-top .ivu-menu-horizontal .ivu-menu-item .ivu-icon{ 90 | font-size: 18px; 91 | } 92 | .menu-slide{ 93 | position: fixed; 94 | height: 100%; 95 | padding-top: 10px; 96 | z-index: 40; 97 | //box-shadow: 0 2px 3px 0 rgba(0,0,0,.05); 98 | left: 20px; 99 | top: 70px; 100 | transition: all 368ms; 101 | } 102 | .menu-slide.hide { 103 | opacity: 0; 104 | left: -200px; 105 | transition-delay: 0ms; 106 | } 107 | .menu-slide .ivu-menu{ 108 | padding: 10px 0; 109 | } 110 | .menu-slide .ivu-menu-vertical .ivu-menu-item-group-title{ 111 | font-size: 14px; 112 | } 113 | .menu-slide i.ivu-icon { 114 | font-size: 16px; 115 | } 116 | .menu-slide .ivu-menu-item{ 117 | font-size: 14px; 118 | } 119 | .menu-slide .ivu-menu-vertical.ivu-menu-light:after{ 120 | background: initial !important; 121 | } 122 | .menu-slide .ivu-menu-submenu-title{ 123 | font-weight: 700; 124 | font-size: 12px; 125 | } 126 | .menu-slide .ivu-menu-submenu-title .ivu-icon{ 127 | font-size: 14px; 128 | } 129 | .menu-slide .ivu-menu-item.ivu-menu-item-active{ 130 | font-weight: 700; 131 | } 132 | .menu-slide .ivu-menu-item-active .ivu-menu-submenu-title { 133 | color: @primary-color; 134 | } 135 | .ivu-dropdown-item-menu{ 136 | padding-left: 10px !important; 137 | } 138 | .ivu-select-dropdown-menu{ 139 | width: inherit; 140 | max-height: 200px; 141 | overflow: hidden; 142 | margin: 5px 0; 143 | padding: 5px 0; 144 | background-color: #fff; 145 | box-sizing: border-box; 146 | border-radius: 4px; 147 | box-shadow: 0 1px 6px rgba(0,0,0,.2); 148 | position: absolute; 149 | z-index: 900; 150 | } 151 | .filter-content{ 152 | float: right; 153 | padding: 0 20px; 154 | } 155 | .filter-content .ivu-date-picker { 156 | padding: 10px 0 !important; 157 | } 158 | .filter-content a{ 159 | transition: color 0.2s ease; 160 | color: #464c5b !important; 161 | } 162 | .filter-content a:hover{ 163 | color: #5cadff !important; 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/views/system/auth/auth-rule-add.vue: -------------------------------------------------------------------------------- 1 | 46 | 99 | -------------------------------------------------------------------------------- /src/assets/css/common/layout_top.less: -------------------------------------------------------------------------------- 1 | .menu-top .ivu-menu-light { 2 | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.15); 3 | } 4 | 5 | .menu-header { 6 | margin: auto; 7 | } 8 | 9 | .menu-header .first-item { 10 | margin-left: 55px; 11 | } 12 | 13 | .menu-right { 14 | float: right; 15 | font-size: 14px; 16 | } 17 | 18 | .menu-right .ivu-btn { 19 | font-size: 14px !important; 20 | } 21 | 22 | .menu-right button.ivu-btn.ivu-btn-text { 23 | padding-left: 0; 24 | } 25 | 26 | .menu-right .ivu-dropdown-item { 27 | font-size: 14px !important; 28 | } 29 | 30 | .menu-right .ivu-dropdown .ivu-select-dropdown { 31 | border-radius: 2px !important; 32 | } 33 | 34 | .menu-right .ivu-dropdown-item { 35 | min-width: 200px; 36 | } 37 | 38 | .layout-logo { 39 | width: 125px; 40 | height: 30px; 41 | background: #5b6270; 42 | border-radius: 3px; 43 | float: left; 44 | position: relative; 45 | top: 15px; 46 | left: 20px; 47 | line-height: 2.2; 48 | text-align: center; 49 | color: #FFF; 50 | } 51 | 52 | .layout-navicon { 53 | width: 60px; 54 | border-radius: 3px; 55 | float: left; 56 | position: relative; 57 | left: 20px; 58 | line-height: 2.2; 59 | text-align: center; 60 | font-size: 27px; 61 | cursor: pointer; 62 | } 63 | 64 | .layout-navicon:hover { 65 | color: #2d8cf0; 66 | } 67 | 68 | .layout-nav { 69 | margin: 0 auto; 70 | } 71 | 72 | .handler-active { 73 | color: #57a3f3; 74 | } 75 | 76 | .search-input .ivu-input { 77 | padding-left: 15px; 78 | border-radius: 25px !important; 79 | } 80 | 81 | .auto-complete-item { 82 | padding: 4px 0; 83 | } 84 | 85 | .auto-complete-group { 86 | font-size: 12px; 87 | padding: 0 16px 5px 16px; 88 | margin-bottom: 5px; 89 | border-bottom: 1px solid #F6F6F6; 90 | } 91 | 92 | .auto-complete-group span { 93 | color: gray; 94 | font-weight: bold; 95 | } 96 | 97 | .auto-complete-group a { 98 | float: right; 99 | } 100 | 101 | .auto-complete-more { 102 | color: gray; 103 | display: block; 104 | margin: 0 auto; 105 | padding: 4px 4px 4px 16px; 106 | font-size: 12px; 107 | font-weight: bold; 108 | } 109 | 110 | span.auto-complete-title { 111 | width: 270px; 112 | white-space: nowrap; 113 | display: block; 114 | overflow: hidden; 115 | text-overflow: ellipsis; 116 | } 117 | 118 | .auto-complete-title em { 119 | font-style: normal; 120 | color: #2d8cf0; 121 | } 122 | .notice .ivu-poptip-body{ 123 | padding: 8px 0; 124 | } 125 | .notice .ivu-tabs-bar{ 126 | margin-bottom: 5px; 127 | } 128 | .notice .ivu-tabs-nav-wrap{ 129 | padding-left: 15px; 130 | } 131 | .notice .notice-list-item { 132 | -webkit-transition: all .3s; 133 | -o-transition: all .3s; 134 | transition: all .3s; 135 | overflow: hidden; 136 | cursor: pointer; 137 | -webkit-box-align: center; 138 | -ms-flex-align: center; 139 | align-items: center; 140 | display: -webkit-box; 141 | display: -ms-flexbox; 142 | display: flex; 143 | padding: 10px 24px; 144 | border-bottom: 1px solid #e8e8e8; 145 | } 146 | .notice .notice-list-item:hover { 147 | background: #ebf7ff; 148 | } 149 | .notice .notice-list-item-meta { 150 | -webkit-box-align: start; 151 | -ms-flex-align: start; 152 | align-items: flex-start; 153 | display: -webkit-box; 154 | display: -ms-flexbox; 155 | display: flex; 156 | font-size: 0; 157 | } 158 | .notice .notice-list-item-meta-avatar { 159 | -webkit-box-flex: 0; 160 | -ms-flex: 0; 161 | flex: 0; 162 | margin-right: 16px; 163 | } 164 | .notice .notice-list-item-meta-avatar img{ 165 | width: 32px; 166 | height: 32px; 167 | } 168 | .notice .notice-list-item-meta-content { 169 | -webkit-box-flex: 1; 170 | -ms-flex: 1 0; 171 | flex: 1 0; 172 | } 173 | .notice .notice-list-item-meta-title { 174 | margin-bottom: 4px; 175 | font-size: 12px; 176 | line-height: 22px; 177 | } 178 | .notice .title{ 179 | font-weight: normal; 180 | white-space: initial; 181 | } 182 | .notice .notice-list-item-meta-description { 183 | color: rgba(0, 0, 0, 0.45); 184 | font-size: 12px; 185 | line-height: 22px; 186 | } 187 | 188 | .notice .more { 189 | height: 35px; 190 | line-height: 43px; 191 | text-align: center; 192 | border-radius: 0 0 4px 4px; 193 | cursor: pointer; 194 | width: 50%; 195 | display: inline-block; 196 | } 197 | .notice .notFound{ 198 | text-align: center; 199 | padding: 73px 0 88px 0; 200 | color: rgba(0, 0, 0, 0.45); 201 | } -------------------------------------------------------------------------------- /src/assets/image/global/notice-icon/no-notice.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | bells (1) 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/router/system.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统 3 | */ 4 | export default [ 5 | { 6 | name: 'system_setting_base', 7 | path: '/system/setting_base', 8 | component: resolve => require(['@/views/system/setting/base/system-setting-base'], resolve), 9 | meta: {model: 'Project'} 10 | }, 11 | { 12 | name: 'system_auth_group_list', 13 | path: '/system/auth_group/list', 14 | component: resolve => require(['@/views/system/auth/auth-group-list'], resolve), 15 | meta: {model: 'Project'}, 16 | children: [ 17 | { 18 | name: 'auth_group_add', 19 | path: '/system/auth_group/add', 20 | component: resolve => require(['@/views/system/auth/auth_group_add'], resolve), 21 | meta: {model: 'Project', parent: '/system/auth_group/list'}, 22 | }, 23 | { 24 | name: 'auth_group_edit', 25 | path: '/system/auth_group/edit/:id', 26 | component: resolve => require(['@/views/system/auth/auth_group_edit'], resolve), 27 | meta: {model: 'Project', parent: '/system/auth_group/list'}, 28 | }, 29 | { 30 | name: 'system_group_user_list', 31 | path: '/system/auth_group/user_list/:id', 32 | component: resolve => require(['@/views/system/auth/group-user-list'], resolve), 33 | meta: {model: 'Project', parent: '/system/auth_group/list'} 34 | }, 35 | ] 36 | }, 37 | { 38 | name: 'system_menu_model_list', 39 | path: '/system/menu_model/list', 40 | component: resolve => require(['@/views/system/auth/menu-model-list'], resolve), 41 | meta: {model: 'Project'}, 42 | children: [ 43 | { 44 | name: 'menu_model_add', 45 | path: '/system/menu_model/add', 46 | component: resolve => require(['@/views/system/auth/menu-model-add'], resolve), 47 | meta: {model: 'Project', parent: '/system/menu_model/list'}, 48 | }, 49 | { 50 | name: 'menu_model_edit', 51 | path: '/system/menu_model/edit/:id', 52 | component: resolve => require(['@/views/system/auth/menu-model-edit'], resolve), 53 | meta: {model: 'Project', parent: '/system/menu_model/list'}, 54 | } 55 | ] 56 | }, 57 | { 58 | name: 'system_auth_menu_list', 59 | path: '/system/auth_menu/list', 60 | component: resolve => require(['@/views/system/auth/auth-menu-list'], resolve), 61 | meta: {model: 'Project'}, 62 | children: [ 63 | { 64 | name: 'auth_menu_add', 65 | path: '/system/auth_menu/add', 66 | component: resolve => require(['@/views/system/auth/auth-menu-add'], resolve), 67 | meta: {model: 'Project', parent: '/system/auth_menu/list'}, 68 | }, 69 | { 70 | name: 'auth_menu_edit', 71 | path: '/system/auth_menu/edit/:id', 72 | component: resolve => require(['@/views/system/auth/auth-menu-edit'], resolve), 73 | meta: {model: 'Project', parent: '/system/auth_menu/list'}, 74 | } 75 | ] 76 | }, 77 | { 78 | name: 'system_auth_rule_list', 79 | path: '/system/auth_rule/list', 80 | component: resolve => require(['@/views/system/auth/auth-rule-list'], resolve), 81 | meta: {model: 'Project'}, 82 | children: [ 83 | { 84 | name: 'auth_rule_add', 85 | path: '/system/auth_rule/add', 86 | component: resolve => require(['@/views/system/auth/auth-rule-add'], resolve), 87 | meta: {model: 'Project', parent: '/system/auth_rule/list'}, 88 | }, 89 | { 90 | name: 'auth_rule_edit', 91 | path: '/system/auth_rule/edit/:id', 92 | component: resolve => require(['@/views/system/auth/auth-rule-edit'], resolve), 93 | meta: {model: 'Project', parent: '/system/auth_rule/list'}, 94 | } 95 | ] 96 | }, 97 | { 98 | name: 'system_log_list', 99 | path: '/system/log/list', 100 | component: resolve => require(['@/views/system/log/log-list'], resolve), 101 | meta: {model: 'Project'}, 102 | }, 103 | ]; -------------------------------------------------------------------------------- /src/api/system.js: -------------------------------------------------------------------------------- 1 | import $http from '../assets/js/http' 2 | 3 | export async function getSetting(set_name) { 4 | return $http.post('System_Setting.getSetting', { 5 | set_name: set_name 6 | }); 7 | } 8 | 9 | export async function doSetting(set_name, data) { 10 | return $http.post('System_Setting.doSetting', {name: set_name, value: data}); 11 | } 12 | 13 | export async function getAuthGroupList(page_size, page_num, keyword = '') { 14 | return $http.post('System_AuthGroup.getList', { 15 | page_size: page_size, 16 | page_num: page_num, 17 | keyword: keyword 18 | }); 19 | } 20 | export async function getGroupAccess(user_id) { 21 | return $http.post('System_AuthGroup.getGroupAccess', {user_id: user_id}); 22 | } 23 | export async function assGroupAccess(data) { 24 | return $http.post('System_AuthGroup.assGroupAccess', data); 25 | } 26 | 27 | export async function delGroup(ids) { 28 | return $http.post('System_AuthGroup.delGroup', { 29 | ids: ids 30 | }); 31 | } 32 | 33 | export async function getMenu(id) { 34 | return $http.post('System_AuthMenu.getMenu', {id: id}); 35 | } 36 | 37 | export async function delMenu(ids) { 38 | return $http.post('System_AuthMenu.delMenu', {ids: ids}); 39 | } 40 | 41 | export async function getAllAuthMenuList(page_size, page_num, keyword,pid = -1) { 42 | return $http.post('System_AuthMenu.getAllList', { 43 | pid: pid, 44 | page_size: page_size, 45 | page_num: page_num, 46 | keyword: keyword 47 | }); 48 | } 49 | 50 | export async function addMenu(data) { 51 | return $http.post('System_AuthMenu.addMenu', data); 52 | } 53 | 54 | export async function editMenu(data) { 55 | return $http.post('System_AuthMenu.editMenu', data); 56 | } 57 | 58 | export async function getAllMenuModelList() { 59 | return $http.post('System_MenuModel.getAllList'); 60 | } 61 | 62 | export async function getRule(id) { 63 | return $http.post('System_AuthRule.getRule', {id: id}); 64 | } 65 | 66 | export async function addRule(data) { 67 | return $http.post('System_AuthRule.addRule', data); 68 | } 69 | 70 | export async function editRule(data) { 71 | return $http.post('System_AuthRule.editRule', data); 72 | } 73 | 74 | export async function delRule(ids) { 75 | return $http.post('System_AuthRule.delRule', {ids: ids}); 76 | } 77 | 78 | export async function getAllAuthRuleList(pid = 0, page_size, page_num, keyword) { 79 | return $http.post('System_AuthRule.getAllList', { 80 | pid: pid, 81 | page_size: page_size, 82 | page_num: page_num, 83 | keyword: keyword 84 | }); 85 | } 86 | 87 | export async function getAllAuthGroupList() { 88 | return $http.post('System_AuthGroup.getAllList'); 89 | } 90 | 91 | export async function addGroup(data) { 92 | return $http.post('System_AuthGroup.addGroup', data); 93 | } 94 | 95 | export async function editGroup(data) { 96 | return $http.post('System_AuthGroup.editGroup', data); 97 | } 98 | 99 | export async function getFullGroupOne(id) { 100 | return $http.post('System_AuthGroup.getFullGroupOne', {id: id}); 101 | } 102 | 103 | export async function removeGroupUser(group_id, ids) { 104 | return $http.post('System_AuthGroup.removeGroupUser', {group_id: group_id, id: id}); 105 | } 106 | 107 | export async function getGroupUserList(id, page_size, page_num, keyword) { 108 | return $http.post('System_AuthGroup.getGroupUserList', { 109 | id: id, 110 | page_size: page_size, 111 | page_num: page_num, 112 | keyword: keyword 113 | }); 114 | } 115 | 116 | export async function getMenuModel(id) { 117 | return $http.post('System_MenuModel.getModel', {id: id}); 118 | } 119 | 120 | export async function addMenuModel(data) { 121 | return $http.post('System_MenuModel.addModel', data); 122 | } 123 | 124 | export async function editMenuModel(data) { 125 | return $http.post('System_MenuModel.editModel', data); 126 | } 127 | 128 | export async function delMenuModel(ids) { 129 | return $http.post('System_MenuModel.delModel', {ids: ids}); 130 | } 131 | 132 | export async function getMenuModelList(page_size, page_num, keyword) { 133 | return $http.post('System_MenuModel.getList', { 134 | page_size: page_size, 135 | page_num: page_num, 136 | keyword: keyword 137 | }); 138 | } 139 | 140 | export async function getLogList(page_size, page_num, keyword, search_date) { 141 | return $http.post('System_Log.getList', { 142 | page_size: page_size, 143 | page_num: page_num, 144 | keyword: keyword, 145 | search_date: search_date 146 | }); 147 | } -------------------------------------------------------------------------------- /src/assets/css/common/layout_top_3.less: -------------------------------------------------------------------------------- 1 | .menu-top .ivu-menu-light { 2 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); 3 | //box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.15); 4 | } 5 | .menu-top .ivu-menu-horizontal.ivu-menu-light:after{ 6 | content: none; 7 | } 8 | .menu-top .ivu-menu-horizontal .ivu-menu-item, .ivu-menu-horizontal .ivu-menu-submenu { 9 | left: 0; 10 | transition: all 368ms; 11 | } 12 | .menu-top.hide .ivu-menu-horizontal .ivu-menu-item, .ivu-menu-horizontal .ivu-menu-submenu { 13 | left: -256px; 14 | } 15 | 16 | .menu-header { 17 | margin: auto; 18 | } 19 | 20 | .menu-header .first-item { 21 | margin-left: 0; 22 | } 23 | 24 | .menu-right { 25 | float: right; 26 | font-size: 14px; 27 | } 28 | 29 | .menu-right .ivu-btn { 30 | font-size: 14px !important; 31 | } 32 | 33 | .menu-right button.ivu-btn.ivu-btn-text { 34 | padding-left: 0; 35 | } 36 | 37 | .menu-right .ivu-dropdown-item { 38 | font-size: 14px !important; 39 | } 40 | 41 | .menu-right .ivu-dropdown .ivu-select-dropdown { 42 | border-radius: 2px !important; 43 | } 44 | 45 | .menu-right .ivu-dropdown-item { 46 | min-width: 200px; 47 | } 48 | 49 | .layout-logo { 50 | width: 256px; 51 | height: 60px; 52 | background: #002140; 53 | float: left; 54 | position: relative; 55 | line-height: 2.8; 56 | text-align: center; 57 | color: #FFF; 58 | font-size: 20px; 59 | left: 0; 60 | cursor: pointer; 61 | transition: all 368ms; 62 | box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); 63 | } 64 | .menu-top.hide .layout-logo { 65 | left: -256px; 66 | opacity: 0; 67 | transition-delay: 0ms; 68 | } 69 | 70 | .layout-navicon { 71 | width: 60px; 72 | border-radius: 3px; 73 | float: left; 74 | position: relative; 75 | left: 0; 76 | line-height: 2.2; 77 | text-align: center; 78 | font-size: 27px; 79 | cursor: pointer; 80 | transition: all 368ms; 81 | } 82 | .menu-top.hide .layout-navicon { 83 | left: -256px; 84 | transition-delay: 0ms; 85 | } 86 | 87 | .layout-navicon:hover { 88 | color: #2d8cf0; 89 | } 90 | 91 | .layout-nav { 92 | margin: 0 auto; 93 | } 94 | 95 | .handler-active { 96 | color: #57a3f3; 97 | } 98 | 99 | .search-input .ivu-input { 100 | padding-left: 15px; 101 | border-radius: 25px !important; 102 | } 103 | 104 | .auto-complete-item { 105 | padding: 4px 0; 106 | } 107 | 108 | .auto-complete-group { 109 | font-size: 12px; 110 | padding: 0 16px 5px 16px; 111 | margin-bottom: 5px; 112 | border-bottom: 1px solid #F6F6F6; 113 | } 114 | 115 | .auto-complete-group span { 116 | color: gray; 117 | font-weight: bold; 118 | } 119 | 120 | .auto-complete-group a { 121 | float: right; 122 | } 123 | 124 | .auto-complete-more { 125 | color: gray; 126 | display: block; 127 | margin: 0 auto; 128 | padding: 4px 4px 4px 16px; 129 | font-size: 12px; 130 | font-weight: bold; 131 | } 132 | 133 | span.auto-complete-title { 134 | width: 270px; 135 | white-space: nowrap; 136 | display: block; 137 | overflow: hidden; 138 | text-overflow: ellipsis; 139 | } 140 | 141 | .auto-complete-title em { 142 | font-style: normal; 143 | color: #2d8cf0; 144 | } 145 | .notice .ivu-poptip-body{ 146 | padding: 8px 0; 147 | } 148 | .notice .ivu-tabs-bar{ 149 | margin-bottom: 5px; 150 | } 151 | .notice .ivu-tabs-nav-wrap{ 152 | padding-left: 15px; 153 | } 154 | .vs-list-item { 155 | -webkit-transition: all .3s; 156 | -o-transition: all .3s; 157 | transition: all .3s; 158 | overflow: hidden; 159 | cursor: pointer; 160 | -webkit-box-align: center; 161 | -ms-flex-align: center; 162 | align-items: center; 163 | display: -webkit-box; 164 | display: -ms-flexbox; 165 | display: flex; 166 | padding: 10px 24px; 167 | border-bottom: 1px solid #e8e8e8; 168 | } 169 | .notice .vs-list-item:hover { 170 | background: #ebf7ff; 171 | } 172 | .vs-list-item-meta { 173 | -webkit-box-align: start; 174 | -ms-flex-align: start; 175 | align-items: flex-start; 176 | display: -webkit-box; 177 | display: -ms-flexbox; 178 | display: flex; 179 | font-size: 0; 180 | } 181 | .vs-list-item-meta-avatar { 182 | -webkit-box-flex: 0; 183 | -ms-flex: 0; 184 | flex: 0; 185 | margin-right: 16px; 186 | } 187 | .vs-list-item-meta-avatar img{ 188 | width: 32px; 189 | height: 32px; 190 | } 191 | .vs-list-item-meta-content { 192 | -webkit-box-flex: 1; 193 | -ms-flex: 1 0; 194 | flex: 1 0; 195 | } 196 | .vs-list-item-meta-title { 197 | margin-bottom: 4px; 198 | font-size: 12px; 199 | line-height: 22px; 200 | } 201 | .vs-list-item-meta-title .title{ 202 | font-weight: normal; 203 | white-space: initial; 204 | } 205 | .vs-list-item-meta-description { 206 | color: rgba(0, 0, 0, 0.45); 207 | font-size: 12px; 208 | line-height: 22px; 209 | } 210 | 211 | .notice .more { 212 | height: 35px; 213 | line-height: 43px; 214 | text-align: center; 215 | border-radius: 0 0 4px 4px; 216 | cursor: pointer; 217 | width: 50%; 218 | display: inline-block; 219 | } 220 | .notice .notFound{ 221 | text-align: center; 222 | padding: 73px 0 88px 0; 223 | color: rgba(0, 0, 0, 0.45); 224 | } -------------------------------------------------------------------------------- /src/views/system/auth/menu-model-add.vue: -------------------------------------------------------------------------------- 1 | 56 | 111 | -------------------------------------------------------------------------------- /src/assets/css/common/layout_3.less: -------------------------------------------------------------------------------- 1 | .layout{ 2 | /*width: 1200px !important;*/ 3 | margin: auto; 4 | background: #efeff4; 5 | } 6 | .page-title{ 7 | font-size: 18px; 8 | color: #464c5b; 9 | line-height: 35px; 10 | padding-bottom: 15px; 11 | font-weight: 400; 12 | border-bottom: 1px solid #e5e5e5; 13 | } 14 | .page-action + .page-title { 15 | //padding-top: 55px; 16 | } 17 | .page-content{ 18 | top: 60px; 19 | bottom: 0; 20 | position: fixed; 21 | width:100%; 22 | overflow-x: auto; 23 | } 24 | .wrapper-main{ 25 | height: 100vh; 26 | padding-bottom: 15px; 27 | } 28 | .wrapper-content{ 29 | padding: 60px 0 0 256px; 30 | position: absolute; 31 | width:100%; 32 | transition: all 368ms; 33 | } 34 | .layout-content{ 35 | min-height: 200px; 36 | padding: 15px 30px; 37 | margin: 20px 20px 0 20px; 38 | overflow: hidden; 39 | background: #fff; 40 | box-shadow: 0 2px 3px 0 rgba(0,0,0,.047); 41 | } 42 | .has-header-content .wrapper-content{ 43 | padding: 80px 20px 0 276px; 44 | background: #f1f1f1; 45 | margin-top: 0; 46 | height: 100%; 47 | } 48 | .wrapper-content.hide { 49 | padding-left: 0; 50 | transition-delay: 0ms; 51 | } 52 | .has-header-content .layout-content { 53 | box-shadow: 0 2px 3px 0 rgba(0,0,0,.047); 54 | padding: 5px 30px 15px 30px; 55 | } 56 | .wrapper-content .data-content { 57 | margin-top: 30px; 58 | } 59 | .layout-content .content-header { 60 | height: 56px; 61 | z-index: 5; 62 | width: 100%; 63 | line-height: 56px; 64 | overflow: hidden; 65 | border-bottom: 1px solid #e5e5e5; 66 | margin-bottom: 35px; 67 | } 68 | .layout-content .content-header h1:first-child { 69 | cursor: pointer; 70 | color: @primary-color; 71 | } 72 | .layout-content .content-header h1 { 73 | font-size: 14px; 74 | float: left; 75 | line-height: 56px; 76 | font-weight: 400; 77 | } 78 | .layout-copy{ 79 | text-align: center; 80 | padding: 10px 0 20px; 81 | color: #9ea7b4; 82 | } 83 | /*Slide*/ 84 | .menu-top{ 85 | position: fixed; 86 | top: 0; 87 | width: 100%; 88 | z-index: 999; 89 | } 90 | .menu-top .ivu-menu-horizontal .ivu-menu-item{ 91 | padding: 0 10px; 92 | margin-right: 20px; 93 | } 94 | .menu-top .ivu-menu-horizontal .ivu-menu-item .ivu-icon{ 95 | font-size: 18px; 96 | } 97 | .menu-slide .ivu-menu { 98 | background: #001529; 99 | } 100 | .menu-slide .ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened { 101 | background: #001529; 102 | } 103 | .menu-slide .ivu-menu-submenu.ivu-menu-opened .ivu-menu{ 104 | background-color: #000c17; 105 | } 106 | .menu-slide .ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened .ivu-menu-submenu-title { 107 | background: #001529; 108 | color: #FFF; 109 | } 110 | .menu-slide{ 111 | position: fixed; 112 | height: 100%; 113 | padding-top: 10px; 114 | z-index: 40; 115 | box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); 116 | //box-shadow: 0 2px 3px 0 rgba(0,0,0,.05); 117 | left: 0; 118 | top: 60px; 119 | transition: all 368ms; 120 | background-color: #001529; 121 | } 122 | .menu-slide.hide { 123 | opacity: 0; 124 | left: -256px; 125 | transition-delay: 0ms; 126 | } 127 | .menu-slide .ivu-menu{ 128 | padding: 3px 0; 129 | } 130 | .menu-slide .ivu-menu-vertical .ivu-menu-item-group-title{ 131 | font-size: 14px; 132 | } 133 | .menu-slide i.ivu-icon { 134 | font-size: 16px; 135 | } 136 | .menu-slide .ivu-menu-item{ 137 | font-size: 14px; 138 | } 139 | .menu-slide .ivu-menu-vertical.ivu-menu-light:after{ 140 | background: initial !important; 141 | } 142 | .ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item { 143 | margin-top: 5px; 144 | margin-bottom: 5px; 145 | } 146 | .menu-slide .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item-active, .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item-active:hover{ 147 | background: #1890ff !important 148 | } 149 | .menu-slide .ivu-menu-dark.ivu-menu-vertical .ivu-menu-item:hover, .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title:hover{ 150 | background: #001529; 151 | } 152 | .menu-slide .ivu-menu-submenu-title{ 153 | font-weight: normal; 154 | font-size: 14px; 155 | } 156 | .menu-slide .ivu-menu-submenu-title .ivu-icon{ 157 | font-size: 14px; 158 | } 159 | .menu-slide .ivu-menu-item.ivu-menu-item-active{ 160 | font-weight: normal; 161 | } 162 | .menu-slide .ivu-menu-item-active .ivu-menu-submenu-title { 163 | color: @primary-color; 164 | } 165 | .ivu-menu-vertical .ivu-menu-item, .ivu-menu-vertical .ivu-menu-submenu-title{ 166 | padding: 10px 15px 10px 25px; 167 | } 168 | .ivu-dropdown-item-menu{ 169 | padding-left: 10px !important; 170 | } 171 | .ivu-select-dropdown-menu{ 172 | width: inherit; 173 | max-height: 200px; 174 | overflow: hidden; 175 | margin: 5px 0; 176 | padding: 5px 0; 177 | background-color: #fff; 178 | box-sizing: border-box; 179 | border-radius: 4px; 180 | box-shadow: 0 1px 6px rgba(0,0,0,.2); 181 | position: absolute; 182 | z-index: 900; 183 | } 184 | .filter-content{ 185 | float: right; 186 | padding: 0 20px; 187 | } 188 | .filter-content .ivu-date-picker { 189 | padding: 10px 0 !important; 190 | } 191 | .filter-content a{ 192 | transition: color 0.2s ease; 193 | color: #464c5b !important; 194 | } 195 | .filter-content a:hover{ 196 | color: #5cadff !important; 197 | } 198 | 199 | -------------------------------------------------------------------------------- /src/views/user/profile/user-ass-group-access.vue: -------------------------------------------------------------------------------- 1 | 40 | 124 | -------------------------------------------------------------------------------- /src/views/system/auth/auth-rule-edit.vue: -------------------------------------------------------------------------------- 1 | 46 | 126 | -------------------------------------------------------------------------------- /src/views/system/auth/menu-model-edit.vue: -------------------------------------------------------------------------------- 1 | 52 | 124 | -------------------------------------------------------------------------------- /src/assets/js/date_time.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取本周一时间 3 | * @returns {number} 4 | */ 5 | export const getWeekDay = () => { 6 | //起止日期数组 7 | var startStop = new Array() 8 | //获取当前时间 9 | var currentDate = new Date() 10 | //返回date是一周中的某一天 11 | var week = currentDate.getDay() 12 | //返回date是一个月中的某一天 13 | var month = currentDate.getDate() 14 | 15 | //一天的毫秒数 16 | var millisecond = 1000 * 60 * 60 * 24 17 | //减去的天数 18 | var minusDay = week != 0 ? week - 1 : 6 19 | //alert(minusDay) 20 | //本周 周一 21 | var monday = new Date(currentDate.getTime() - (minusDay * millisecond)) 22 | //本周 周日 23 | var sunday = new Date(monday.getTime() + (6 * millisecond)) 24 | monday = monday.getFullYear() + "-" + (monday.getMonth() + 1) + "-" + monday.getDate() 25 | sunday = sunday.getFullYear() + "-" + (sunday.getMonth() + 1) + "-" + sunday.getDate() 26 | var week_day = { 27 | monday: monday, 28 | sunday: sunday, 29 | } 30 | return week_day 31 | } 32 | 33 | /** 34 | * 格式化时间 35 | * @param data 36 | * @param show 37 | * @returns {string} 38 | */ 39 | export const format_date = (data, show) => { 40 | if (show == undefined) { 41 | show = true 42 | } 43 | //格式化时间 44 | let now = new Date(data * 1000); 45 | let year = now.getFullYear(); 46 | let month = now.getMonth() + 1; 47 | let date = now.getDate(); 48 | let hour = now.getHours(); 49 | let minute = now.getMinutes(); 50 | // let second = now.getSeconds(); 51 | if (month < 10) { 52 | month = '0' + month; 53 | } 54 | if (date < 10) { 55 | date = '0' + date; 56 | } 57 | if (hour < 10) { 58 | hour = '0' + hour; 59 | } 60 | if (minute < 10) { 61 | minute = '0' + minute; 62 | } 63 | const finally_date = { 64 | year: year, 65 | month: month, 66 | day: date, 67 | hour: hour, 68 | minute: minute 69 | } 70 | if (show) { 71 | return year + "-" + month + "-" + date + " " + hour + ":" + minute; 72 | } else { 73 | return finally_date 74 | } 75 | } 76 | 77 | export const format_date_now = (day) => { 78 | //格式化时间 79 | if (day == undefined) { 80 | day = 0; 81 | } 82 | let now = new Date(); 83 | let year = now.getFullYear(); 84 | let month = now.getMonth(); 85 | let date = now.getDate() + day; 86 | if (month < 10) { 87 | month = '0' + month; 88 | } 89 | if (date < 10) { 90 | date = '0' + date; 91 | } 92 | return year + "-" + month + "-" + date; 93 | } 94 | 95 | /** 96 | * 格式化项目任务时间 97 | * @param begin_time 98 | * @param end_time 99 | * @returns {string} 100 | */ 101 | export const showTaskTime = (begin_time, end_time) => { 102 | let task_time = '' 103 | let begin_time_format = '' 104 | let end_time_format = '' 105 | begin_time = Date.parse(new Date(begin_time)) / 1000; 106 | end_time = Date.parse(new Date(end_time)) / 1000; 107 | if (begin_time > 0) { 108 | let begin = format_date(begin_time, false) 109 | begin_time_format = begin.month + '月' + begin.day + '日' + ' - ' 110 | } 111 | if (end_time > 0) { 112 | let end = format_date(end_time, false) 113 | end_time_format = end.month + '月' + end.day + '日' 114 | if (end.hour > 12 && end.hour <= 18) { 115 | end_time_format += ' 下午下班前' 116 | } 117 | if (end.hour > 18) { 118 | end_time_format += ' 加班' 119 | } 120 | if (end.hour <= 12 && end.hour >= 8) { 121 | end_time_format += ' 上午下班前' 122 | } 123 | if (end.hour < 8 && end.hour > 0) { 124 | end_time_format += ' 通宵' 125 | } 126 | } 127 | if (begin_time_format == '') { 128 | end_time_format += '完成' 129 | } 130 | task_time += begin_time_format + end_time_format 131 | return task_time 132 | } 133 | /** 134 | * 格式化项目任务时间 135 | * @returns {string} 136 | * @param time 137 | */ 138 | export const showHelloTime = (time) => { 139 | let time_format = '' 140 | if (time == undefined) { 141 | time = new Date(); 142 | } 143 | let hr = time.getHours(); 144 | if ((hr >= 0) && (hr <= 4)) 145 | time_format = "深夜了,注意身体," 146 | if ((hr >= 4) && (hr < 7)) 147 | time_format = "清晨好, " 148 | if ((hr >= 7) && (hr < 12)) 149 | time_format = "早安," 150 | if ((hr >= 12) && (hr <= 13)) 151 | time_format = "午饭时间到了," 152 | if ((hr >= 13) && (hr <= 17)) 153 | time_format = "下午好," 154 | if ((hr >= 17) && (hr <= 18)) 155 | time_format = "进入傍晚了," 156 | if ((hr >= 18) && (hr <= 20)) 157 | time_format = "吃过晚饭了吗," 158 | if ((hr >= 20) && (hr <= 24)) 159 | time_format = "在加班吗?辛苦了," 160 | return time_format 161 | } 162 | 163 | /** 164 | * 格式化日期对象 165 | * 如:1->A 166 | * @returns {string} 167 | * @param date 168 | * @param format 169 | */ 170 | export const date_format = (date, format) => { 171 | let o = { 172 | "M+": date.getMonth() + 1, //month 173 | "d+": date.getDate(), //day 174 | "h+": date.getHours(), //hour 175 | "m+": date.getMinutes(), //minute 176 | "s+": date.getSeconds(), //second 177 | "q+": Math.floor((date.getMonth() + 3) / 3), //quarter 178 | "S": date.getMilliseconds() //millisecond 179 | } 180 | if (/(y+)/.test(format)) { 181 | format = format.replace(RegExp.$1, 182 | (date.getFullYear() + "").substr(4 - RegExp.$1.length)); 183 | } 184 | for (let k in o) if (new RegExp("(" + k + ")").test(format)) 185 | format = format.replace(RegExp.$1, 186 | RegExp.$1.length == 1 ? o[k] : 187 | ("00" + o[k]).substr(("" + o[k]).length)); 188 | return format; 189 | } 190 | 191 | /** 192 | * 数字转英文字母 193 | * 如:1->A 194 | * @param num 195 | * @returns {string} 196 | */ 197 | export const convert = (num) => { 198 | let result = ""; 199 | while (num) { 200 | result = String.fromCharCode(--num % 26 + 65) + result; 201 | num = Math.floor(num / 26) 202 | } 203 | return result 204 | } -------------------------------------------------------------------------------- /src/views/team/user/level/detail.vue: -------------------------------------------------------------------------------- 1 | 27 | 30 | 148 | -------------------------------------------------------------------------------- /src/views/team/user/position/detail.vue: -------------------------------------------------------------------------------- 1 | 27 | 30 | 148 | -------------------------------------------------------------------------------- /src/components/editor_2.0.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/views/system/auth/auth-menu-add.vue: -------------------------------------------------------------------------------- 1 | 64 | 136 | -------------------------------------------------------------------------------- /src/views/system/auth/auth-menu-edit.vue: -------------------------------------------------------------------------------- 1 | 62 | 151 | -------------------------------------------------------------------------------- /src/views/project/task/task-overview.vue: -------------------------------------------------------------------------------- 1 | 24 | 29 | 164 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 19 | 115 | 116 | 175 | 184 | --------------------------------------------------------------------------------