前端拆分为单独项目来维护开发

This commit is contained in:
暮光:城中城
2019-05-17 18:23:03 +08:00
parent 13e390535d
commit 25b4089a8f
27 changed files with 12600 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
{
"presets": ["vue-app"]
}

5
zyplayer-doc-ui/wiki-ui/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.DS_Store
node_modules/
dist/
npm-debug.log
.idea

View File

@@ -0,0 +1,9 @@
.PHONY: dist build
install:
@npm install
dev: install
@npm run dev
build:
@npm run build

View File

@@ -0,0 +1,31 @@
# zyplayer-doc-wiki项目的UI
zyplayer-doc-wiki项目的UI使用此项目构建开发起来爽得很
但是,才发第一版,又他喵得重构一次~
之前从jQuery换到element以为是结局了爽到吐结果又被这个迷住了前端真是让人高潮个不停啊
但是,好东西怎么放过呢!
## 环境要求
`Node >= 6`
## 开始
``` bash
# 执行下面的命令初始化
yarn
```
## 开发环境
``` bash
# 执行下面的命令后即可到 localhost:8010 看到页面
npm run dev
```
## 打包
``` bash
# 开发完成后执行打包命令然后复制dist目录里的文件到zyplayer-doc-wiki项目的webjars目录下即可
# 打包前记得修改zyplayer-doc-ui/wiki-ui/src/common/config/apimix.js里的HOST接口地址
npm run build
```

7678
zyplayer-doc-ui/wiki-ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
{
"name": "element-starter",
"description": "A Vue.js project",
"author": "yi.shyang@ele.me",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --hot --env.dev",
"build": "rimraf dist && webpack -p --progress --hide-modules"
},
"dependencies": {
"axios": "^0.18.0",
"element-ui": "^2.3.4",
"vue": "^2.5.16",
"vue-axios": "^2.1.4",
"vue-router": "^3.0.6"
},
"engines": {
"node": ">=6"
},
"devDependencies": {
"autoprefixer": "^6.6.0",
"babel-core": "^6.24.1",
"babel-loader": "^6.4.0",
"babel-preset-vue-app": "^1.2.0",
"css-loader": "^0.27.0",
"file-loader": "^0.10.1",
"html-webpack-plugin": "^2.24.1",
"postcss-loader": "^1.3.3",
"rimraf": "^2.6.3",
"style-loader": "^0.13.2",
"url-loader": "^0.5.8",
"vue-loader": "^13.3.0",
"vue-template-compiler": "^2.5.16",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.2",
"axios": "^0.18.0",
"vue-axios": "^2.1.4"
}
}

View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer')()
]
}

View File

@@ -0,0 +1,243 @@
<template>
<div id="app">
<template v-if="global.fullscreen">
<router-view></router-view>
</template>
<el-container v-else>
<el-aside width="200px">
<div style="padding: 10px;" v-show="leftCollapse">
<div style="margin-bottom: 10px;">
<el-select v-model="choiceSpace" @change="spaceChangeEvents" filterable placeholder="选择空间" style="width: 100%;">
<el-option-group label="">
<el-option key="0" label="创建空间" value="0"></el-option>
<el-option key="-1" label="空间管理" value="-1"></el-option>
</el-option-group>
<el-option-group label="">
<el-option v-for="item in spaceOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-option-group>
</el-select>
</div>
<div align="center">
<el-button v-on:click="createWiki" icon="el-icon-plus" style="width: 100%;">创建文档</el-button>
</div>
<el-input v-model="searchKeywords" @keyup.enter.native="searchByKeywords" placeholder="搜索文档" style="margin: 10px 0;">
<el-button slot="append" icon="el-icon-search" v-on:click="searchByKeywords"></el-button>
</el-input>
<el-tree :props="defaultProps" :data="wikiPageList" @node-click="handleNodeClick"
@node-expand="handleNodeExpand" draggable @node-drop="handlePageDrop"
ref="wikiPageTree" :filter-node-method="filterPageNode" highlight-current
:expand-on-click-node="false" :default-expanded-keys="wikiPageExpandedKeys"
node-key="id"
style="background-color: #fafafa;">
</el-tree>
</div>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</div>
</template>
<script>
var app;
export default {
data() {
return {
leftCollapse: true,
aboutDialogVisible: false,
rightContentLoading: false,
rightContentType: 0,// 右侧显示类型0=欢迎页 1=文章内容 2=编辑或新增文章
pathIndex: [],
defaultProps: {
children: 'children',
label: 'name'
},
// 空间搜索相关
spaceOptions: [],
spaceList:[],
choiceSpace: "",
nowSpaceId: '',
nowSpaceShow: {},
newSpaceDialogVisible: false,
manageSpaceDialogVisible: false,
newSpaceForm: {id: '', name: '', spaceExplain: '', treeLazyLoad: 0, openDoc: 0, uuid: '', type: 1},
newSpaceFormRules: {
name: [
{required: true, message: '请输入空间名', trigger: 'blur'},
{min: 2, max: 25, message: '长度在 2 到 25 个字符', trigger: 'blur'}
],
},
// 依据目录树存储的map全局对象
treePathDataMap: new Map(),
// 搜索的输入内容
searchKeywords: "",
lastClickNode: {},
// 编辑相关
newPageId: "",
newPageTitle: "",
// 页面展示相关
wikiPageList:[],
wikiPage: {},
wikiPageExpandedKeys: [],
pageContent: {},
pageFileList: [],
uploadFileList: [],
uploadFormData: {pageId: 0},
zanUserDialogVisible: false,
zanUserList: [],
// 评论相关
commentTextInput: "",
commentList: [],
recommentInfo: {},
// 页面跳转相关
initOver: false,
doNotPushState: false,
urlParamPageId: 0,
urlParam: {},
// 升级信息
upgradeInfo: {},
}
},
mounted: function () {
app = this;
this.loadSpaceList();
},
methods: {
createWiki() {
},
searchByKeywords() {
this.$refs.wikiPageTree.filter(app.searchKeywords);
},
handleNodeClick(data) {
app.rightContentType = 1;
if (app.lastClickNode.id == data.id) {
return;
}
console.log("点击节点:", data);
app.lastClickNode = data;
app.urlParamPageId = app.lastClickNode.id;
},
handleNodeExpand(node) {
if (node.children.length > 0 && node.children[0].needLoad) {
console.log("加载节点:", node);
app.doGetPageList(node.id, node);
}
},
handlePageDrop(draggingNode, dropNode, dropType, ev) {
//console.log('tree drop: ', draggingNode.data, dropNode.data, dropType);
// 'prev'、'inner'、'next'
var param = {id: draggingNode.data.id, parentId: dropNode.data.parentId};
if (dropType == 'inner') {
param.parentId = dropNode.data.id;
}
this.common.post(this.apilist1.pageUpdate, param, function (json) {
app.doGetPageList(null);
});
},
filterPageNode(value, data) {
if (!value) return true;
return data.name.indexOf(value) !== -1;
},
spaceChangeEvents(data) {
if (data == 0) {
app.newSpaceForm = {id: '', name: '', spaceExplain: '', treeLazyLoad: 0, openDoc: 0, uuid: '', type: 1};
app.choiceSpace = app.nowSpaceId;
app.newSpaceDialogVisible = true;
} else if (data == -1) {
app.choiceSpace = app.nowSpaceId;
app.manageSpaceDialogVisible = true;
} else {
app.nowSpaceId = data;
app.rightContentType = 0;
for (var i = 0; i < app.spaceList.length; i++) {
if (app.spaceList[i].id == data) {
app.nowSpaceShow = app.spaceList[i];
break;
}
}
app.doGetPageList(null);
}
},
loadSpaceList() {
this.common.post(this.apilist1.spaceList, {}, function (json) {
app.spaceList = json.data || [];
var spaceOptions = [];
for (var i = 0; i < app.spaceList.length; i++) {
spaceOptions.push({
label: app.spaceList[i].name, value: app.spaceList[i].id
});
}
app.spaceOptions = spaceOptions;
if (app.spaceList.length > 0) {
app.nowSpaceId = app.spaceList[0].id;
app.nowSpaceShow = app.spaceList[0];
app.choiceSpace = app.nowSpaceId;
app.doGetPageList(null);
}
});
},
doGetPageList(parentId, node) {
var nodePath = "";
if (!!node) {
nodePath = node.nodePath || "/";
if (!nodePath.endsWith("/")) {
nodePath += "/";
}
} else {
nodePath = "/";
}
var param = {spaceId: this.nowSpaceId, parentId: parentId || 0};
if (app.nowSpaceShow.treeLazyLoad == 0) {
param.parentId = null;
}
this.common.post(this.apilist1.pageList, param, function (json) {
var result = json.data || [];
var pathIndex = [];
if (app.nowSpaceShow.treeLazyLoad == 0) {
pathIndex = result;
} else {
for (var i = 0; i < result.length; i++) {
var item = result[i];
item.parentId = item.parentId || 0;
item.children = [{label: '', needLoad: true}];// 初始化一个对象,点击展开时重新查询加载
pathIndex.push(item);
}
}
app.createNodePath(pathIndex, nodePath);
if (parentId > 0) {
node.children = pathIndex;
} else {
app.wikiPageList = pathIndex;
//app.lastClickNode = {};
}
});
},
createNodePath(node, nodePath) {
if (!nodePath.endsWith("/")) {
nodePath += "/";
}
for (var i = 0; i < node.length; i++) {
var item = node[i];
item.nodePath = nodePath + item.name;
if (!!item.children && item.children.length > 0) {
this.createNodePath(item.children, item.nodePath);
}
}
},
}
}
</script>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
}
#app, .el-container, .el-menu {
height: 100%;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,17 @@
var URL = {
userLogin: '/user/login',
getUserInfo: '/user/getUserInfo',
pageUpdate: '/zyplayer-doc-wiki/page/update',
pageList: '/zyplayer-doc-wiki/page/list',
spaceList: '/zyplayer-doc-wiki/space/list',
};
var URL1 = {};
export default {
URL, URL1
};

View File

@@ -0,0 +1,70 @@
import apilist from './apilist'
var href = window.location.href;
var EVT = '';
var _evt = function () {
if (href.indexOf('https://') > -1) {
// 测试环境
if (href.indexOf('https://test') > -1 && href.indexOf('https://test.') == -1) {
EVT = 'https://test';
// dev环境
} else if (href.indexOf('https://dev') > -1 && href.indexOf('https://dev.') == -1) {
EVT = 'https://dev';
} else {
EVT = 'https://'
}
return EVT;
} else {
// 测试环境
if (href.indexOf('http://test') > -1 && href.indexOf('http://test.') == -1) {
EVT = 'http://test';
// dev环境
} else if (href.indexOf('http://dev') > -1 && href.indexOf('http://dev.') == -1) {
EVT = 'http://dev';
} else {
EVT = 'http://'
}
return EVT;
}
};
var _fn = {
href: href,
HOST: EVT + 'local.zyplayer.com:8083/zyplayer-doc-manage', //这里设置接口域名
HOST1: EVT + 'local.zyplayer.com:8083', //设置多个接口域名
mixUrl: function (host, url) {
var p;
if (!host || !url || _fn.isEmptyObject(url)) {
return;
}
url.EVT = _evt();
for (p in url) {
if (url[p].indexOf('http') == -1) {
url[p] = url.EVT + host + url[p];
}
}
return url;
},
//判断是否空对象
isEmptyObject: function (obj) { //判断空对象
if (typeof obj === "object" && !(obj instanceof Array)) {
var hasProp = false;
for (var prop in obj) {
hasProp = true;
break;
}
if (hasProp) {
return false;
}
return true;
}
}
};
var apilist1 = _fn.mixUrl(_fn.HOST, apilist.URL);
var apilist2 = _fn.mixUrl(_fn.HOST1, apilist.URL1);
export default {
apilist1, apilist2
};

View File

@@ -0,0 +1,12 @@
const user = {
isLogin: true,
};
const app = {};
const fullscreen = false;
export default {
app,
user,
fullscreen,
}

View File

@@ -0,0 +1,51 @@
import Qs from 'qs'
import global from '../../config/global'
export default {
data: {
accessToken: '',
},
setAccessToken: function (token) {
this.data.accessToken = token;
},
getAccessToken: function () {
if (!this.data.accessToken) {
var arr, reg = new RegExp("(^| )accessToken=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)) {
this.data.accessToken = unescape(arr[2]);
}
}
return this.data.accessToken;
},
validateResult: function (res, callback) {
if (res.data.errCode == 400) {
global.app.$message('请先登录');
global.app.$router.push("/user/login");
} else if (res.data.errCode == 402) {
global.app.$router.push("/common/noAuth");
} else if (res.data.errCode !== 200) {
global.app.$message(res.data.errMsg || "未知错误");
} else {
if (typeof callback == 'function') {
callback(res.data);
}
}
},
post: function (url, param, callback) {
param = param || {};
param.accessToken = this.getAccessToken();
global.app.axios({
method: "post",
url: url,
headers: {'Content-type': 'application/x-www-form-urlencoded'},
data: Qs.stringify(param),
}).then((res) => {
console.log("ok", res);
this.validateResult(res, callback);
}).catch((res) => {
console.log("error", res);
this.validateResult(res);
});
},
}

View File

@@ -0,0 +1,40 @@
import global from '../../config/global'
/**
* 提示工具类
* @author
* @since 2017年5月7日
*/
export default {
notOpen: function () {
global.app.$message({
message: '该功能暂未开放,敬请期待!',
type: 'warning',
showClose: true
});
},
success: function (msg, time) {
global.app.$message({
message: msg,
duration: time || 3000,
type: 'success',
showClose: true
});
},
warn: function (msg, time) {
global.app.$message({
message: msg,
duration: time || 3000,
type: 'warning',
showClose: true
});
},
error: function (msg, time) {
global.app.$message({
message: msg,
duration: time || 3000,
type: 'error',
showClose: true
});
},
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>wiki文档管理系统</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,59 @@
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'
import global from './common/config/global'
import apimix from './common/config/apimix'
import common from './common/lib/common/common'
import toast from './common/lib/common/toast'
import VueRouter from 'vue-router'
import routes from './routes'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(ElementUI);
Vue.use(VueRouter);
Vue.use(VueAxios, axios);
// 全局参数
Vue.prototype.global = global;
// 接口列表
Vue.prototype.apilist1 = apimix.apilist1;
Vue.prototype.apilist2 = apimix.apilist1;
// 公用方法
Vue.prototype.common = common;
Vue.prototype.toast = toast;
const router = new VueRouter({routes});
// 路由跳转时判断处理
router.beforeEach((to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title
}
global.fullscreen = !!to.meta.fullscreen;
/* 判断该路由是否需要登录权限 */
if (to.matched.some(record => record.meta.requireAuth)) {
if (global.user.isLogin) {
next();
} else {
next({path: '/login'});
}
} else {
next();
}
});
new Vue({
el: '#app',
router,
render(h) {
var app = h(App);
global.app = app.context;
return app;
}
});

View File

@@ -0,0 +1,36 @@
import Home from './views/home/Home.vue'
import UserLogin from './views/user/Login.vue'
import UserRouterView from './views/user/RouterView.vue'
import CommonNoAuth from './views/common/NoAuth.vue'
let routes = [
{
path: '/home',
component: Home,
name: '主页',
meta: {
requireAuth: true,
}
}, {
path: '/user',
name: '用户管理',
component: UserRouterView,
children: [
{path: 'login', name: '系统登录',component: UserLogin, meta: {fullscreen: true}},
]
}, {
path: '/common',
name: '',
component: UserRouterView,
children: [
{path: 'noAuth', name: '没有权限',component: CommonNoAuth},
]
}, {
path: '/',
redirect: '/home'
}
];
export default routes;

View File

@@ -0,0 +1,2 @@
import Vue from 'vue'
import ElementUI from 'element-ui'

View File

@@ -0,0 +1,18 @@
<template>
<div>没有权限访问该模块</div>
</template>
<script>
export default {
data() {
return {};
},
mounted: function () {
},
methods: {}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,23 @@
<template>
<div>欢迎使用wiki文档管理工具</div>
</template>
<script>
export default {
data() {
return {};
},
mounted: function () {
// this.getUserInfo();
},
methods: {
getUserInfo: function () {
this.common.post(this.apilist1.getUserInfo, {}, function (json) {});
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,86 @@
<template>
<el-form :model="loginParam" :rules="loginRules" ref="loginParam" label-position="left" label-width="0px"
class="demo-ruleForm login-container">
<h3 class="title">系统登录</h3>
<el-form-item prop="userNo">
<el-input type="text" v-model="loginParam.userNo" auto-complete="off" placeholder="账号"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="loginParam.password" auto-complete="off" placeholder="密码"></el-input>
</el-form-item>
<el-form-item style="width:100%;">
<el-button type="primary" style="width:100%;" @click.native.prevent="loginSubmit" :loading="logining">登录
</el-button>
<!--<el-button @click.native.prevent="handleReset2">重置</el-button>-->
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
logining: false,
loginParam: {
userNo: '',
password: ''
},
loginRules: {
userNo: [
{required: true, message: '请输入账号', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
]
},
checked: true
};
},
methods: {
loginSubmit(ev) {
var that = this;
this.$refs.loginParam.validate((valid) => {
if (!valid) return;
that.common.post(that.apilist1.userLogin, that.loginParam, function (json) {
// 设置cookie
var token = escape(json.data);
var exp = new Date();
exp.setTime(exp.getTime() + 30 * 24 * 60 * 60 * 1000);
document.cookie = "accessToken=" + token + ";expires=" + exp.toGMTString();
that.common.setAccessToken(token);
// 跳转
that.global.user.isLogin = true;
that.$router.push("/user/wxLogin");
});
});
}
}
}
</script>
<style>
.login-container {
-webkit-border-radius: 5px;
border-radius: 5px;
-moz-border-radius: 5px;
background-clip: padding-box;
margin: 80px auto;
width: 350px;
padding: 35px 35px 15px 35px;
background: #fff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
}
.title {
margin: 0px auto 40px auto;
text-align: center;
color: #505458;
}
.remember {
margin: 0px 0px 35px 0px;
}
</style>

View File

@@ -0,0 +1,4 @@
<template>
<router-view></router-view>
</template>

View File

@@ -0,0 +1,74 @@
const resolve = require('path').resolve;
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const url = require('url');
const publicPath = '';
module.exports = (options = {}) => ({
entry: {
vendor: './src/vendor',
index: './src/main.js'
},
output: {
path: resolve(__dirname, 'dist'),
filename: options.dev ? '[name].js' : '[name].js?[chunkhash]',
chunkFilename: '[id].js?[chunkhash]',
publicPath: options.dev ? '/assets/' : publicPath
},
module: {
rules: [{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 10000
}
}]
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest']
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
resolve: {
alias: {
'~': resolve(__dirname, 'src')
},
extensions: ['.js', '.vue', '.json', '.css']
},
devServer: {
host: 'local.zyplayer.com',
port: 8010,
proxy: {
'/api/': {
target: 'http://local.zyplayer.com:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
historyApiFallback: {
index: url.parse(options.dev ? '/assets/' : publicPath).pathname
}
},
devtool: options.dev ? '#eval-source-map' : '#source-map'
});

File diff suppressed because it is too large Load Diff