Commit 0edc2446 authored by 姚广胤's avatar 姚广胤

初始化

parents
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"rules": {
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn"
}
}
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
#Mac
.DS_Store
server/.DS_Store
server/static/dist
web/.DS_Store
web/dist
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
server/node_modules/
web/node_modules/
server/upload_store/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
### 背景
公司有一个专用于管理CDN文件上传的系统,该系统全公司各个部门的人都会经常使用到。
之前的工具虽然很稳定,但是界面稍显简陋,代码比较复杂不利于维护。
这次改造希望优化代码架构,简化业务,增加几个必要的功能。
最重要的原因是借助这个项目锻炼自己的技术能力,以及项目管理的能力。
### 功能点分析
Oss工具主要功能模块有:
#### 文件管理:
1. 列出文件和文件夹、文件信息【区分文件夹、常用文件类型图标】
2. 新建文件夹
3. 文件操作(上传、删除)
4. 获取文件链接地址
5. 文件查询(根据文件名模糊查询)
6. 当前文件夹根据文件名过滤
7. 文件同步(从测试bucket同步到线网bucket)
#### 日志管理
1. 已上传文件列表(记录上传人)
2. 文件同步列表(管理员才可同步)
3. 失败列表、异常日志信息、文件删除日志
#### 用户权限管理
普通用户
管理员
### 技术选型
项目的业务逻辑比较简单,尝试使用前后端分离的js全栈方案。
#### 服务端
考虑到nodejs已经可以升级到7.7,原生支持async和await方法了,Koa2使用async/await处理异步事件,是以后的趋势。
所以后端的技术栈设计为:
> Koa2 + Nodejs
#### 网页端
使用vue全家桶 + elementUI
使用vue的原因是vue文档更友好,比较容易上手,现在vue2.0的生态也比较丰富,能很好的涵盖需要的功能。
elementUI用于搭建前端界面,有非常完善的组件样式和对应的示例,对新手友好。
网页端技术栈为:
> vue2.0 (vue + vue-router + vue-resouce) + elementUI
\ No newline at end of file
{
"compilerOptions": {
"lib": ["es6"]
}
}
\ No newline at end of file
/*
* @Author: ygy
* @Date: 2018-03-14 19:40:01
* @Last Modified by: ygy
* @Last Modified time: 2018-03-14 20:27:07
*/
const Koa = require('koa');
const send = require('koa-send');
const bodyParser = require('koa-bodyparser');
const cors = require('koa-cors');
const path = require('path');
const router = require('./router');
const templating = require('./utils/templating');
const rest = require('./utils/rest');
const filter = require('./filter/index');
const task = require('./task/index');
const app = new Koa();
app.use(cors());
// log request URL:
app.use(async (ctx, next) => {
console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
await next();
});
if (process.env.NODE_ENV === 'production') {
//chek user's login state,except index,login,signin pages
app.use(filter.checkLogin);
}
// parse request body:
app.use(bodyParser());
// add nunjucks as view:
app.use(
templating('views', {
noCache: true, //in production ENV,noCache should be changed to false.
watch: true
})
);
app.use(async (ctx, next) => {
if (ctx.path.indexOf('/dist') !== -1) {
await send(ctx, ctx.path, {
root: path.join(__dirname, 'static')
});
} else if (ctx.path === '/private') {
await ctx.render('private.html');
} else {
await next();
}
});
// bind .rest() for ctx:
app.use(rest.restify());
// add controllers:
app.use(router());
const schedule = require('node-schedule');
const j = schedule.scheduleJob({ dayOfWeek: 3, second: 0 }, function() {
console.log('执行任务开始');
task.runTiming();
console.log('执行任务结束');
});
app.listen(3000);
console.log('Project is running at http://localhost:3000/');
var config = {
db: {
dialect: 'mysql',
database: 'fed_pf_test', // 使用哪个数据库
username: 'fed', // 用户名
password: 'tuia123', // 口令
host: '172.16.80.91', // 主机名
port: 3306 // 端口号,MySQL默认3306
},
cookie: {
path: '/', // 写cookie所在的路径
maxAge: 24 * 60 * 60 * 1000, // cookie有效时长
expires: new Date('2019-02-15'), // cookie失效时间
httpOnly: false, // 是否只用于http请求中获取
overwrite: false // 是否允许重写
}
};
module.exports = config;
var config = {
db: {
dialect: 'mysql',
database: 'fed_pf_test', // 使用哪个数据库
username: 'fed', // 用户名
password: 'tuia123', // 口令
host: '172.16.80.91', // 主机名
port: 3306 // 端口号,MySQL默认3306
},
cookie: {
path: '/', // 写cookie所在的路径
maxAge: 24 * 60 * 60 * 1000, // cookie有效时长
expires: new Date('2019-02-15'), // cookie失效时间
httpOnly: false, // 是否只用于http请求中获取
overwrite: false // 是否允许重写
}
};
module.exports = config;
const prodConfig = './config-prod.js';
const devConfig = './config-dev.js';
var config = null;
console.log('===process.env.NODE_ENV***', process.env.NODE_ENV);
if (process.env.NODE_ENV === 'production') {
console.log(`Load DBconfig ${prodConfig}...`);
config = require(prodConfig);
} else {
console.log(`Load DBconfig ${devConfig}...`);
config = require(devConfig);
}
module.exports = config;
const Sequelize = require('sequelize');
const uuid = require('node-uuid');
const config = require('./config');
console.log('init sequelize...');
/**
1、统一主键,名称必须是id,类型必须是STRING(50);
2、主键可以自己指定,也可以由框架自动生成(如果为null或undefined);
3、所有字段默认为NOT NULL,除非显式指定;
统一timestamp机制,每个Model必须有createdAt、updatedAt和version,分别记录创建时间、修改时间和版本号。
其中,createdAt和updatedAt以BIGINT存储时间戳,最大的好处是无需处理时区,排序方便。
version每次修改时自增。
*/
function generateId() {
return uuid.v4(); //1、uuid.v1(); -->基于时间戳生成 (time-based) 2、uuid.v4(); -->随机生成 (random)
}
var sequelize = new Sequelize(config.db.database, config.db.username, config.db.password, {
host: config.db.host,
dialect: config.db.dialect,
pool: {
max: 5,
min: 0,
idle: 10000
}
});
const ID_TYPE = Sequelize.STRING(50);
function defineModel(name, attributes) {
var attrs = {};
attrs.id = {
type: ID_TYPE,
primaryKey: true
};
for (let key in attributes) {
let value = attributes[key];
if (typeof value === 'object' && value['type']) {
value.allowNull = value.allowNull || false;
attrs[key] = value;
} else {
attrs[key] = {
type: value,
allowNull: false
};
}
}
attrs.createdAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.updatedAt = {
type: Sequelize.BIGINT,
allowNull: false
};
attrs.version = {
type: Sequelize.BIGINT,
allowNull: false
};
//打印加载的数据库表结构
// console.log('model defined for table: ' + name + '\n' + JSON.stringify(attrs, function (k, v) {
// if (k === 'type') {
// for (let key in Sequelize) {
// if (key === 'ABSTRACT' || key === 'NUMBER') {
// continue;
// }
// let dbType = Sequelize[key];
// if (typeof dbType === 'function') {
// if (v instanceof dbType) {
// if (v._length) {
// return `${dbType.key}(${v._length})`;
// }
// return dbType.key;
// }
// if (v === dbType) {
// return dbType.key;
// }
// }
// }
// }
// return v;
// }, ' '));
return sequelize.define(name, attrs, {
tableName: name,
timestamps: false,
hooks: {
beforeValidate: function (obj) {
let now = Date.now();
if (obj.isNewRecord) {
console.log('will create entity...');
if (!obj.id) {
obj.id = generateId();
}
obj.createdAt = now;
obj.updatedAt = now;
obj.version = 0;
} else {
console.log('will update entity...');
obj.updatedAt = now;
obj.version++;
}
}
}
});
}
const TYPES = ['STRING', 'INTEGER', 'BIGINT', 'TEXT', 'DOUBLE', 'DATEONLY', 'BOOLEAN'];
var exp = {
defineModel: defineModel,
sync: () => {
// only allow create ddl in non-production environment:
if (process.env.NODE_ENV !== 'production') {
console.log('db.js - sync() called');
return sequelize.sync({
force: true
});
} else {
throw new Error('Cannot sync() when NODE_ENV is set to \'production\'.');
}
}
};
for (let type of TYPES) {
exp[type] = Sequelize[type];
}
exp.ID = ID_TYPE;
exp.generateId = generateId;
exp.sequelize = sequelize;
module.exports = exp;
const model = require('./model.js');
model.sync().then(() => {
console.log('sync done,init db ok.');
process.exit(0);
}).catch((e) => {
console.log('failed with: ' + e);
process.exit(0);
});
\ No newline at end of file
// scan all models defined in models:
const fs = require('fs');
const db = require('./db');
let files = fs.readdirSync(__dirname + '/../models');
let js_files = files.filter((f) => {
return f.endsWith('.js');
}, files);
module.exports = {};
for (let f of js_files) {
console.log(`import model from file ${f}...`);
let name = f.substring(0, f.length - 3);
module.exports[name] = require('../models/' + f);
}
module.exports.sync = () => {
return db.sync();
};
\ No newline at end of file
const historyService = require('../services/historyService');
module.exports = {
'GET /history/list': async (ctx, next) => {
const { type = ''} = ctx.request.query;
let logs = await historyService.findAllPagination(
type
);
ctx.response.body = JSON.stringify(logs);
},
'GET /history/create': async (ctx, next) => {
await historyService.createOne({
result: JSON.stringify({ all: 1020.1 }),
owner: 'test',
type: '发发发',
day: '2018-03-02'
});
ctx.rest({
code: 0,
data: null
});
}
};
const config = require('../config/config');
const unicode = require('../utils/unicode');
const userService = require('../services/userService');
let signup = async(ctx, next) => {
const {
username,
password,
name,
department
} = ctx.request.body;
if (!username || !password || !name || !department) {
ctx.rest({
code: 1,
desc: '参数异常!'
})
}
//数据库查询该用户是否存在
let userExist = await userService.userExist(username);
if (userExist) {
ctx.rest({
code: 1,
desc: '该用户名已注册!'
})
} else {
let newUser = await userService.createUser({
username,
name,
department,
password
});
ctx.rest({
code: 0,
desc: '注册成功!'
})
}
};
let signin = async(ctx, next) => {
let
username = ctx.request.body.username,
password = ctx.request.body.password;
if (!username || !password) {
ctx.rest({
code: 1,
desc: '参数异常!'
})
}
let user = await userService.userCorrect(username, password);
console.log(user)
if (user) {
//响应中设置cookie
let wdata = user.id + '_' + unicode.unicode(user.name) + '_' + user.username;
ctx.cookies.set(
'wdata-oss',
wdata, config.cookie
)
ctx.rest({
code: 0,
desc: '登录成功!'
})
} else {
ctx.rest({
code: 1,
desc: '登录失败!'
})
}
};
const getInfo = async(ctx, next) => {
const wdata = ctx.cookies.get('wdata-oss');
let user;
if (!wdata) {
user = '缔造';
} else {
const unicode = require('../utils/unicode');
user = unicode.reconvert(wdata.split('_')[1]);
}
ctx.rest({
code: 0,
data: user
})
};
const getUserId = async(ctx, next) => {
const wdata = ctx.cookies.get('wdata-oss');
let id;
if (!wdata) {
id = 'dizao';
} else {
id = wdata.split('_')[2];
}
ctx.rest({
code: 0,
data: id
})
};
module.exports = {
'POST /user/signup': signup,
'POST /user/signin': signin,
'GET /user/info': getInfo,
'GET /user/id': getUserId
};
const model = require('../config/model');
let History = model.History;
// History.sync();
module.exports = {
createOne: async(fileObj = {}) => {
const {
result,
type,
owner,
day
} = fileObj;
try {
let newLog = await History.create({
result,
type,
day,
owner
});
return true;
} catch (e) {
return false;
}
},
updateOne: async(fileObj = {}) => {
const {
result,
type,
owner
} = fileObj;
try {
let updateLog = await History.update({
owner,
action
}, {
where: {
type
}
});
return true;
} catch (e) {
return false;
}
},
findAllPagination: async(type, pageSize, currentPage) => {
type = type || '';
let logs = await History.findAndCountAll({
where: {
type: {
$like: '%' + type + '%'
}
},
'order': [
['createdAt', 'DESC']
]
})
return logs;
},
};
const model = require('../config/model');
let User = model.User;
let findOneByUsername = async(username) => {
let user = await User.findOne({
where: {
username
}
});
return user;
}
let findOneById = async(uid) => {
let user = await User.findOne({
where: {
id: uid
}
});
return user;
}
let createUser = async(userObj={}) => {
const {
username,
name,
department,
password
} = userObj;
let newUser = await User.create({
username,
name,
department,
password
});
return newUser;
}
module.exports = {
findOneByUsername,
findOneById,
createUser
};
// 回调地狱
module.exports = function (param, cb) {
asyncFun1(param, function (result1) {
asyncFun2(result1, function (result2) {
asyncFun3(result2, function (result3) {
cb(result3)
})
})
})
};
// Promise
module.exports = function (param, cb) {
asyncFun1(param).then(function (result1) {
return result1;
}
).then(function (result1) {
return asyncFun2(param);
}).then(function (result2) {
return asyncFun3(param);
}).then(function (result3) {
cb(result3);
});
}
// ES6 Generator
module.exports = function* (param, cb) {
const result1 = yield asyncFun1(param);
const result2 = yield asyncFun2(result1);
const result3 = yield asyncFun3(result2);
cb(result3);
};
// ES7
module.exports = async(param, cb) => {
const result1 = await asyncFun1(param);
const result2 = await asyncFun2(result1);
const result3 = await asyncFun3(result2);
cb(result3);
};
const userDao = require('../dao/userDAO');
const checkLogin = async(ctx, next) => {
//首页、登录、注册页面不需要判断登录
if (ctx.request.url === '/' ||
ctx.request.url === '/user/signin' ||
ctx.request.url === '/user/signup' ||
ctx.request.url === '/api/upload4Sword' ||
ctx.request.url === '/dist/public.js' ||
ctx.request.url === '/cdn/flush'
) {
await next();
} else {
const wdata = ctx.cookies.get('wdata-oss'); //获取cookie
if (wdata && wdata.indexOf('_') > 0) {
const uid = wdata.split('_')[0];
var user = await userDao.findOneById(uid);
if (user) {
await next(); //如果cookie解析正确且查询到具体User,则继续中间件
} else {
ctx.response.redirect('/#/signin'); //否则引导至登录页面
}
} else {
ctx.response.redirect('/#/signin');
}
}
};
module.exports = {
checkLogin
};
const db = require('../config/db');
module.exports = db.defineModel('results', {
result: db.STRING(255),
type: db.STRING(100),
day: db.STRING(100),
owner: db.STRING(100)
});
const db = require('../config/db');
module.exports = db.defineModel('users', {
username: {
type: db.STRING(100),
unique: true
},
password: db.STRING(100),
name: db.STRING(100),
department: db.STRING(100)
});
\ No newline at end of file
{
"restartable": "rs",
"ignore": [
".git",
"upload_store/",
"node_modules/**/node_modules"
],
"verbose": true,
"execMap": {
"js": "node --harmony"
},
"events": {
"restart": "osascript -e 'display notification \"App restarted due to:\n'$FILENAME'\" with title \"nodemon\"'"
}
}
\ No newline at end of file
{
"name": "ali-oss-service",
"description": "aiyun oss web tool",
"version": "2.0.0",
"main": "app.js",
"scripts": {
"dev": "export NODE_ENV=development&& nodemon --harmony app.js",
"devwin": "set NODE_ENV=development&& nodemon --harmony app.js",
"prod": "pm2 start pm2.json --env production",
"prodwin": "set NODE_ENV=production&& nodemon --harmony app.js"
},
"keywords": [
"koa",
"async"
],
"author": "jsholic <junhe0723@gmail.com>",
"contributors": [
{
"email": "ygy@duiba.com.cn",
"name": "ygy"
},
{
"email": "fxt@duiba.com.cn",
"name": "方雄韬"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": ""
},
"dependencies": {
"ali-cdn-sdk": "^1.2.0",
"ali-oss": "^4.9.0",
"async-busboy": "^0.4.0",
"koa": "^2.3.0",
"koa-bodyparser": "^3.2.0",
"koa-cors": "0.0.16",
"koa-router": "^7.2.1",
"koa-send": "^4.1.0",
"mime": "^1.3.6",
"mkdirp": "^0.5.1",
"mysql": "^2.14.1",
"mz": "^2.4.0",
"net-ping": "^1.2.1",
"node-schedule": "^1.3.0",
"node-uuid": "^1.4.8",
"nunjucks": "^2.4.2",
"puppeteer": "^1.1.1",
"qcloud-cdn-node-sdk": "^1.0.0",
"sequelize": "^3.24.1",
"tinify": "^1.5.0"
},
"devDependencies": {
"mocha": "^3.5.0",
"nodemon": "^1.11.0"
}
}
{
"apps" : [{
"name" : "ali-oss-service",
"script" : "./app.js",
"watch" : false,
"node_args": ["--harmony"],
"env": {
"NODE_ENV": "default"
},
"env_production" : {
"NODE_ENV": "production"
}
}]
}
const fs = require('fs')
const path = require('path')
function addMapping (router, mapping) {
for (var url in mapping) {
if (url.startsWith('GET ')) {
var path = url.substring(4)
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`)
} else if (url.startsWith('POST ')) {
var path = url.substring(5)
router.post(path, mapping[url])
console.log(`register URL mapping: POST ${path}`)
} else {
console.log(`invalid URL: ${url}`)
}
}
}
function addControllers (router) {
var files = fs.readdirSync(path.resolve(__dirname, '..') + '/controllers')
var js_files = files.filter((f) => {
return f.endsWith('.js')
})
for (var f of js_files) {
console.log(`process controller: ${f}...`)
let mapping = require(path.resolve(__dirname, '..') + '/controllers/' + f)
addMapping(router, mapping)
}
}
module.exports = function (dir) {
let controllers_dir = dir || 'controllers', // 如果不传参数,扫描目录默认为'controllers'
router = require('koa-router')()
addControllers(router, controllers_dir)
return router.routes()
}
const historyDAO = require('../dao/historyDAO');
let findAllPagination = async(path = '', pageSize = 20, currentPage = 1) => {
let logs = await historyDAO.findAllPagination(path, pageSize, currentPage);
let data;
if (logs) {
data = {
code: 0,
desc: '查询成功!',
totalCount: logs.count,
data: logs.rows
}
console.log(logs);
} else {
data = {
code: 1,
desc: '查询失败!',
totalCount: 0,
data: null
}
}
return data;
}
module.exports = {
findAllPagination: findAllPagination,
createOne: historyDAO.createOne,
updateOne: historyDAO.updateOne
}
const model = require('../config/model');
const userDao = require('../dao/userDAO');
let userExist = async(username) => {
let user = await userDao.findOneByUsername(username);
return !!user;
};
let userCorrect = async(username, password) => {
let user = await userDao.findOneByUsername(username);
if (user && user.password == password){
return user;
} else {
return null;
}
};
module.exports = {
userExist: userExist,
userCorrect: userCorrect,
createUser: userDao.createUser
};
/*
* @Author: ygy
* @Date: 2018-03-14 19:39:46
* @Last Modified by: ygy
* @Last Modified time: 2018-03-14 20:21:37
*/
const historyService = require('../services/historyService');
const date = require('../utils/date');
const timing = require('./timing');
const runTiming = async () => {
const urls = [
{
id: 'tuia',
href: `http://activity.tuidragon.com/activity/index?id=5644&slotId=2380&login=normal&appKey=3p1fqtfC3x5krVrsgCmdSx68JPPj&deviceId=b17b1d5e-7dba-4a55-bedb-26ff10bec388&dsm=1.2380.0.0&tenter=SOW&tck_rid_6c8=0a1b5a39jat135tf-6340031&tck_loc_c5d=tactivity-4783&dcm=401.2380.0.0&&tenter=SOW&tck_userId_674=null`,
arr: []
}
];
await timing.iterateTimes(urls, 2);
const resultToSave = urls[0]['arr'];
const total = resultToSave.reduce((item, index) => {
console.log(item, index);
return item + index;
});
await historyService.createOne({
result: JSON.stringify({ all: total / (resultToSave.length || 1) }),
owner: 'test',
type: '大转盘1',
day: date.dateFormat(new Date(), 'yyyy-MM-dd')
});
};
module.exports = {
runTiming
};
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];
/**
* 启用无头浏览器,根据列表里的页面地址去循环执行
*/
const runBrowser = async (urls) => {
const browser = await puppeteer.launch();
const requests = [];
for (const url of urls) {
requests.push(await runPage(browser, url));
}
// const results = await Promise.all(requests);
// console.log(results);
browser.close();
};
/**
* 执行页面,收集性能数据信息
*
* @param {*} page
* @param {*} url
*/
const collectTiming = async (page, url) => {
return await page.evaluate(url => {
const pt = window.performance.timing;
const { href, id } = url;
return {
href,
id,
allEnd: window.allEnd - pt.navigationStart
};
}, url);
};
/**
* 打开某个页面,执行并收集数据
*
* @param {*} browser
* @param {*} url
*/
const runPage = async (browser, url) => {
try {
const page = await browser.newPage();
const { href, arr } = url;
let eventType = 'domcontentloaded';
await page.emulate(iPhone);
await page.goto(href, {});
await page.waitForFunction('window.allEnd > 0');
const dimensions = await collectTiming(page, url);
console.log(dimensions.allEnd);
arr.push(dimensions.allEnd);
await page.close();
} catch (err) {
console.log(err);
return null;
}
};
/**
* 每个页面跑n次来获取测试数据
*
* @param {*} n
*/
const iterateTimes = async (urls, n = 2) => {
for (let i = 0; i < n; i++) {
await runBrowser(urls);
}
};
module.exports = {
iterateTimes
};
var schedule = require("node-schedule");
var date = new Date(2018,2,12,16,56,0);
var j = schedule.scheduleJob(date, function(){
console.log("执行任务");
});
/*
* @Author: ygy
* @Date: 2018-03-14 19:39:55
* @Last Modified by: ygy
* @Last Modified time: 2018-03-14 19:39:55
*/
module.exports = {
dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
}
/**
* restful api
* 将接口restful,自动配置响应类型为json。
*/
module.exports = {
APIError: function(code, message) {
this.code = code || 'internal:unknown_error';
this.message = message || '';
},
restify: (pathPrefix) => {
pathPrefix = pathPrefix || '/api/';
return async(ctx, next) => {
//所有请求都添加rest方法。
// if (ctx.request.path.startsWith(pathPrefix)) {
console.log(`Process API ${ctx.request.method} ${ctx.request.url}...`);
ctx.rest = (data) => {
ctx.response.type = 'application/json';
ctx.response.body = data;
}
try {
await next();
} catch (e) {
console.log('Process API error...');
console.log(e);
ctx.response.status = 400;
ctx.response.type = 'application/json';
ctx.response.body = {
code: e.code || 'internal:unknown_error',
message: e.message || ''
};
}
// } else {
// await next();
// }
};
}
};
const nunjucks = require('nunjucks');
function createEnv(path, opts) {
var
autoescape = opts.autoescape === undefined ? true : opts.autoescape,
noCache = opts.noCache || false,
watch = opts.watch || false,
throwOnUndefined = opts.throwOnUndefined || false,
env = new nunjucks.Environment(
new nunjucks.FileSystemLoader(path, {
noCache: noCache,
watch: watch,
}), {
autoescape: autoescape,
throwOnUndefined: throwOnUndefined
});
if (opts.filters) {
for (var f in opts.filters) {
env.addFilter(f, opts.filters[f]);
}
}
return env;
}
function templating(path, opts) {
var env = createEnv(path, opts);
return async (ctx, next) => {
ctx.render = function (view, model) {
ctx.response.body = env.render(view, Object.assign({}, ctx.state || {}, model || {}));
ctx.response.type = 'text/html';
};
await next();
};
}
module.exports = templating;
//中文转换unicode方法
function unicode(str) {
var value = '';
for (var i = 0; i < str.length; i++) {
value += '\\u' + left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
}
return value;
}
//中文转换unicode辅助方法
function left_zero_4(str) {
if (str != null && str != '' && str != 'undefined') {
if (str.length == 2) {
return '00' + str;
}
}
return str;
}
//Unicode转中文汉字、ASCII转换Unicode
function reconvert(str) {
str = str.replace(/(\\u)(\w{1,4})/gi, function ($0) {
return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{1,4})/g, "$2")), 16)));
});
str = str.replace(/(&#x)(\w{1,4});/gi, function ($0) {
return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{1,4})(%3B)/g, "$2"), 16));
});
str = str.replace(/(&#)(\d{1,6});/gi, function ($0) {
return String.fromCharCode(parseInt(escape($0).replace(/(%26%23)(\d{1,6})(%3B)/g, "$2")));
});
return str;
}
module.exports = {
'unicode': unicode,
'reconvert': reconvert
};
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>闪光</title>
<link rel="shortcut icon" type="image/x-icon" href="//yun.tuiapple.com/tuia/cdn/heaven.ico">
<link rel="stylesheet" href="//yun.tuiapple.com/tuia/tuia-advertiser/bower_components/bootstrap/dist/css/bootstrap.min.css">
</head>
<body style="background-repeat:no-repeat; background-attachment:fixed;background-size:cover;background-image: url(https://img.xjh.me/random_img.php?type=bg&ctype=nature&return=302);">
<div id="app"></div>
<script src="http://localhost:8086/dist/public.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>闪光</title>
<link rel="shortcut icon" type="image/x-icon" href="//yun.tuiapple.com/tuia/cdn/heaven.ico">
<link rel="stylesheet" href="//yun.tuiapple.com/tuia/tuia-advertiser/bower_components/bootstrap/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/3.8.5/echarts-en.common.min.js"></script>
</head>
<body style="background-repeat:no-repeat; background-attachment:fixed;background-size:cover;background-image: url(//yun.duiba.com.cn/tuia/cdn/background-logo.jpg);">
<div id="app"></div>
<script src="http://localhost:8086/dist/private.js"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"presets": [
["env"],
["latest", {
"es2015": { "modules": false }
}]
],
"plugins": ["transform-vue-jsx"]
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# web
> A Vue.js project
## Build Setup
``` bash
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
```
For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader).
const express = require('express');
const path = require('path');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const devConfig = require('./build/webpack.dev.config.js');
const compiler = webpack(devConfig);
const app = express();
app.use(webpackDevMiddleware(compiler, {
publicPath: devConfig.output.publicPath,
stats: {
colors: true,
chunks: false
}
}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('./'));
app.set('view engine', 'html');
app.set('views', path.join(__dirname, './html'));
app.engine('.html', require('ejs').__express);
app.get('/', function(req, res) {
res.render('index');
});
app.use('/private', function(req, res) {
res.render(path.join(__dirname, './private.html'));
});
app.use(require('./mock/router/router'));
console.log(`<http://localhost:8086> with Chrome`);
module.exports = app;
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('epack:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || 8086);
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
var path = require('path');
var glob = require('glob');
const isProd = process.env.NODE_ENV === 'production';
// ----- 动态查找所有入口entry文件 ----- //
var files = glob.sync('./src/containers/*/main.js');
var entryList = {};
// 匹配入口文件
files.forEach(function (f) {
var mainName = /.*\/(containers\/.*?\/main)\.js/.exec(f)[1]; // 得到containers/mobile/main.js这样的文件名
var mainPath = mainName.split('main')[0]; // 得到containers/mobile/这样的文件名
var fileName = mainPath.split('/')[1];
// 记录入口文件
entryList[fileName] = f;
});
Object.keys(entryList).forEach(function (k) {
var arr = [];
arr.push(entryList[k]);
entryList[k] = arr;
});
module.exports = {
entry: entryList,
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: process.env.NODE_ENV === 'production' ? 'http://yun.dui88.com/tuia/cdn/' : '/dist' ,
filename: '[name].js'
},
resolve: {
extensions: ['.js', '.vue'],
alias: {
'comcomp': path.resolve(__dirname, '../src/components'),
'comstyle': path.resolve(__dirname, '../src/styles')
}
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.less$/,
loaders: 'style-loader!css-loader!less-loader'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
{
test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: 'file-loader'
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
}
}
function getIPAdress() {
var interfaces = require('os').networkInterfaces();
for (var devName in interfaces) {
var iface = interfaces[devName];
for (var i = 0; i < iface.length; i++) {
var alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
return alias.address;
}
}
}
}
const webpackBaseConfig = require('./webpack.base');
const webpack = require('webpack')
Object.keys(webpackBaseConfig.entry).forEach(function (name) {
webpackBaseConfig.entry[name] = webpackBaseConfig.entry[name].concat('webpack-hot-middleware/client?reload=true')
})
module.exports = Object.assign(webpackBaseConfig, {
performance: {
hints: false
},
devtool: '#eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
var webpack = require('webpack');
var base = require('./webpack.base');
module.exports = Object.assign(base, {
performance: {
hints: false
},
devtool: '#source-map',
// http://vue-loader.vuejs.org/en/workflow/production.html
plugins : [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>闪光</title>
<link rel="shortcut icon" type="image/x-icon" href="//yun.tuiapple.com/tuia/cdn/heaven.ico">
<link rel="stylesheet" href="//yun.tuiapple.com/tuia/tuia-advertiser/bower_components/bootstrap/dist/css/bootstrap.min.css">
</head>
<body style="background-repeat:no-repeat; background-attachment:fixed;background-size:cover;background-image: url(https://img.xjh.me/random_img.php?type=bg&ctype=nature&return=302);">
<div id="app"></div>
<script src="/dist/public.js"></script>
</body>
</html>
{
"code": 0,
"desc": "查询成功!",
"totalCount": 257,
"data": [
["2000-06-05", 116],
["2000-06-06", 129],
["2000-06-07", 135],
["2000-06-08", 86],
["2000-06-09", 73],
["2000-06-10", 85],
["2000-06-11", 73],
["2000-06-12", 68],
["2000-06-13", 92],
["2000-06-14", 130],
["2000-06-15", 245],
["2000-06-16", 139],
["2000-06-17", 115],
["2000-06-18", 111],
["2000-06-19", 309],
["2000-06-20", 206],
["2000-06-21", 137],
["2000-06-22", 128],
["2000-06-23", 85],
["2000-06-24", 94],
["2000-06-25", 71],
["2000-06-26", 106],
["2000-06-27", 84],
["2000-06-28", 93],
["2000-06-29", 85],
["2000-06-30", 73],
["2000-07-01", 83],
["2000-07-02", 125],
["2000-07-03", 107],
["2000-07-04", 82],
["2000-07-05", 44],
["2000-07-06", 72],
["2000-07-07", 106],
["2000-07-08", 107],
["2000-07-09", 66],
["2000-07-10", 91],
["2000-07-11", 92],
["2000-07-12", 113],
["2000-07-13", 107],
["2000-07-14", 131],
["2000-07-15", 111],
["2000-07-16", 64],
["2000-07-17", 69],
["2000-07-18", 88],
["2000-07-19", 77],
["2000-07-20", 83],
["2000-07-21", 111],
["2000-07-22", 57],
["2000-07-23", 55],
["2000-07-24", 60]
]
}
{
"code": 0,
"msg": "success",
"dirs": [
"DS-online/",
"activity/",
"admin/",
"aerosol/",
"aerosolXml/",
"apk/",
"apks/",
"app/",
"asdfasdf/",
"baidu/",
"couponcode_daily/",
"couponcode_dev/",
"coupons/",
"db-m/",
"db_games/",
"developer/",
"developer_new/",
"ds/",
"duibaFloorCofig/",
"duibaManagerWeb/",
"egret/",
"floorCode/",
"floorSkin/",
"game/",
"h5-tuia/",
"h5/",
"http:/",
"hwqtest/",
"images/",
"layui/",
"lib/",
"maila/",
"mainMeet/",
"mainmeet/",
"mobile/",
"node_test/",
"node_test_img/",
"pcduiba/",
"pptv/",
"resource/",
"simple-dev/",
"static/",
"test/",
"tuia-media/",
"tuia/",
"upload/",
"webapp/"
],
"files": [
"1.png",
"125_599_Tue Aug 16 18:25:46 CST 2016.txt",
"2.png",
"2016-152-5-jxwy.mp4",
"3.png",
"370-230.jpg",
"462_568_Tue Aug 16 18:38:20 CST 2016.txt",
"640-280-yuan.jpg",
"addObject.js",
"address-v12.24.css",
"bundle.js",
"christmasinfo.min.js",
"coolgirl.jpg",
"coupon-code-template.txt",
"dailyduiba-oss-logdaily-duiba2016-09-22-11-00-00-0001",
"dui88",
"duiba-oss-logduiba2016-09-22-11-00-00-0001",
"face.jpg",
"fd1e859a.library_class.min.js",
"file.js",
"gift.png",
"hwq-test.html",
"hwq-test.js",
"import_log",
"kuyin.css",
"lantern.css",
"node_test1.png",
"pptvIframeHack.min.js",
"rem-responsive.js",
"shot.png",
"shot1.png",
"statistics.js",
"test.js",
"user.js",
"webp4.jpg"
]
}
{
"success": "true",
"code": 0
}
{
"code": 0,
"prefix": "//yun.duiba.com.cn"
}
{
"success": "true",
"code": "0",
"path": "h5-tuia/YJk3a1474684409537.png"
}
{
"success": "true",
"code": 0
}
{
"code": 0,
"desc": "查询成功!",
"totalCount": 26,
"data": [
{
"id": "2f2bb8ae-f4a1-4542-bb9c-e2dc0c101b61",
"name": "1.jpeg",
"path": "tuia/test/1.jpeg",
"type": "image/jpeg",
"size": 4831,
"owner": "管理员",
"sync": false,
"createdAt": 1514964614241,
"updatedAt": 1514964614241,
"version": 0
},
{
"id": "9f824ea1-fc43-49f4-ae92-f3c73c0fb080",
"name": "a336845a2e965ca587a0.codemirror.js",
"path": "tuia/tuia-admin/dist/a336845a2e965ca587a0.codemirror.js",
"type": "text/javascript",
"size": 225070,
"owner": "周成",
"sync": true,
"createdAt": 1513583609452,
"updatedAt": 1513583609452,
"version": 0
},
{
"id": "4c8bf8ff-4cbd-41fd-b85f-d5c77a6c8134",
"name": "dd04863ca08f21d3972f.iScroll.js",
"path": "tuia/tuia-admin/dist/dd04863ca08f21d3972f.iScroll.js",
"type": "text/javascript",
"size": 32949,
"owner": "周成",
"sync": true,
"createdAt": 1513583609065,
"updatedAt": 1513583609065,
"version": 0
},
{
"id": "d606abca-b7e1-4bb9-89dd-923bd04fb8e4",
"name": "vendors.js",
"path": "tuia/media-internal/dist/vendors.js",
"type": "text/javascript",
"size": 1599092,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134800634,
"updatedAt": 1513134800634,
"version": 0
},
{
"id": "0a7b1c91-4ffb-48ed-b2f6-1f11f41ed61c",
"name": "Simditor.js",
"path": "tuia/media-internal/dist/Simditor.js",
"type": "text/javascript",
"size": 454689,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134797785,
"updatedAt": 1513134797785,
"version": 0
},
{
"id": "95e1d860-c959-4bb1-8e5a-bc2c1dee110e",
"name": "Spectrum.js",
"path": "tuia/media-internal/dist/Spectrum.js",
"type": "text/javascript",
"size": 28189,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134797138,
"updatedAt": 1513134797138,
"version": 0
},
{
"id": "9b634012-c56d-420f-b586-353e4a46e6da",
"name": "Sortable.js",
"path": "tuia/media-internal/dist/Sortable.js",
"type": "text/javascript",
"size": 12717,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134797096,
"updatedAt": 1513134797096,
"version": 0
},
{
"id": "65e07794-ae28-44c6-9dd3-23cb102a2ef9",
"name": "private.js",
"path": "tuia/media-internal/dist/private.js",
"type": "text/javascript",
"size": 1798600,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796992,
"updatedAt": 1513134796992,
"version": 0
},
{
"id": "6d00dce1-946a-4d38-bce7-17693392c16b",
"name": "DateRangePicker.js",
"path": "tuia/media-internal/dist/DateRangePicker.js",
"type": "text/javascript",
"size": 122351,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796920,
"updatedAt": 1513134796920,
"version": 0
},
{
"id": "caf12054-1134-42a8-bac0-a044d75c9813",
"name": "codemirror.js",
"path": "tuia/media-internal/dist/codemirror.js",
"type": "text/javascript",
"size": 213398,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796766,
"updatedAt": 1513134796766,
"version": 0
},
{
"id": "979fa3d9-b17c-4e01-a7e4-8d4341ca85bd",
"name": "iScroll.js",
"path": "tuia/media-internal/dist/iScroll.js",
"type": "text/javascript",
"size": 33028,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796731,
"updatedAt": 1513134796731,
"version": 0
},
{
"id": "c14c22d1-81b9-47f2-84ac-267add30e429",
"name": "public.js",
"path": "tuia/media-internal/dist/public.js",
"type": "text/javascript",
"size": 15261,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796710,
"updatedAt": 1513134796710,
"version": 0
},
{
"id": "a7c630a7-837b-4400-a758-44c0108303d7",
"name": "html2canvas.js",
"path": "tuia/media-internal/dist/html2canvas.js",
"type": "text/javascript",
"size": 63428,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796531,
"updatedAt": 1513134796531,
"version": 0
},
{
"id": "042db5ac-12c3-4a0c-8add-9d438c2ba71b",
"name": "Jquery.QrCode.js",
"path": "tuia/media-internal/dist/Jquery.QrCode.js",
"type": "text/javascript",
"size": 14025,
"owner": "顾灿灿",
"sync": true,
"createdAt": 1513134796438,
"updatedAt": 1513134796438,
"version": 0
},
{
"id": "b0f68ed6-65b7-442e-801a-8d42cba0c10e",
"name": "detail_dev.css",
"path": "qiho-h5/order/detail_dev.css",
"type": "text/css",
"size": 42614,
"owner": "卢静",
"sync": true,
"createdAt": 1500989998801,
"updatedAt": 1500989998801,
"version": 0
},
{
"id": "2ce1e040-ec4d-4518-a873-6b5a000844fc",
"name": "detail_dev.js",
"path": "qiho-h5/order/detail_dev.js",
"type": "application/javascript",
"size": 27140,
"owner": "卢静",
"sync": true,
"createdAt": 1500989965985,
"updatedAt": 1500989965985,
"version": 0
},
{
"id": "9320dc47-0ab3-4b69-ab84-cd25f47ca224",
"name": "cashier_dev.css",
"path": "qiho-h5/order/cashier_dev.css",
"type": "text/css",
"size": 35531,
"owner": "卢静",
"sync": false,
"createdAt": 1500989952207,
"updatedAt": 1500989952207,
"version": 0
},
{
"id": "f1e84548-89f9-494f-ba23-de03219d53b8",
"name": "success_dev.js",
"path": "qiho-h5/goods/success_dev.js",
"type": "application/javascript",
"size": 47889,
"owner": "卢静",
"sync": true,
"createdAt": 1500946474262,
"updatedAt": 1500946474262,
"version": 0
},
{
"id": "81800d85-90d3-4340-98ee-375b54028744",
"name": "vg_201707241656.css",
"path": "h5-tuia/insurance/shajin/vg_201707241656.css",
"type": "text/css",
"size": 13095,
"owner": "邓沁",
"sync": false,
"createdAt": 1500886594580,
"updatedAt": 1500886594580,
"version": 0
},
{
"id": "654c5f98-a39a-430b-8d9a-b1dab28186c2",
"name": "vg_201707241656.js",
"path": "h5-tuia/insurance/shajin/vg_201707241656.js",
"type": "text/javascript",
"size": 48577,
"owner": "邓沁",
"sync": false,
"createdAt": 1500886593569,
"updatedAt": 1500886593569,
"version": 0
}
]
}
{
"success": "true",
"code": 0
}
{
"code": 0,
"data": "tuia"
}
{
"code": 0,
"data": "本地测试"
}
{
"success": "true",
"code": 0
}
{
"success": "true",
"code": 0
}
{
"/todo/list": "/todo/list",
"/todo/delete": "/todo/delete",
"/todo/sync": "/todo/sync",
"/todo/batchDelete": "/todo/delete",
"/todo/batchSync": "/todo/sync",
"/history/list": "/history/list",
"/oss/prefix": "/oss/prefix",
"/oss/list": "/oss/list",
"/oss/newFolder": "/oss/newFolder",
"/oss/upload": "/oss/upload",
"/user/signin": "/user/signin",
"/user/signup": "/user/signup",
"/user/id": "/user/id",
"/user/info": "/user/name"
}
let path = require('path');
var fs = require('fs');
let router = require('express').Router();
let routerMap = JSON.parse(fs.readFileSync(path.join(__dirname, './router-map.json')));
const handleHttp = (url) => {
return [url, (req, res) => {
let filePath = path.join(__dirname, '../data/', `${routerMap[url]}.json`)
res.json(JSON.parse(fs.readFileSync(filePath)))
}];
};
for (let url in routerMap) {
router.get(...handleHttp(url));
router.post(...handleHttp(url));
}
console.log(router)
module.exports = router;
{
"name": "web",
"description": "aiyun oss web tool",
"version": "2.0.0",
"author": "jsholic <junhe0723@gmail.com>",
"contributors": [
{
"email": "ygy@duiba.com.cn",
"name": "ygy"
},
{
"email": "fxt@duiba.com.cn",
"name": "方雄韬"
}
],
"scripts": {
"start": "cross-env NODE_ENV=development node ./bin/www",
"build": "cross-env NODE_ENV=production webpack -p --progress --hide-modules --config build/webpack.prod.config.js",
"taobao": "npm install --registry=https://registry.npm.taobao.org",
"taobaodev": "npm install --only=dev --registry=https://registry.npm.taobao.org"
},
"dependencies": {
"axios": "^0.18.0",
"clipboard": "^1.6.1",
"element-theme-default": "^1.4.12",
"element-ui": "^2.0.11",
"vue": "^2.5.13",
"vue-resource": "^1.3.1",
"vue-router": "^2.8.1"
},
"devDependencies": {
"babel-core": "^6.0.0",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^6.0.0",
"babel-plugin-syntax-jsx": "^6.8.0",
"babel-plugin-transform-vue-jsx": "^3.3.0",
"babel-preset-env": "^1.6.1",
"babel-preset-latest": "^6.0.0",
"cross-env": "^3.0.0",
"css-loader": "^0.25.0",
"ejs": "^2.5.7",
"file-loader": "^0.9.0",
"glob": "^7.1.1",
"less": "^2.7.2",
"less-loader": "^4.0.3",
"style-loader": "^0.16.1",
"vue-loader": "^11.3.4",
"vue-template-compiler": "^2.5.13",
"webpack": "^2.2.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-dev-server": "^2.9.3",
"webpack-hot-middleware": "^2.20.0",
"webpack-merge": "^4.1.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>闪光</title>
<link rel="shortcut icon" type="image/x-icon" href="//yun.tuiapple.com/tuia/cdn/heaven.ico">
<link rel="stylesheet" href="//yun.tuiapple.com/tuia/tuia-advertiser/bower_components/bootstrap/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/3.8.5/echarts-en.common.min.js"></script>
</head>
<body style="background-repeat:no-repeat; background-attachment:fixed;background-size:cover;background-image: url(//yun.duiba.com.cn/tuia/cdn/background-logo.jpg);">
<div id="app"></div>
<script src="/dist/private.js"></script>
</body>
</html>
export default {
setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
const expires = 'expires=' + d.toUTCString();
document.cookie = cname + '=' + cvalue + '; ' + expires;
},
getCookie(name) {
const regexp = new RegExp('(^| )' + name + '=([^;]*)(;|$)');
const matches = regexp.exec(document.cookie);
return matches ? matches[2] : null;
},
clearCookie(name) {
this.setCookie(name, '', -1);
}
}
export default {
dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
}
export default {
getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
}
<template>
<router-view>
</router-view>
</template>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
h1,
h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 0 10px;
}
a {
color: #4287ed;
}
.el-button {
border-radius: 2px !important;
}
.el-input__inner {
border-radius: 2px !important;
}
body {
margin: 0;
}
input[type=file] {
display: none !important;
}
</style>
<template lang="html">
<div ref="myEchart" style="width: 1200px;height:400px;"></div>
</template>
<script>
import { Loading } from 'element-ui';
import axios from 'axios';
export default {
data() {
return {
chart: undefined
};
},
mounted() {
this.fetch();
},
beforeDestroy() {
clipboard.destroy();
},
methods: {
fetch() {
axios
.get('/history/list')
.then(response => {
this.initChart(response.data.data);
})
.catch(error => {
console.log(error);
});
},
initChart(data) {
this.chart = echarts.init(this.$refs.myEchart);
const xData = data.map(item => item[0]);
const yData = data.map(item => item[1]);
console.log(xData, yData);
var option = {
title: {
text: '性能分析'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['tuia']
},
toolbox: {
show: true,
feature: {
dataZoom: {
yAxisIndex: 'none'
},
dataView: { readOnly: false },
magicType: { type: ['line', 'bar'] },
restore: {},
saveAsImage: {}
}
},
xAxis: {
type: 'category',
data: xData,
boundaryGap: false
},
yAxis: {
type: 'value'
},
series: [
{
data: yData,
name: 'tuia',
type: 'line',
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
]
},
markLine: {
data: [{ type: 'average', name: '平均值' }]
}
}
]
};
// 把配置和数据放这里
this.chart.setOption(option);
}
},
components: {}
};
</script>
<style lang="css">
</style>
<template lang="html">
<div class="wrap" @drop.prevent @dragover.prevent @dragleave.prevent>
<DirTree></DirTree>
</div>
</template>
<script>
import DirTree from './DirTree.vue'
export default {
data: () => ({
msg: 'OSS文件管理'
}),
components: {
DirTree
}
}
</script>
<style lang="css">
.content {
padding: 20px 50px;
}
.button-group {
margin-bottom: 15px;
}
</style>
import Vue from 'vue'
import VueRouter from "vue-router"
import VueResource from 'vue-resource'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'
import Index from './components/Index.vue'
import 'comstyle/layout.less';
Vue.use(VueRouter)
Vue.use(VueResource)
Vue.use(ElementUI)
const router = new VueRouter({
base: __dirname,
routes: [{
path: '/',
redirect: '/home'
}, {
path: '/home',
component: Index
}]
})
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
<template>
<router-view>
</router-view>
</template>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
h1,
h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 0 10px;
}
.el-menu {
background-color: transparent;
}
.el-menu--horizontal {
border: none !important;
}
.login-wrap {
width: 760px;
min-height: 476px;
margin: 260px auto;
padding-right: 200px;
padding-left: 200px;
background-color: transparent;
}
.el-button {
border-radius: 2px !important;
}
.el-input__inner {
border-radius: 2px !important;
}
</style>
<template lang="html">
<el-menu :default-active="activeIndex" mode="horizontal" @select="handleSelect" router>
<h2 class="nav-title">苍穹</h2>
<el-menu-item index="signin">登录</el-menu-item>
<el-menu-item index="signup">注册</el-menu-item>
</el-menu>
</template>
<script>
export default {
data() {
const hrefArray = window.location.href.split('/');
const activeIndex = hrefArray[hrefArray.length - 1];
return {
activeIndex
};
},
methods: {
handleSelect(key, keyPath) {
console.log(key, keyPath);
}
}
}
</script>
<style lang="css">
.nav-title {
position: relative;
float: left;
margin: 13px;
color: #fff;
}
.el-menu {
padding: 0 20px;
}
.el-menu-item {
font-size: 16px;
color: #fff !important;
}
.el-menu-item:hover {
background-color: transparent !important;
}
</style>
<template lang="html">
<div>
<!-- <NavHeader /> -->
<div class="login-wrap">
<el-form class="login-ruleForm" :model="ruleForm" label-position="top" :rules="rules" ref="ruleForm" label-width="100px">
<el-form-item style="text-align:center;">
<img class="logo" src="//yun.tuiapple.com/tuia/cdn/heaven-logo.png" alt="">
</el-form-item>
<el-form-item prop="username">
<el-input placeholder="账号" v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input placeholder="密码" type="password" v-model="ruleForm.password" auto-complete="off"></el-input>
</el-form-item>
<el-form-item class="submit-button">
<el-button @click="toSignup('ruleForm')">注册</el-button>
<el-button type="primary" @click="submitForm('ruleForm')" @keyup.enter="submitForm('ruleForm')">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import NavHeader from '../NavHeader.vue';
import { Message, Loading } from 'element-ui';
export default {
data() {
var checkName = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入用户名'));
} else {
callback();
}
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
callback();
}
};
return {
msg: 'OSS文件管理',
ruleForm: {
password: '',
username: ''
},
rules: {
password: [{
validator: validatePass,
trigger: 'blur'
}],
username: [{
validator: checkName,
trigger: 'blur'
}]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
const {
username,
password
} = this.ruleForm;
this.$http.post('/user/signin', {
username,
password
}).then((response) => {
if (response.data.code === 0) {
window.location.replace('/private');
} else {
Message.error({ message: '密码错误或者账号不存在', duration: 3000 });
}
}, (error) => {
Message.error({ message: '登录失败', duration: 3000 });
});
} else {
this.$message.error('填写信息不正确');
return false;
}
});
},
toSignup(formName) {
window.location.href = '#/signup';
}
},
components: {
NavHeader
}
}
</script>
<style lang="css">
a {
cursor: pointer;
}
.inline {
display: inline;
margin: 0 5px;
}
.login-ruleForm {
margin-top: 50px;
}
.submit-button {
margin-top: 30px;
}
.submit-button button{
width: 48%;
}
.title {
font-size: 32px;
color: #fff;
}
</style>
<template lang="html">
<div>
<!-- <NavHeader /> -->
<div class="login-wrap">
<el-form :model="ruleForm" label-position="top" :rules="rules" ref="ruleForm" label-width="100px" class="signin-ruleForm">
<el-form-item style="text-align:center;">
<img class="logo" src="//yun.tuiapple.com/tuia/cdn/heaven-logo.png" alt="">
</el-form-item>
<el-form-item prop="username">
<el-input placeholder="账号" v-model="ruleForm.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input placeholder="密码" type="password" v-model="ruleForm.password" auto-complete="off"></el-input>
</el-form-item>
<el-form-item prop="checkPass">
<el-input placeholder="确认密码" type="password" v-model="ruleForm.checkPass" auto-complete="off"></el-input>
</el-form-item>
<el-form-item prop="name">
<el-input placeholder="真实名字" v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item prop="department">
<el-input placeholder="部门" v-model="ruleForm.department"></el-input>
</el-form-item>
<el-form-item class="submit-button">
<el-button @click="toSignin('ruleForm')">登录</el-button>
<el-button type="primary" @click="submitForm('ruleForm')">注册</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import NavHeader from '../NavHeader.vue';
import { Message, Loading } from 'element-ui';
export default {
data() {
var checkName = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入用户名'));
} else {
callback();
}
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
var checkRealName = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入真实姓名'));
} else {
callback();
}
};
var checkDepartment = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入部门名称'));
} else {
callback();
}
};
return {
msg: 'OSS文件管理',
ruleForm: {
password: '',
username: '',
checkPass: '',
name: '',
department: ''
},
rules: {
password: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
username: [
{ validator: checkName, trigger: 'blur' }
],
name: [
{ validator: checkRealName, trigger: 'blur' }
],
department: [
{ validator: checkDepartment, trigger: 'blur' }
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
const {
username,
password,
name,
department
} = this.ruleForm;
this.$http.post('/user/signup', { username, password, name, department }).then((response) => {
if (response.data.code === 0) {
Message.success({ message: '注册成功', duration: 3000 });
window.location.href = '#/signin';
} else {
Message.success({ message: '注册失败', duration: 3000 });
}
}, (error) => {
Message.error({ message: '注册失败', duration: 3000 });
});
} else {
this.$message.error('填写信息不正确');
return false;
}
});
},
toSignin(formName) {
window.location.href = '#/signin';
}
},
components: {
NavHeader
}
}
</script>
<style lang="css">
a {
cursor: pointer;
}
.inline {
display: inline;
margin: 0 5px;
}
.title {
font-size: 32px;
color: #fff;
}
.submit-button button{
width: 48%;
}
.signin-ruleForm {
margin-top: 50px;
margin-bottom: 50px;
}
</style>
import Vue from 'vue'
import VueRouter from "vue-router"
import VueResource from 'vue-resource'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'
import Signin from './components/signin/Signin.vue'
import Signup from './components/signup/Signup.vue'
Vue.use(VueRouter)
Vue.use(VueResource)
Vue.use(ElementUI)
const router = new VueRouter({
// mode: 'history',
base: __dirname,
routes: [{
path: '/',
redirect: '/signin'
}, {
path: '/signin',
component: Signin
}, {
path: '/signup',
component: Signup
}]
})
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
.oss-container {
padding: 30px 50px 0;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment