├── backstage
├── src
│ ├── css
│ │ ├── keyframe.css
│ │ ├── variables.scss
│ │ ├── index.scss
│ │ ├── mixin.scss
│ │ ├── reset.css
│ │ ├── element-variables.scss
│ │ └── index.css
│ ├── store
│ │ ├── edit
│ │ │ ├── action
│ │ │ │ ├── item.js
│ │ │ │ ├── phone.js
│ │ │ │ └── page.js
│ │ │ ├── index.js
│ │ │ ├── mutation-types.js
│ │ │ ├── getters.js
│ │ │ └── modules
│ │ │ │ └── page.js
│ │ └── index.js
│ ├── config.js
│ ├── page
│ │ ├── list
│ │ │ ├── bus.js
│ │ │ ├── list.vue
│ │ │ ├── header.vue
│ │ │ ├── feed.vue
│ │ │ └── create.vue
│ │ ├── edit
│ │ │ ├── event.vue
│ │ │ ├── edit.vue
│ │ │ ├── page-dom.vue
│ │ │ ├── qrcode.vue
│ │ │ ├── tool.vue
│ │ │ ├── page.vue
│ │ │ ├── ani.vue
│ │ │ └── phone.vue
│ │ └── login
│ │ │ └── login.vue
│ ├── img
│ │ ├── git.png
│ │ ├── logo.png
│ │ ├── logo2.png
│ │ ├── logo_header.png
│ │ ├── phonewhite.svg
│ │ ├── show.svg
│ │ ├── music_btn.svg
│ │ ├── bg.svg
│ │ └── notfound.svg
│ ├── iconfont
│ │ ├── iconfont.eot
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
│ ├── tpl
│ │ ├── types.js
│ │ ├── tpl.art
│ │ └── index.js
│ ├── App.vue
│ ├── components
│ │ ├── crop
│ │ │ └── index.js
│ │ ├── image
│ │ │ ├── index.js
│ │ │ └── main.vue
│ │ ├── music
│ │ │ ├── index.js
│ │ │ └── main.vue
│ │ ├── shape
│ │ │ ├── index.js
│ │ │ └── main.vue
│ │ ├── background
│ │ │ ├── index.js
│ │ │ └── main.vue
│ │ └── dialog
│ │ │ └── dialog.vue
│ ├── api
│ │ ├── fetch.js
│ │ └── index.js
│ ├── keycode
│ │ └── index.js
│ ├── router
│ │ └── index.js
│ ├── utils
│ │ └── index.js
│ ├── main.js
│ └── directive
│ │ ├── drag.js
│ │ └── select.js
├── public
│ ├── favicon.ico
│ └── index.html
├── .editorconfig
├── .gitignore
├── babel.config.js
├── README.md
├── package.json
├── utils
│ └── index.js
└── vue.config.js
├── server
├── api
│ ├── index.js
│ ├── types.js
│ ├── login.js
│ └── scene.js
├── .jsbeautifyrc
├── views
│ ├── index.jade
│ ├── error.jade
│ ├── layout.jade
│ └── index.art
├── utils
│ └── index.js
├── db
│ ├── index.js
│ ├── handel.js
│ └── model.js
├── public
│ └── stylesheets
│ │ └── style.css
├── .editorconfig
├── const
│ └── index.js
├── upload
│ ├── a.js
│ ├── down.js
│ ├── update_music.js
│ ├── b.js
│ ├── index.js
│ └── app.js
├── models
│ ├── login.js
│ └── scene.js
├── qiniu
│ ├── upload.js
│ └── move.js
├── bin
│ └── www
├── package.json
└── app.js
├── h5
├── babel.config.js
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── index.art
├── src
│ ├── assets
│ │ └── logo.png
│ ├── img
│ │ └── view_bg.png
│ ├── api
│ │ ├── index.js
│ │ └── fetch.js
│ ├── art
│ │ └── index.art
│ ├── main.js
│ └── css
│ │ └── index.scss
├── .gitignore
├── README.md
├── vue.config.js
└── package.json
├── .jsbeautifyrc
├── .editorconfig
├── documents
├── question.md
├── todo.md
└── changelog.md
├── .gitignore
├── README.md
├── utils
└── index.js
├── LICENSE
└── package.json
/backstage/src/css/keyframe.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/action/item.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/action/phone.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backstage/src/config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | revoke: true
3 | }
4 |
--------------------------------------------------------------------------------
/server/api/index.js:
--------------------------------------------------------------------------------
1 | require('./edit')
2 | require('./scene')
3 | require('./login')
--------------------------------------------------------------------------------
/backstage/src/page/list/bus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | export default new Vue;
3 |
--------------------------------------------------------------------------------
/h5/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ]
5 | }
--------------------------------------------------------------------------------
/.jsbeautifyrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent_size": "4",
3 | "brace_style": "collapse-preserve-inline"
4 | }
--------------------------------------------------------------------------------
/h5/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/h5/public/favicon.ico
--------------------------------------------------------------------------------
/h5/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/h5/src/assets/logo.png
--------------------------------------------------------------------------------
/h5/src/img/view_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/h5/src/img/view_bg.png
--------------------------------------------------------------------------------
/backstage/src/img/git.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/img/git.png
--------------------------------------------------------------------------------
/backstage/src/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/img/logo.png
--------------------------------------------------------------------------------
/backstage/src/img/logo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/img/logo2.png
--------------------------------------------------------------------------------
/server/.jsbeautifyrc:
--------------------------------------------------------------------------------
1 | {
2 | "indent_size": "2",
3 | "brace_style": "collapse-preserve-inline"
4 | }
--------------------------------------------------------------------------------
/backstage/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/public/favicon.ico
--------------------------------------------------------------------------------
/server/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= title
5 | p Welcome to #{title}
6 |
--------------------------------------------------------------------------------
/backstage/src/img/logo_header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/img/logo_header.png
--------------------------------------------------------------------------------
/backstage/src/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/backstage/src/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/backstage/src/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Braised-Cakes/myh5/HEAD/backstage/src/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/server/views/error.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= message
5 | h2= error.status
6 | pre #{error.stack}
7 |
--------------------------------------------------------------------------------
/h5/src/api/index.js:
--------------------------------------------------------------------------------
1 | import fetch from './fetch'
2 |
3 | export const getSceneData = data => fetch('/aj/scene/getPublishData', data);
4 |
--------------------------------------------------------------------------------
/server/utils/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 获取当前时间
3 | */
4 | module.exports.getTime = function () {
5 | return new Date().getTime()
6 | }
7 |
--------------------------------------------------------------------------------
/server/db/index.js:
--------------------------------------------------------------------------------
1 | let mongoose = require('mongoose')
2 | let db = mongoose.createConnection('mongodb://localhost/test')
3 | mongoose.Promise = Promise
4 | module.exports = db
--------------------------------------------------------------------------------
/server/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/server/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title= title
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | body
7 | block content
8 |
--------------------------------------------------------------------------------
/backstage/src/css/variables.scss:
--------------------------------------------------------------------------------
1 | $headerHeight:56px;
2 | $panelZIndex:1002;
3 | $headerZIndex:2;
4 | $pageZIndex:1;
5 | $helpZIndex:1000;
6 | $maskZIndex:1001;
7 | $workspaceZIndex:3;
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/server/.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 |
--------------------------------------------------------------------------------
/backstage/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/backstage/src/tpl/types.js:
--------------------------------------------------------------------------------
1 | /*
2 | 元素系列
3 | */
4 |
5 | export const TXT = 'txt';
6 |
7 | export const SHAPE = 'shape';
8 | export const MUSIC = 'music';
9 |
10 | export const IMAGE = 'image';
11 |
12 | export const QRCODE = 'qrcode';
--------------------------------------------------------------------------------
/backstage/src/css/index.scss:
--------------------------------------------------------------------------------
1 | @import '~@/css/variables.scss';
2 | .my-mask {
3 | position: fixed;
4 | left: 0;
5 | top: 0;
6 | width: 100%;
7 | height: 100%;
8 | opacity: 0.5;
9 | background: #000;
10 | z-index: $maskZIndex;
11 | }
12 |
--------------------------------------------------------------------------------
/documents/question.md:
--------------------------------------------------------------------------------
1 | # Question
2 |
3 | ## crop
4 |
5 | - [ ] 调用方式?
6 | - [ ] 如何处理图片尺寸问题?
7 |
8 | ```javascript
9 | this.$crop({
10 | src : 'http://baidu.com/a.png',
11 | callback: ()=>{}
12 | })
13 |
14 |
15 | 增加两个字段
16 |
17 | originPath
18 |
19 | crop
20 | ```
21 |
22 |
--------------------------------------------------------------------------------
/server/const/index.js:
--------------------------------------------------------------------------------
1 | module.exports.DEFAULT_PAGE = {
2 | limit: 15,
3 | page: 1
4 | }
5 |
6 | module.exports.AJ_MESSAGE = {
7 | success: 'success',
8 | error: 'error',
9 |
10 | }
11 |
12 | module.exports.AJ_STATUS = {
13 | success: 0,
14 | error: 1,
15 | notlogin: 2
16 | }
17 |
--------------------------------------------------------------------------------
/h5/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/backstage/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | /dist2
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 |
23 | .key.js
--------------------------------------------------------------------------------
/backstage/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ],
5 | plugins: [
6 | [
7 | "component",
8 | {
9 | "libraryName": "element-ui",
10 | "styleLibraryName": "theme-chalk"
11 | }
12 | ]
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/h5/README.md:
--------------------------------------------------------------------------------
1 | # h4
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | yarn run lint
21 | ```
22 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/index.js:
--------------------------------------------------------------------------------
1 | import actions from './action'
2 | import getters from './getters'
3 | import mutations from './mutations'
4 | import * as constant from '@/constant'
5 |
6 | const state = {
7 | ...constant.initState
8 | }
9 |
10 | export default {
11 | state,
12 | getters,
13 | actions,
14 | mutations
15 | }
--------------------------------------------------------------------------------
/backstage/README.md:
--------------------------------------------------------------------------------
1 | # backstage
2 |
3 | ## Project setup
4 | ```
5 | yarn install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | yarn run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | yarn run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | yarn run lint
21 | ```
22 |
--------------------------------------------------------------------------------
/server/upload/a.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path');
3 | const {
4 | uploadFile
5 | } = require('./index.js');
6 |
7 |
8 |
9 | (async () => {
10 | await uploadFile('yq0KZVbqTEaAXk33AAAD205QFoU790.svg', '/Users/BraisedCakes/Desktop/2018/myh5-store/svg/yq0KZVbqTEaAXk33AAAD205QFoU790.svg')
11 | console.log('成功一张')
12 | })()
13 |
--------------------------------------------------------------------------------
/server/db/handel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose')
2 | const models = require("./model.js")
3 | const db = require("./index.js")
4 | const Schemas = {}
5 | for (let key in models) {
6 | Schemas[key] = new mongoose.Schema(models[key])
7 | }
8 |
9 | module.exports = {
10 | getModel: function (item) {
11 | return db.model(item, Schemas[item])
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # myh5
2 |
3 | > myh5页面制作工具, 一键生成H5酷炫页面, 类似于易企秀!
4 |
5 | ## 技术栈
6 |
7 | vue, node, sass, express, mongoose
8 |
9 |
10 | ## Build Setup
11 |
12 | ``` bash
13 | # install dependencies
14 | npm install
15 |
16 | # serve with hot reload at localhost:8080
17 | npm run start
18 |
19 | # build for production with minification
20 | npm run build
21 |
22 | ```
23 | ## CHANGELOG
24 |
25 | [@CHANGELOG](./documents/changelog.md)
26 |
27 | ## TODU
28 |
29 | [@TODU](./documents/todo.md)
--------------------------------------------------------------------------------
/backstage/src/img/phonewhite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/api/types.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 登录相关
3 | */
4 | module.exports.getUserInfo = '/aj/user/info'
5 | module.exports.userLogin = '/aj/user/login'
6 | module.exports.userRegister = '/aj/user/register'
7 | module.exports.userLogout = '/aj/user/logout'
8 |
9 |
10 | /**
11 | * 指定场景的操作
12 | */
13 | module.exports.getSceneData = '/aj/scene/get'
14 | module.exports.getPublishScene = '/aj/scene/getPublishData'
15 | module.exports.saveScene = '/aj/scene/save'
16 | module.exports.updateScene = '/aj/scene/update'
17 |
--------------------------------------------------------------------------------
/h5/src/api/fetch.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery';
2 |
3 | export default async function (url, data, type = 'GET') {
4 | return new Promise((resolve) => {
5 | $.ajax({
6 | url: url,
7 | dataType: 'json',
8 | data: type == 'GET' ? data : JSON.stringify(data),
9 | type: type,
10 | // contentType: 'application/json; charset=UTF-8',
11 | success(rs) {
12 | resolve(rs);
13 | }
14 | });
15 | })
16 | }
17 |
--------------------------------------------------------------------------------
/server/models/login.js:
--------------------------------------------------------------------------------
1 | let dbHandel = require('../db/handel.js')
2 | let collection = dbHandel.getModel('user')
3 |
4 | module.exports = {
5 | // 判断用户名和密码是否匹配
6 | goLogin(user, pass) {
7 | return collection.findOne({ username: user, password: pass })
8 | },
9 |
10 | // 判断用户名是否存在
11 | getUser(user) {
12 | return collection.findOne({ username: user })
13 | },
14 |
15 | //注册
16 | login({ user, pass, uid }) {
17 | return new collection({ username: user, password: pass, uid: uid }).save()
18 | }
19 | }
--------------------------------------------------------------------------------
/backstage/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backstage",
3 | "version": "0.3.0",
4 | "scripts": {
5 | "dev": "vue-cli-service serve --open",
6 | "server": "node ./server/bin/www",
7 | "build": "vue-cli-service build",
8 | "start": "concurrently \"yarn dev\" \"yarn server\"",
9 | "lint": "vue-cli-service lint"
10 | },
11 | "postcss": {
12 | "plugins": {
13 | "autoprefixer": {}
14 | }
15 | },
16 | "browserslist": [
17 | "> 1%",
18 | "last 2 versions",
19 | "not ie <= 8"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/documents/todo.md:
--------------------------------------------------------------------------------
1 |
2 | # TODU
3 |
4 | * ## h5
5 | - [ ] 发布状态才允许查看
6 |
7 | * ## 列表页
8 | - [x] 创建
9 | - [x] 删除
10 | - [x] 复制
11 | - [x] 回收站
12 | - [x] 发布状态
13 |
14 | * ## 元素操作
15 | - [x] 添加
16 | - [x] 删除
17 | - [x] 单选
18 | - [x] 多选
19 | - [x] 撤销&&重做
20 |
21 | * ## 登录
22 | - [x] 注册
23 | - [x] 登录
24 | - [ ] 找回密码
25 | - [ ] 接入qq登录
26 |
27 | * ## 图片
28 | - [x] 图片库
29 | - [x] 最近使用
30 | - [x] 用户上传
31 | - [ ] 图片管理
32 | - [x] 图片裁切功能
33 |
34 | * ## 音乐
35 | - [x] 音乐库
36 | - [x] 最近使用
37 | - [x] 用户上传
38 | - [ ] 添加外链
39 | - [ ] 音乐管理
40 |
41 | * ## 形状
42 | - [x] 形状库
43 | - [x] 最近使用
44 | - [ ] 用户上传
45 | - [ ] 形状管理
46 |
47 | * ## 二维码
48 | - [x] 生成
49 | - [ ] 自定义logo
50 |
51 | * ## 表单
--------------------------------------------------------------------------------
/backstage/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
26 |
--------------------------------------------------------------------------------
/h5/src/art/index.art:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ each data }}
4 |
5 |
6 | {{each $value.data}}
7 |
8 | {{@ $value.content }}
9 |
10 | {{/each}}
11 |
12 |
13 | {{/each}}
14 |
15 |
--------------------------------------------------------------------------------
/backstage/src/tpl/tpl.art:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ each data }}
4 |
5 |
6 | {{each $value.data}}
7 |
8 | {{@ $value.content }}
9 |
10 | {{/each}}
11 |
12 |
13 | {{/each}}
14 |
15 |
--------------------------------------------------------------------------------
/h5/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devServer: {
3 | proxy: {
4 | '/aj': {
5 | target: 'http://localhost:3000', // 你接口的域名
6 | secure: true,
7 | changeOrigin: true
8 | },
9 | '/store': {
10 | target: 'http://localhost:3000', // 你接口的域名
11 | secure: true,
12 | changeOrigin: true
13 | },
14 | '/show': {
15 | target: 'http://localhost:3000', // 你接口的域名
16 | secure: true,
17 | changeOrigin: true
18 | },
19 | '/app.js': {
20 | target: 'http://localhost:3000', // 你接口的域名
21 | secure: true,
22 | changeOrigin: true
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/backstage/src/components/crop/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './main.vue'
2 |
3 | export default {
4 | install(Vue, options = {}) {
5 | const VueToast = Vue.extend(Toast)
6 | let toast = null
7 |
8 | function $toast(params) {
9 | return new Promise(resolve => {
10 | if (!toast) {
11 | toast = new VueToast()
12 |
13 | toast.$mount()
14 |
15 | document.querySelector(options.container || 'body').appendChild(toast.$el)
16 | }
17 | console.log('plugin done')
18 | toast.init(params)
19 | resolve()
20 | })
21 | }
22 |
23 | Vue.prototype.$crop = $toast
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backstage/src/components/image/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './main.vue'
2 |
3 | export default {
4 | install(Vue, options = {}) {
5 | const VueToast = Vue.extend(Toast)
6 | let toast = null
7 |
8 | function $toast(params) {
9 | return new Promise(resolve => {
10 | if (!toast) {
11 | toast = new VueToast()
12 |
13 | toast.$mount()
14 |
15 | document.querySelector(options.container || 'body').appendChild(toast.$el)
16 | }
17 | console.log('plugin done')
18 | toast.init(params)
19 | resolve()
20 | })
21 | }
22 |
23 | Vue.prototype.$image = $toast
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backstage/src/components/music/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './main.vue'
2 |
3 | export default {
4 | install(Vue, options = {}) {
5 | const VueToast = Vue.extend(Toast)
6 | let toast = null
7 |
8 | function $toast(params) {
9 | return new Promise(resolve => {
10 | if (!toast) {
11 | toast = new VueToast()
12 |
13 | toast.$mount()
14 |
15 | document.querySelector(options.container || 'body').appendChild(toast.$el)
16 | }
17 | console.log('plugin done')
18 | toast.init(params)
19 | resolve()
20 | })
21 | }
22 |
23 | Vue.prototype.$music = $toast
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backstage/src/components/shape/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './main.vue'
2 |
3 | export default {
4 | install(Vue, options = {}) {
5 | const VueToast = Vue.extend(Toast)
6 | let toast = null
7 |
8 | function $toast(params) {
9 | return new Promise(resolve => {
10 | if (!toast) {
11 | toast = new VueToast()
12 |
13 | toast.$mount()
14 |
15 | document.querySelector(options.container || 'body').appendChild(toast.$el)
16 | }
17 | console.log('plugin done')
18 | toast.init(params)
19 | resolve()
20 | })
21 | }
22 |
23 | Vue.prototype.$shape = $toast
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backstage/src/components/background/index.js:
--------------------------------------------------------------------------------
1 | import Toast from './main.vue'
2 |
3 | export default {
4 | install(Vue, options = {}) {
5 | const VueToast = Vue.extend(Toast)
6 | let toast = null
7 |
8 | function $toast(params) {
9 | return new Promise(resolve => {
10 | if (!toast) {
11 | toast = new VueToast()
12 |
13 | toast.$mount()
14 |
15 | document.querySelector(options.container || 'body').appendChild(toast.$el)
16 | }
17 | console.log('plugin done')
18 | toast.init(params)
19 | resolve()
20 | })
21 | }
22 |
23 | Vue.prototype.$image = $toast
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/backstage/src/css/mixin.scss:
--------------------------------------------------------------------------------
1 | //定位上下居中
2 | @mixin ct {
3 | position: absolute;
4 | top: 50%;
5 | transform: translateY(-50%);
6 | }
7 |
8 | //定位左右居中
9 | @mixin cl {
10 | position: absolute;
11 | left: 50%;
12 | transform: translateX(-50%);
13 | }
14 |
15 | //定位上下左右居中
16 | @mixin ctl {
17 | position: absolute;
18 | left: 50%;
19 | top: 50%;
20 | transform: translate(-50%, -50%);
21 | }
22 |
23 | //宽高
24 | @mixin wh($width, $height) {
25 | width: $width;
26 | height: $height;
27 | }
28 |
29 | //字体大小,颜色
30 | @mixin sc($size, $color) {
31 | font-size: $size;
32 | color: $color;
33 | }
34 |
35 | //flex 布局和 子元素 对其方式
36 | @mixin fj($type: space-between) {
37 | display: flex;
38 | justify-content: $type;
39 | }
40 |
--------------------------------------------------------------------------------
/backstage/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import $ from 'jquery'
4 | import edit from './edit'
5 | import * as constant from '@/constant'
6 | Vue.use(Vuex);
7 | const state = {
8 | auth: {
9 | request: false,
10 | username: null
11 | }
12 | };
13 | const getters = {};
14 | const actions = {};
15 | const mutations = {
16 | UPDATE_USER_INFO(state, {
17 | username,
18 | uid
19 | }) {
20 | state.auth.username = username;
21 | state.auth.uid = uid;
22 | }
23 | }
24 | export default new Vuex.Store({
25 | strict: process.env.NODE_ENV !== 'production',
26 | state,
27 | getters,
28 | actions,
29 | mutations,
30 | modules: {
31 | edit
32 | }
33 | })
--------------------------------------------------------------------------------
/backstage/src/api/fetch.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 |
3 | export default async function (url, data, type = 'GET') {
4 | return new Promise((resolve, reject) => {
5 | $.ajax({
6 | url: url,
7 | dataType: 'json',
8 | data: type == 'GET' ? data : JSON.stringify(data),
9 | type: type,
10 | contentType: 'application/json; charset=UTF-8',
11 | xhrFields: {
12 | withCredentials: true
13 | },
14 | // crossDomain: true,
15 | success(rs) {
16 | //为登录
17 | if (rs.status == 2) {
18 | document.location = '/login';
19 | reject();
20 | } else {
21 | resolve(rs);
22 | }
23 | }
24 | });
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/server/models/scene.js:
--------------------------------------------------------------------------------
1 | let dbHandel = require('../db/handel.js')
2 | let collection = dbHandel.getModel('myh5')
3 |
4 | module.exports = {
5 | // 获取场景数量
6 | getSceneCount(data = {}) {
7 | return collection.countDocuments(data)
8 | },
9 |
10 | // 添加场景
11 | addScene(data) {
12 | return new collection(data).save()
13 | },
14 |
15 | // 获取场景列表
16 | getSceneList(data, { page, limit }) {
17 | return collection
18 | .find(data)
19 | .skip((page - 1) * limit)
20 | .limit(limit)
21 | .sort({ updateTime: -1 })
22 | },
23 |
24 | // 获取指定场景
25 | getSceneById(id) {
26 | return collection.findOne({ id: id })
27 | },
28 |
29 | // 更新指定场景
30 | updateSceneById(id, data) {
31 | return collection.update({ id: id }, data)
32 | },
33 |
34 | // 删除指定场景
35 | delSceneById(id) {
36 | return collection.update({ id: id }, { status: 3 })
37 | }
38 | }
--------------------------------------------------------------------------------
/server/qiniu/upload.js:
--------------------------------------------------------------------------------
1 | var qiniu = require("qiniu")
2 | const {
3 | AccessKey,
4 | SecretKey
5 | } = require('../../.key.js')
6 |
7 | module.exports.upload = function (bucket, localFile, key) {
8 | var mac = new qiniu.auth.digest.Mac(AccessKey, SecretKey);
9 | var options = {
10 | scope: bucket,
11 | };
12 | var putPolicy = new qiniu.rs.PutPolicy(options);
13 | var uploadToken = putPolicy.uploadToken(mac);
14 | var config = new qiniu.conf.Config();
15 | // 空间对应的机房
16 | config.zone = qiniu.zone.Zone_z2;
17 | let glob = require('glob')
18 | var formUploader = new qiniu.form_up.FormUploader(config);
19 | var putExtra = new qiniu.form_up.PutExtra();
20 | return new Promise((resolve) => {
21 | formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr,
22 | respBody, respInfo) {
23 | if (respErr) {
24 | throw respErr;
25 | }
26 | resolve(true)
27 | });
28 | })
29 | }
30 |
--------------------------------------------------------------------------------
/server/upload/down.js:
--------------------------------------------------------------------------------
1 | const dbHandel = require('../server/db/handel.js')
2 | let collection = dbHandel.getModel('shape')
3 | const fs = require('fs')
4 | const request = require('request')
5 | function downloadFile(uri, filename) {
6 | var stream = fs.createWriteStream(filename);
7 | return new Promise((resolve, reject) => {
8 | request(uri).pipe(stream).on('close', function () {
9 | // let timer = parseInt(Math.random() * 1000) + 500;
10 | // setTimeout(() => {
11 | resolve();
12 | // }, timer)
13 | });
14 | })
15 | }
16 |
17 |
18 | (async () => {
19 | let docs = await collection.find();
20 | // console.log(docs)
21 | for(let i = 0; i < docs.length; i++){
22 | let url = `http://p7d4z759a.bkt.clouddn.com/${docs[i].path}`;
23 |
24 | await downloadFile(url, '/Users/BraisedCakes/Desktop/2018/myh5-store/svg/' + docs[i].path)
25 | console.log('当前第' + i + '个');
26 | }
27 | })()
28 |
--------------------------------------------------------------------------------
/h5/src/main.js:
--------------------------------------------------------------------------------
1 | import 'minireset.css'
2 | import $ from 'jquery'
3 | import 'animate.css'
4 | import '@/css/index.scss'
5 | import * as utils from '../../utils/index'
6 | import * as api from '@/api/index'
7 | api.getSceneData({
8 | id: 20
9 | }).then((res) => {
10 | console.log(res);
11 | })
12 | new window.Swiper('.swiper-container', {
13 | direction: 'vertical',
14 | loop: true,
15 | on: {
16 | transitionStart() {
17 | $('.swiper-slide').eq(this.activeIndex).each((index, item) => {
18 | $(item).find('.items').each((index2, item2) => {
19 | $('.' + $(item2).attr('data-id')).css('animation', '');
20 | $('.' + $(item2).attr('data-id')).show();
21 | utils.runAni($(item2).attr('data-id'), JSON.parse($('.' + $(item2).attr('data-id')).attr('v-data')))
22 | })
23 | })
24 | },
25 | slideChangeTransitionEnd() {}
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/utils/index.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | /**
3 | * 小数点后保留几位
4 | * @param {*} num 数字
5 | * @param {*} n 小数点后保留几位
6 | */
7 | export const round = function (num, n = 2) {
8 | return Number(parseFloat(num).toFixed(n));
9 | }
10 | export const runAni = function (id, ani, aniIndex) {
11 | let str = '';
12 | let delay = 0;
13 | ani.forEach(($item, $index) => {
14 | let aniName = $item['animation-name'];
15 | let aniDuration = $item['animation-duration'];
16 | let aniDelay = $item['animation-delay'];
17 | if (typeof aniIndex == 'number' && aniIndex != $index) {
18 | return;
19 | } else if (typeof aniIndex != 'number' && $index > 0) {
20 | str += ','
21 | }
22 | str = str +
23 | `${aniName} ${aniDuration}s ${round(delay + round(aniDelay, 1), 1)}s 1 normal`;
24 | delay += round(parseFloat(aniDelay) + parseFloat(aniDuration), 1);
25 | });
26 |
27 | $('.' + id).css({
28 | 'animation': str
29 | })
30 | };
31 |
--------------------------------------------------------------------------------
/backstage/utils/index.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | /**
3 | * 小数点后保留几位
4 | * @param {*} num 数字
5 | * @param {*} n 小数点后保留几位
6 | */
7 | export const round = function (num, n = 2) {
8 | return Number(parseFloat(num).toFixed(n));
9 | }
10 | export const runAni = function (id, ani, aniIndex) {
11 | let str = '';
12 | let delay = 0;
13 | ani.forEach(($item, $index) => {
14 | let aniName = $item['animation-name'];
15 | let aniDuration = $item['animation-duration'];
16 | let aniDelay = $item['animation-delay'];
17 | if (typeof aniIndex == 'number' && aniIndex != $index) {
18 | return;
19 | } else if (typeof aniIndex != 'number' && $index > 0) {
20 | str += ','
21 | }
22 | str = str +
23 | `${aniName} ${aniDuration}s ${round(delay + round(aniDelay, 1), 1)}s 1 normal`;
24 | delay += round(parseFloat(aniDelay) + parseFloat(aniDuration), 1);
25 | });
26 |
27 | $('.' + id).css({
28 | 'animation': str
29 | })
30 | };
31 |
--------------------------------------------------------------------------------
/backstage/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | myh5-project
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/mutation-types.js:
--------------------------------------------------------------------------------
1 | /**
2 | * page页
3 | */
4 | export const ADD_PAGE = 'ADD_PAGE'; //添加
5 | export const DEL_PAGE = 'DEL_PAGE'; //删除
6 | export const SELECT_PAGE = 'SELECT_PAGE'; //选中
7 | export const SORT_PAGE = 'SORT_PAGE'; //排序
8 | /**
9 | * phone页面
10 | */
11 | export const SET_PHONE = 'SET_PHONE';
12 |
13 | export const ADD_ITEM = 'ADD_ITEM';
14 |
15 | export const UPDATE_PHONE = 'UPDATE_PHONE';
16 | export const UPDATE_MAIN = 'UPDATE_MAIN';
17 | export const UPDATE_ITEM = 'UPDATE_ITEM';
18 | export const CHANGE_DATA = 'CHANGE_DATA';
19 |
20 | /**
21 | *
22 | */
23 | export const SELECT_ITEM = 'SELECT_ITEM';
24 | export const DEL_ITEM = 'DEL_ITEM';
25 | export const ADD_CREATED_ID = 'ADD_CREATED_ID';
26 | /**
27 | * 打开or关闭面板
28 | */
29 | export const OPEN_PANEL = 'OPEN_PANEL';
30 | export const CLOSE_PANEL = 'CLOSE_PANEL';
31 | //记录
32 | export const RECORD = 'RECORD';
33 | //撤销
34 | export const REVOKE = 'REVOKE';
35 | //重做
36 | export const REDO = 'REDO';
37 | //更新otherInfo
38 | export const OTHERINFO = 'OTHERINFO';
39 |
--------------------------------------------------------------------------------
/backstage/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devServer: {
3 | proxy: {
4 | '/aj': {
5 | target: 'http://localhost:3000', // 你接口的域名
6 | secure: true,
7 | changeOrigin: true
8 | },
9 | '/store': {
10 | target: 'http://localhost:3000', // 你接口的域名
11 | secure: true,
12 | changeOrigin: true
13 | },
14 | // '/svg': {
15 | // target: 'http://p7d4z759a.bkt.clouddn.com', // 你接口的域名
16 | // secure: true,
17 | // changeOrigin: true
18 | // }
19 | }
20 | },
21 | configureWebpack: {
22 | module: {
23 | rules: [{
24 | test: /\.art$/,
25 | loader: "art-template-loader",
26 | options: {
27 | // art-template options (if necessary)
28 | // @see https://github.com/aui/art-template
29 | }
30 | }]
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/backstage/src/css/reset.css:
--------------------------------------------------------------------------------
1 | /*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */
2 |
3 | html,
4 | body,
5 | p,
6 | ol,
7 | ul,
8 | li,
9 | dl,
10 | dt,
11 | dd,
12 | blockquote,
13 | figure,
14 | fieldset,
15 | legend,
16 | textarea,
17 | pre,
18 | iframe,
19 | hr,
20 | h1,
21 | h2,
22 | h3,
23 | h4,
24 | h5,
25 | h6 {
26 | margin: 0;
27 | padding: 0;
28 | }
29 |
30 | /* h1,
31 | h2,
32 | h3,
33 | h4,
34 | h5,
35 | h6 {
36 | font-size: 100%;
37 | font-weight: normal;
38 | } */
39 |
40 | ul {
41 | list-style: none;
42 | }
43 |
44 | button,
45 | input,
46 | select,
47 | textarea {
48 | margin: 0;
49 | }
50 |
51 | html {
52 | box-sizing: border-box;
53 | }
54 |
55 | *,
56 | *:before,
57 | *:after {
58 | box-sizing: inherit;
59 | }
60 |
61 | img,
62 | embed,
63 | iframe,
64 | object,
65 | audio,
66 | video {
67 | height: auto;
68 | max-width: 100%;
69 | }
70 |
71 | iframe {
72 | border: 0;
73 | }
74 |
75 | table {
76 | border-collapse: collapse;
77 | border-spacing: 0;
78 | }
79 |
80 | td,
81 | th {
82 | padding: 0;
83 | text-align: left;
84 | }
85 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 刘少鹏
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/backstage/src/css/element-variables.scss:
--------------------------------------------------------------------------------
1 | /* 改变主题色变量 */
2 |
3 | // $--color-primary: #fd8527;
4 | /* 改变 icon 字体路径变量,必需 */
5 |
6 | $--font-path: '../../node_modules/element-ui/lib/theme-chalk/fonts';
7 | @import "../../node_modules/element-ui/packages/theme-chalk/src/index";
8 | .el-collapse-item__header {
9 | padding-left: 20px;
10 | background: #f6f9fa;
11 | line-height: 32px;
12 | height: 32px;
13 | }
14 |
15 | .el-collapse-item__arrow {
16 | line-height: 32px !important;
17 | }
18 |
19 | .el-select--mini {
20 | width: 130px;
21 | }
22 |
23 | .el-input--mini {
24 | width: 130px;
25 | }
26 |
27 | .el-radio-group {
28 | width: 130px;
29 | .el-radio+.el-radio {
30 | margin-left: 0;
31 | }
32 | .el-radio__label {
33 | font-size: 12px;
34 | }
35 | }
36 |
37 | .el-upload-dragger {
38 | width: 160px;
39 | height: 50px;
40 | border-style: none;
41 | background-color: inherit;
42 | }
43 |
44 | .el-notification {
45 | p {
46 | word-break: break-all;
47 | }
48 | }
49 |
50 | .my-el-dialog {
51 | .el-dialog__header,
52 | .el-dialog__body {
53 | padding: 0 !important;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/h5/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "h4",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "minireset.css": "^0.0.3",
12 | "vue": "^2.5.16"
13 | },
14 | "devDependencies": {
15 | "@vue/cli-plugin-babel": "^3.0.0-rc.5",
16 | "@vue/cli-plugin-eslint": "^3.0.0-rc.5",
17 | "@vue/cli-service": "^3.0.0-rc.5",
18 | "vue-template-compiler": "^2.5.16"
19 | },
20 | "eslintConfig": {
21 | "root": true,
22 | "env": {
23 | "node": true
24 | },
25 | "extends": [
26 | "plugin:vue/essential",
27 | "eslint:recommended"
28 | ],
29 | "rules": {
30 | "no-console": "off"
31 | },
32 | "parserOptions": {
33 | "parser": "babel-eslint"
34 | }
35 | },
36 | "postcss": {
37 | "plugins": {
38 | "autoprefixer": {}
39 | }
40 | },
41 | "browserslist": [
42 | "> 1%",
43 | "last 2 versions",
44 | "not ie <= 8"
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/backstage/src/img/show.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/upload/update_music.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const glob = require('glob')
3 | var request = require('request');
4 | var path = require('path')
5 |
6 | function downloadFile(uri, filename, callback) {
7 | var stream = fs.createWriteStream(filename);
8 | return new Promise((resolve, reject) => {
9 | request(uri).pipe(stream).on('close', function () {
10 | let timer = parseInt(Math.random() * 1000) + 500;
11 | setTimeout(() => {
12 | resolve();
13 | }, timer)
14 | });
15 | })
16 | }
17 |
18 |
19 | let fileList = glob.sync(`/Users/BraisedCakes/Desktop/2018/myh5-store/musics/*.json`);
20 | let allNum = 0;
21 | (async function () {
22 | for (let i = 0; i < fileList.length; i++) {
23 | let docs = JSON.parse(fs.readFileSync(fileList[i], 'utf-8'));
24 | for (let j = 0; j < docs.length; j++) {
25 | console.log(`${path.basename(fileList[i])}类型共需下载${docs.length}张, 已下载${j}张`)
26 | if (!docs[j].path) {
27 | console.log('path不存在')
28 | continue;
29 | }
30 | if (glob.sync(`/Users/BraisedCakes/Desktop/2018/myh5-store/music/${path.basename(docs[j].path)}`).length != 0) {
31 | continue;
32 | }
33 | let fileUrl = `http://res1.eqh5.com/${docs[j].path}`;
34 | let filename = `/Users/BraisedCakes/Desktop/2018/myh5-store/music/${path.basename(docs[j].path)}`;
35 | await downloadFile(fileUrl, filename)
36 | }
37 | }
38 | })()
39 |
--------------------------------------------------------------------------------
/backstage/src/img/music_btn.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/h5/src/css/index.scss:
--------------------------------------------------------------------------------
1 | .loading {
2 | background: #48424f;
3 | width: 100%;
4 | height: 100%;
5 | position: absolute;
6 | z-index: 9999;
7 | top: 0;
8 | }
9 |
10 | .loadbox {
11 | position: relative;
12 | height: 70px;
13 | margin: 0 auto;
14 | margin-top: 50%;
15 | }
16 |
17 | .loadbg,
18 | .loadbox {
19 | display: block;
20 | width: 70px;
21 | }
22 |
23 | .loadbg {
24 | position: absolute;
25 | z-index: 1000;
26 | height: 42px;
27 | background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgMjQwIj48cmVjdCBmaWxsPSIjMDhhMWVmIiB4PSI0IiB5PSI0IiB3aWR0aD0iMzkyIiBoZWlnaHQ9IjIzMiIvPjxjaXJjbGUgaWQ9ImFjdG9yXzMiIGN4PSIwIiBjeT0iMCIgcj0iMzAiIGZpbGw9IiM5QUQ2NEIiPjxhbmltYXRlTW90aW9uIHBhdGg9Ik0zOSwxMjBMNzgsNTBIMTYxTDIzOSwxOTBIMzIyTDM2MSwxMjBMMzIyLDUwSDIzOUwxNjEsMTkwSDc4TDM5LDEyMCIgZHVyPSIxcyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz48L2NpcmNsZT48cGF0aCBkPSJNMCwyNDBWMGg0MDB2MjQwSDB6IE0zMzAuNzY5LDM0aC05OC40NjJsLTgxLjUzOCwxNDEuMzQ1SDg2LjE1NEw1My44NDYsMTE5LjVsMzIuMzA4LTU1Ljg0NWg2NC42MTVsMjMuODQ2LDQwLjgyNGwxNi45MjMtMjkuMjdMMTY3LjY5MiwzNEg2OS4yMzFMMjAsMTE5LjVMNjkuMjMxLDIwNWg5OC40NjFsODEuNTM4LTE0MS4zNDVoNjQuNjE1bDMyLjMwOCw1NS44NDVsLTMyLjMwOCw1NS44NDVoLTY0LjYxNWwtMjMuODQ2LTQwLjgyNGwtMTYuOTIzLDI5LjI3TDIzMi4zMDgsMjA1aDk4LjQ2MkwzODAsMTE5LjVMMzMwLjc2OSwzNHoiIGZpbGw9IiM0ODQyNEYiLz48L3N2Zz4=)
28 | }
29 |
30 | .loading-tip {
31 | display: none;
32 | position: absolute;
33 | bottom: 40px;
34 | font-size: 16px;
35 | z-index: 9999;
36 | width: 200px;
37 | left: 50%;
38 | margin-left: -100px;
39 | text-align: center;
40 | color: #7986cb;
41 | }
42 |
--------------------------------------------------------------------------------
/server/qiniu/move.js:
--------------------------------------------------------------------------------
1 | var qiniu = require("qiniu")
2 | const {
3 | AccessKey,
4 | SecretKey
5 | } = require('../../.key.js')
6 | const dbHandel = require('../db/handel.js')
7 |
8 | var mac = new qiniu.auth.digest.Mac(AccessKey, SecretKey);
9 | var config = new qiniu.conf.Config();
10 | var bucketManager = new qiniu.rs.BucketManager(mac, config);
11 | // var srcBucket = 'public';
12 | // var destBucket = 'store';
13 | //每个operations的数量不可以超过1000个,如果总数量超过1000,需要分批发送
14 | var moveOperations = [
15 | // qiniu.rs.moveOp(srcBucket, '00105d08-3252-47cf-b5c5-7f48f430a46c.svg', destBucket, '00105d08-3252-47cf-b5c5-7f48f430a46c.svg')
16 | ];
17 |
18 | (async () => {
19 | const collection = dbHandel.getModel('musics');
20 | let obj = await collection.find().skip(12000).limit(1000);
21 | obj.forEach((item) => {
22 | moveOperations.push(
23 | qiniu.rs.moveOp('music', item.path, 'store', item.path)
24 | )
25 | })
26 | console.log(moveOperations)
27 | bucketManager.batch(moveOperations, function (err, respBody, respInfo) {
28 | if (err) {
29 | console.log(err);
30 | //throw err;
31 | } else {
32 | // 200 is success, 298 is part success
33 | if (parseInt(respInfo.statusCode / 100) == 2) {
34 | respBody.forEach(function (item) {
35 | if (item.code == 200) {
36 | console.log(item.code + "\tsuccess");
37 | } else {
38 | console.log(item.code + "\t" + item.data.error);
39 | }
40 | });
41 | } else {
42 | console.log(respInfo.deleteusCode);
43 | console.log(respBody);
44 | }
45 | }
46 | });
47 |
48 | })()
49 |
--------------------------------------------------------------------------------
/backstage/src/keycode/index.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | import store from '@/store/index.js'
3 |
4 | const keyCode = {
5 | up: 38,
6 | down: 40,
7 | left: 37,
8 | right: 39,
9 | delete: 8
10 | }
11 |
12 | $(window).keydown(function (ev) {
13 | if (document.activeElement != document.querySelector('body')) {
14 | return;
15 | }
16 | /**
17 | * up 38
18 | * down 40
19 | * left 37
20 | * right 39
21 | */
22 | if (!store.getters.hasSelectedItems) {
23 | return;
24 | }
25 | switch (ev.keyCode) {
26 | case keyCode.up:
27 | store.dispatch('updateItem', {
28 | key: 'style',
29 | val: {
30 | 'top': parseInt(store.getters.curItem.style.top) - 1 + 'px'
31 | }
32 | });
33 | break;
34 | case keyCode.down:
35 | store.dispatch('updateItem', {
36 | key: 'style',
37 | val: {
38 | 'top': parseInt(store.getters.curItem.style.top) + 1 + 'px'
39 | }
40 | });
41 | break;
42 | case keyCode.left:
43 | store.dispatch('updateItem', {
44 | key: 'style',
45 | val: {
46 | 'left': parseInt(store.getters.curItem.style.left) - 1 + 'px'
47 | }
48 | });
49 | break;
50 | case keyCode.right:
51 | store.dispatch('updateItem', {
52 | key: 'style',
53 | val: {
54 | 'left': parseInt(store.getters.curItem.style.left) + 1 + 'px'
55 | }
56 | });
57 | break;
58 | case keyCode.delete:
59 | store.dispatch('delItem')
60 | break;
61 | }
62 | });
63 |
--------------------------------------------------------------------------------
/backstage/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Cookies from 'js-cookie'
4 | import store from '@/store/index.js'
5 |
6 | Vue.use(Router);
7 |
8 | let routes = new Router({
9 | linkActiveClass: 'active',
10 | mode: 'history',
11 | routes: [{
12 | path: '/list',
13 | name: 'list',
14 | meta: {
15 | requiresAuth: true
16 | },
17 | component: () =>
18 | import ( /* webpackChunkName: "list" */ '@/page/list/list.vue')
19 | }, {
20 | path: '/edit/:id',
21 | name: 'edit',
22 | meta: {
23 | requiresAuth: true
24 | },
25 | component: () =>
26 | import ( /* webpackChunkName: "edit" */ '@/page/edit/edit.vue')
27 | }, {
28 | path: '/detail/:id',
29 | name: 'detail',
30 | meta: {
31 | requiresAuth: true
32 | },
33 | component: () =>
34 | import ( /* webpackChunkName: "detail" */ '@/page/detail/detail.vue')
35 | }, {
36 | path: '/login',
37 | name: 'login',
38 | component: () =>
39 | import ( /* webpackChunkName: "login" */ '@/page/login/login.vue')
40 | }]
41 | });
42 |
43 | routes.beforeEach((to, from, next) => {
44 | let token = Cookies('username');
45 | if (!to.name) {
46 | next({
47 | name: 'list'
48 | });
49 | } else if (to.name == 'login') {
50 | if (!token || !store.state.auth.username) {
51 | next();
52 | } else {
53 | next({
54 | name: 'list'
55 | });
56 | }
57 | } else if (to.params.status == 2 || (to.matched.some(record => record.meta.requiresAuth) && (!token || token === null))) {
58 | next({
59 | path: '/login'
60 | });
61 | } else {
62 | next();
63 | }
64 | });
65 |
66 | export default routes
67 |
--------------------------------------------------------------------------------
/backstage/src/components/dialog/dialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
38 |
45 |
46 |
80 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/event.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 无
7 | 链接
8 | 电话
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
45 |
46 |
61 |
--------------------------------------------------------------------------------
/documents/changelog.md:
--------------------------------------------------------------------------------
1 |
2 | # Changelog
3 |
4 | ## 0.3.0 / 2018-07-05
5 | - 新增 `背景` 组件
6 |
7 | ## 0.2.9 / 2018-06-26
8 |
9 | - 新增 `场景图` 上传功能
10 |
11 | ## 0.2.8 / 2018-06-12
12 |
13 | - 新增 `图片` 裁切功能
14 |
15 | ## 0.2.7 / 2018-05-31
16 |
17 | - 新增 `编辑页` 预览功能
18 |
19 | ## 0.2.6 / 2018-05-20
20 | - 新增 `列表页` 增加回收站
21 |
22 | ## 0.2.5 / 2018-05-19
23 | - 新增 `列表页` 支持复制场景
24 |
25 | ## 0.2.4 / 2018-05-18
26 | - 新增 `列表页` 创建场景需先填表
27 |
28 | ## 0.2.3 / 2018-05-08
29 | - 新增 登录功能
30 |
31 | ## 0.2.2 / 2018-05-07
32 | - 修复 `Tooltip` 超长字母没有换行问题
33 | - 新增 `元素` 支持多选操作
34 |
35 | ## 0.2.1 / 2018-05-06
36 | - 新增 `音乐库` 支持用户上传音乐
37 |
38 | ## 0.2.0 / 2018-05-04
39 | - 新增 `图片库` 的所有图片托管到七牛云
40 | - 新增 `图片库` 支持用户上传图片
41 |
42 | ## 0.1.10 / 2018-04-23
43 | - 新增 `二维码` 组件
44 | - 新增 对`元素`的撤销和重做操作
45 |
46 | ## 0.1.9 / 2018-04-21
47 | - 新增 `图片库`支持记录最近使用过的`图片`
48 |
49 | ## 0.1.8 / 2018-04-20
50 | - 新增 `图片` 组件
51 | - 修复 `音乐库` 无法取消选中的问题
52 |
53 | ## 0.1.7 / 2018-04-19
54 | - 新增 `形状库`支持记录最近使用过的`形状`
55 |
56 | ## 0.1.6 / 2018-04-17
57 | - 新增 `形状库` 新增多种官方类型
58 |
59 | ## 0.1.5 / 2018-04-16
60 | - 新增 点击事件
61 |
62 | ## 0.1.4 / 2018-04-12
63 | - 新增 `音乐` 组件
64 |
65 | ## 0.1.3 / 2018-04-09
66 | - 新增 `形状` 组件
67 |
68 | ## 0.1.2 / 2018-04-05
69 | - 新增 重新播放动画效果的按钮
70 | - 修复 被复制的页面动画失效的问题
71 |
72 | ## 0.1.1 / 2018-04-03
73 | - 新增 `元素`以唯一id进行区分
74 |
75 | ## 0.1.0 / 2018-04-1
76 | - 新增 动画效果
77 |
78 | ## 0.0.11 / 2018-03-28
79 | - 新增 `元素`可调整层级关系,置顶,上移一层,下移一层,置底
80 |
81 | ## 0.0.10 / 2018-03-27
82 | - 新增 `编辑页` 可删除元素
83 |
84 | ## 0.0.9 / 2018-03-26
85 | - 新增 ⬆️⬇️⬅️➡️调整元素位置
86 |
87 | ## 0.0.8 / 2018-03-23
88 | - 新增 `编辑页` 复制页面的功能
89 |
90 | ## 0.0.7 / 2018-03-22
91 | - 新增 `编辑页` 对背景颜色进行编辑
92 |
93 | ## 0.0.6 / 2018-03-21
94 | - 新增 保存功能
95 |
96 | ## 0.0.5 / 2018-03-20
97 | - 新增 `元素`缩放功能
98 |
99 | ## 0.0.4 / 2018-03-19
100 | - 新增 对`文字`的内容,以及字号,行高,位置,大小,透明度等进行编辑的功能
101 |
102 | ## 0.0.3 / 2018-03-17
103 | - 新增 `编辑页` 的 `页码区域` 支持拖拽排序
104 | - 新增 `编辑页` 增加右侧操作栏
105 |
106 | ## 0.0.2 / 2018-03-15
107 | - 新增 `列表页` 和 `编辑页` 的布局搭建完成
108 |
109 | ## 0.0.1 / 2018-03-08
110 | - 立项
111 |
--------------------------------------------------------------------------------
/backstage/src/page/list/list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 创建场景
8 | 我的场景
9 | 回收站
10 |
11 |
12 |
13 |
14 |
15 |
16 |
47 |
48 |
76 |
--------------------------------------------------------------------------------
/backstage/src/page/list/header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
登出
13 |
14 |
15 |
16 |
28 |
29 |
79 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
51 |
--------------------------------------------------------------------------------
/server/api/login.js:
--------------------------------------------------------------------------------
1 | let uuid = require('uuid/v1')
2 | let router = require('../app.js')
3 | let userModel = require('../models/login')
4 | let { AJ_STATUS, AJ_MESSAGE } = require('../const/index')
5 | let types = require('./types')
6 |
7 | // 用户注册
8 | router.post(types.userRegister, async (req, res) => {
9 | let user = req.body.username
10 | let pass = req.body.password
11 | try {
12 | let data = await userModel.getUser(req.body.username)
13 | if (!data) {
14 | await userModel.login({ user: user, pass: pass, uid: uuid() })
15 | res.send({ status: AJ_STATUS.success, message: '注册成功' })
16 | } else {
17 | throw new Error('用户已经存在')
18 | }
19 | } catch (e) {
20 | res.send({ status: AJ_STATUS.error, message: e.message })
21 | }
22 | })
23 |
24 | // 用户登陆
25 | router.post(types.userLogin, async (req, res) => {
26 | let user = req.body.username;
27 | let pass = req.body.password;
28 | try {
29 | let data = await userModel.goLogin(user, pass)
30 | if (!data) {
31 | throw new Error('用户名或密码不正确')
32 | } else {
33 | req.session.isLogin = true
34 | req.session.username = req.body.username
35 | req.session.uid = data.uid
36 | res.cookie('username', req.body.username, {
37 | expires: new Date(Date.now() + 10000 * 60 * 60 * 24 * 7)
38 | })
39 | res.send({ status: AJ_STATUS.success, message: '登录成功' })
40 | }
41 | } catch (e) {
42 | res.send({ status: AJ_STATUS.error, message: e.message })
43 | }
44 | })
45 |
46 | // 注销
47 | router.post(types.userLogout, (req, res) => {
48 | req.session.isLogin = null
49 | req.session.uid = null
50 | req.session.username = null
51 | res.clearCookie('username')
52 | res.send({ status: AJ_STATUS.success, message: '注销成功' })
53 | })
54 |
55 | // 获取用户信息
56 | router.get(types.getUserInfo, async (req, res) => {
57 | try {
58 | if (req.session.isLogin) {
59 | let data = await userModel.getUser(req.session.uid)
60 | res.send({ status: AJ_STATUS.success, message: '获取成功', result: data })
61 | } else {
62 | throw new Error('没有拿到用户信息')
63 | }
64 | } catch (e) {
65 | res.send({ status: AJ_STATUS.error, message: e.message })
66 | }
67 | })
--------------------------------------------------------------------------------
/backstage/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | import store from '@/store/index'
3 |
4 | /**
5 | * 小数点后保留几位
6 | * @param {*} num 数字
7 | * @param {*} n 小数点后保留几位
8 | */
9 | export const round = function (num, n = 2) {
10 | return Number(parseFloat(num).toFixed(n));
11 | }
12 | /**
13 | * 执行当前页动画
14 | */
15 | export const runCurPhoneAni = function (delay) {
16 | store.getters.currentPhone.data.forEach((item) => {
17 | if (delay) {
18 | runAni(item.id, item.animation);
19 | } else {
20 | runAni(item.id, item.animation, null, 1);
21 | }
22 |
23 | });
24 | }
25 | /**
26 | * 执行动画
27 | * @param {*} id 元素id
28 | * @param {*} ani 元素animation列表
29 | * @param {*} aniIndex 取animation中第几个?
30 | * @param {*} time 是否存在setTimeout
31 | */
32 | export const runAni = function (id, ani, aniIndex, time) {
33 | let str = '';
34 | let delay = 0;
35 | ani.forEach(($item, $index) => {
36 | let aniName = $item['animation-name'];
37 | let aniDuration = $item['animation-duration'];
38 | let aniDelay = $item['animation-delay'];
39 | if (typeof aniIndex == 'number' && aniIndex != $index) {
40 | return;
41 | } else if (typeof aniIndex != 'number' && $index > 0) {
42 | str += ','
43 | }
44 | str = str +
45 | `${aniName} ${aniDuration}s ${round(delay + round(aniDelay, 1), 1)}s 1 normal`;
46 | delay += round(parseFloat(aniDelay) + parseFloat(aniDuration), 1);
47 | });
48 | if (time) {
49 | $('#' + id + ' .item-body').css({
50 | 'animation': str
51 | })
52 | } else {
53 | $('#' + id + ' .item-body').css({
54 | 'animation': '',
55 | 'animation-play-state': 'paused'
56 | });
57 | setTimeout(() => {
58 | $('#' + id + ' .item-body').css({
59 | 'animation': str
60 | });
61 | }, 30);
62 | }
63 | };
64 |
65 |
66 | export const openMask = function () {
67 | if (!$('.mask').length) {
68 | $('body').append('');
69 | }
70 | }
71 | export const removeMask = function () {
72 | $('.my-mask').remove();
73 | }
74 |
--------------------------------------------------------------------------------
/backstage/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import 'animate.css'
3 | import {
4 | Pagination,
5 | Scrollbar,
6 | Form,
7 | Tooltip,
8 | Loading,
9 | Button,
10 | ColorPicker,
11 | Collapse,
12 | CollapseItem,
13 | InputNumber,
14 | Input,
15 | Select,
16 | Option,
17 | Radio,
18 | RadioGroup,
19 | OptionGroup,
20 | MessageBox,
21 | Notification,
22 | Upload,
23 | FormItem,
24 | Message,
25 | Dialog,
26 | Checkbox
27 | } from 'element-ui';
28 | import App from '@/App'
29 | import router from '@/router'
30 | import Crop from '@/components/crop'
31 | import Image from '@/components/image'
32 | import Shape from '@/components/shape'
33 | import Music from '@/components/music'
34 | import store from '@/store'
35 | import '@/css/reset.css'
36 | import '@/css/index.css'
37 | import '@/css/index.scss'
38 | import '@/css/element-variables.scss'
39 | import '@/iconfont/iconfont.css'
40 | import '@/directive/select'
41 | import '@/directive/drag'
42 | import "@/directive/changesize";
43 | import '@/keycode/index'
44 |
45 | Vue.config.productionTip = process.env.NODE_ENV !== 'production';
46 | Vue.prototype.$ELEMENT = {
47 | size: 'mini',
48 | // zIndex: 3000
49 | };
50 | Vue.use(Pagination);
51 | Vue.use(Scrollbar);
52 | Vue.use(Form);
53 | Vue.use(Tooltip);
54 | Vue.use(Button);
55 | Vue.use(ColorPicker);
56 | Vue.use(Collapse);
57 | Vue.use(CollapseItem);
58 | Vue.use(InputNumber);
59 | Vue.use(Input);
60 | Vue.use(Select);
61 | Vue.use(Radio);
62 | Vue.use(RadioGroup);
63 | Vue.use(Option);
64 | Vue.use(OptionGroup);
65 | Vue.use(Upload);
66 | Vue.use(FormItem);
67 | Vue.use(Dialog);
68 | Vue.use(Checkbox);
69 | Vue.use(Loading.directive);
70 | Vue.prototype.$loading = Loading.service;
71 | Vue.prototype.$msgbox = MessageBox;
72 | Vue.prototype.$alert = MessageBox.alert;
73 | Vue.prototype.$confirm = MessageBox.confirm;
74 | Vue.prototype.$prompt = MessageBox.prompt;
75 | Vue.prototype.$notify = Notification;
76 | Vue.prototype.$message = Message;
77 | Vue.use(Crop);
78 | Vue.use(Image);
79 | Vue.use(Shape);
80 | Vue.use(Music);
81 | export default new Vue({
82 | router: router,
83 | store: store,
84 | render: h => h(App)
85 | }).$mount('#app')
--------------------------------------------------------------------------------
/server/upload/b.js:
--------------------------------------------------------------------------------
1 | const dbHandel = require('../db/handel.js')
2 | const glob = require('glob')
3 | const fs = require('fs')
4 | const path = require('path')
5 | let docs1 = glob.sync(`/Users/BraisedCakes/Desktop/2018/myh5-store/svg-json/*`);
6 | let id = 400000000;
7 | let shape2 = dbHandel.getModel('shape')
8 | let desc = dbHandel.getModel('desc')
9 |
10 | // shape2.find({}, (err, docs) => {
11 | // for (let i = 0; i < docs.length; i++) {
12 | // if (docs[i].tagId.indexOf(',') != -1) {
13 | // console.log(docs[i].tagId)
14 | // }
15 | // }
16 | // })
17 |
18 | ;
19 | (async () => {
20 | let descDocs = await desc.findOne({});
21 | for (let i = 0; i < docs1.length; i++) {
22 | let docs2 = glob.sync(`${docs1[i]}/*.json`);
23 | for (let j = 0; j < docs2.length; j++) {
24 | let data = JSON.parse(fs.readFileSync(docs2[j], 'utf-8'));
25 | //data 当前文件的json数据
26 | for (let z = 0; z < data.length; z++) {
27 | let shapePath = path.basename(data[z].path)
28 |
29 | let itemData = await shape2.findOne({
30 | path: shapePath
31 | })
32 | if (!itemData) {
33 | await new shape2({
34 | path: shapePath,
35 | id: id++,
36 | name: data[z].name,
37 | typeId: String(descDocs.shape.type[i].typeId),
38 | tagId: String(descDocs.shape.type[i].children[j].tagId)
39 | }).save();
40 | } else {
41 | let typeId = itemData.typeId.split(',');
42 | let tagId = itemData.tagId.split(',');
43 | if (typeId.indexOf(String(descDocs.shape.type[i].typeId)) == -1) {
44 | typeId.push(String(descDocs.shape.type[i].typeId));
45 | }
46 | if (tagId.indexOf(String(descDocs.shape.type[i].children[j].tagId)) == -1) {
47 | tagId.push(String(descDocs.shape.type[i].children[j].tagId));
48 | console.log(tagId)
49 | console.log(shapePath)
50 | console.log(typeId.join(','))
51 | }
52 |
53 | await shape2.update({
54 | path: shapePath
55 | }, {
56 | tagId: tagId.join(','),
57 | typeId: typeId.join(',')
58 | })
59 | }
60 | // console.log(`${id}`)
61 | }
62 | }
63 | }
64 | console.log('done')
65 | })();
66 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/getters.js:
--------------------------------------------------------------------------------
1 | const getters = {
2 |
3 | /**
4 | * 总页码
5 | * @return {Number}
6 | */
7 |
8 | pageLength: state => state.phone.data.length,
9 |
10 | /**
11 | * 当前页码, 从0开始
12 | * @return {Number}
13 | */
14 |
15 | currentPage: state => state.currentPage,
16 |
17 | /**
18 | * phone数据
19 | * @return {Object}
20 | */
21 |
22 | phoneData: state => state.phone,
23 |
24 | /**
25 | * 当前页数据
26 | * @return {Object}
27 | */
28 |
29 | currentPhone: (state, getters) => state.phone.data[getters.currentPage],
30 |
31 | /**
32 | * 当前页元素个数
33 | * @return {Object}
34 | */
35 |
36 | curPageItemLen: state => state.phone.data[state.currentPage].data.length,
37 |
38 | /**
39 | * 当前被选中元素
40 | * @return {Object}
41 | */
42 |
43 | curItem: (state, getters) => getters.currentPhone.data[state.curItemId] || false,
44 |
45 | /**
46 | * 是否有被选中元素
47 | * @return {Boolean}
48 | */
49 |
50 | hasSelectedItems: state => (state.curItemId >= 0 || state.curItemIds.length > 0) ? true : false,
51 |
52 | /**
53 | * 是否是单选
54 | * @return {Boolean}
55 | */
56 |
57 | hasSelectedOneItem: state => state.curItemId >= 0 ? true : false,
58 |
59 | /**
60 | * 是否是多选
61 | * @return {Boolean}
62 | */
63 |
64 | hasSelectedMultiItems: state => state.curItemIds.length > 0 ? true : false,
65 |
66 | /**
67 | * 被选中元素的id(以数组形式返回,即使是单选)
68 | * @return {Array}
69 | */
70 |
71 | selectedItemsForArray: state => state.curItemId >= 0 ? [state.curItemId] : state.curItemIds,
72 |
73 | /**
74 | * 被选中元素的id
75 | * @return {Number}
76 | */
77 |
78 | curItemId: state => state.curItemId,
79 |
80 | /**
81 | * 被选中元素的id集合
82 | * @return {Array}
83 | */
84 |
85 | curItemIds: state => state.curItemIds,
86 |
87 | /**
88 | * 当前页的cache数据
89 | * @return {Object}
90 | */
91 |
92 | curCache: state => state.cacheData[state.currentPage],
93 |
94 | /**
95 | * 其他信息
96 | * @return {Object}
97 | */
98 |
99 | otherInfo: state => state.otherInfo,
100 | };
101 |
102 | export default getters;
103 |
--------------------------------------------------------------------------------
/server/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('myh5-b:server');
9 | var http = require('http');
10 | const db = require('../db/index.js')
11 | require('../api')
12 | /**
13 | * Get port from environment and store in Express.
14 | */
15 |
16 | var port = normalizePort(process.env.PORT || '3000');
17 | app.set('port', port);
18 |
19 | /**
20 | * Create HTTP server.
21 | */
22 |
23 | var server = http.createServer(app);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 |
30 | db.on('error', console.error.bind(console, '连接数据库失败'))
31 | db.once('open', function () {
32 | // console.log('连接数据库成功')
33 | // let myh5 = dbHandel.getModel('myh5');
34 | // myh5.find({}, (err, docs) => {
35 | // console.log(docs)
36 | // });
37 | server.listen(port);
38 | server.on('error', onError);
39 | server.on('listening', onListening);
40 | });
41 |
42 |
43 | /**
44 | * Normalize a port into a number, string, or false.
45 | */
46 |
47 | function normalizePort(val) {
48 | var port = parseInt(val, 10);
49 |
50 | if (isNaN(port)) {
51 | // named pipe
52 | return val;
53 | }
54 |
55 | if (port >= 0) {
56 | // port number
57 | return port;
58 | }
59 |
60 | return false;
61 | }
62 |
63 | /**
64 | * Event listener for HTTP server "error" event.
65 | */
66 |
67 | function onError(error) {
68 | if (error.syscall !== 'listen') {
69 | throw error;
70 | }
71 |
72 | var bind = typeof port === 'string' ?
73 | 'Pipe ' + port :
74 | 'Port ' + port;
75 |
76 | // handle specific listen errors with friendly messages
77 | switch (error.code) {
78 | case 'EACCES':
79 | console.error(bind + ' requires elevated privileges');
80 | process.exit(1);
81 | break;
82 | case 'EADDRINUSE':
83 | console.error(bind + ' is already in use');
84 | process.exit(1);
85 | break;
86 | default:
87 | throw error;
88 | }
89 | }
90 |
91 | /**
92 | * Event listener for HTTP server "listening" event.
93 | */
94 |
95 | function onListening() {
96 | var addr = server.address();
97 | var bind = typeof addr === 'string' ?
98 | 'pipe ' + addr :
99 | 'port ' + addr.port;
100 | debug('Listening on ' + bind);
101 | }
102 |
--------------------------------------------------------------------------------
/server/upload/index.js:
--------------------------------------------------------------------------------
1 | // // var qiniu = require("qiniu")
2 | // const dbHandel = require('../db/handel.js')
3 |
4 | // // ;
5 | // // (async (res) => {
6 | // // let collection = dbHandel.getModel('shape')
7 | // // let docs = await collection.find({
8 | // // path : '8fbd0751-b8d3-4cc3-8798-a68673437654.svg'
9 | // // })
10 | // // console.log(docs)
11 | // // })();
12 |
13 |
14 |
15 | // const glob
16 |
17 |
18 | const {
19 | AccessKey,
20 | SecretKey
21 | } = require('../../.key.js')
22 | var mac = new qiniu.auth.digest.Mac(AccessKey, SecretKey);
23 |
24 | var options = {
25 | scope: 'store',
26 | };
27 | var putPolicy = new qiniu.rs.PutPolicy(options);
28 | var uploadToken = putPolicy.uploadToken(mac);
29 |
30 |
31 | var config = new qiniu.conf.Config();
32 | // 空间对应的机房
33 | config.zone = qiniu.zone.Zone_z2;
34 |
35 | let glob = require('glob')
36 | // let b = glob.sync(`/Users/BraisedCakes/Desktop/2018/myh5-store/svg/*.svg`)
37 | // console.log(b.length)
38 | // return;
39 | var formUploader = new qiniu.form_up.FormUploader(config);
40 | var putExtra = new qiniu.form_up.PutExtra();
41 |
42 |
43 |
44 | var localFile = "/Users/BraisedCakes/Desktop/2018/myh5-store/svg/yq0KZVbqS6mAaReOAABLqGlUGoM448.svg";
45 | var key = 'yq0KX1bg6PCAalnlAAAK3WnoBek138.svg';
46 | // 文件上传
47 |
48 | function upload(localFile, key) {
49 | return new Promise((resolve) => {
50 | formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr,
51 | respBody, respInfo) {
52 | if (respErr) {
53 | throw respErr;
54 | }
55 | if (respInfo.statusCode == 200) {
56 | console.log(respBody);
57 | } else {
58 | console.log(respInfo.statusCode);
59 | console.log(respBody);
60 | }
61 | resolve(true)
62 | });
63 | })
64 | }
65 |
66 | (async (req, res) => {
67 | let collection = dbHandel.getModel('shape')
68 | let data = await collection.find({})
69 | let count = await collection.count({})
70 | for (let i = 0; i < data.length; i++) {
71 | console.log(`共${count}个, 已经处理${i}个`);
72 | let one = await collection.findOne({
73 | path: data[i].path,
74 | space: 'qiniu'
75 | })
76 | if (one) {
77 | continue;
78 | }
79 | let localFile = `/Users/BraisedCakes/Desktop/2018/myh5-store/svg/${data[i].path}`;
80 | let key = data[i].path;
81 | await upload(localFile, key)
82 | await collection.update({
83 | path: key
84 | }, {
85 | space: 'qiniu'
86 | })
87 | }
88 | })()
89 |
--------------------------------------------------------------------------------
/backstage/src/page/list/feed.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 | 暂无场景
18 | 创建场景
19 |
20 |
21 |
22 |
23 |
68 |
69 |
93 |
--------------------------------------------------------------------------------
/backstage/src/directive/drag.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import $ from 'jquery'
3 | import store from '@/store/index.js'
4 |
5 | Vue.directive('my-drag', {
6 | bind: function (el) {
7 | $(el).on('mousedown', function (ev) {
8 | if ($(ev.target).hasClass('circle')) {
9 | return;
10 | }
11 | let isMove = false;
12 | let old = [];
13 | let pos = [];
14 | for (let i = 0; i < store.getters.selectedItemsForArray.length; i++) {
15 | let item = store.getters.selectedItemsForArray[i];
16 | old.push({
17 |
18 | x: parseInt($('#' + store.getters.currentPhone.data[item].id).css('left')),
19 | y: parseInt($('#' + store.getters.currentPhone.data[item].id).css('top'))
20 | })
21 | pos.push({
22 | x: 0,
23 | y: 0
24 | })
25 | }
26 | let downLeft = ev.clientX;
27 | let downTop = ev.clientY;
28 | $(document).on('mousemove', function (ev) {
29 | isMove = true;
30 | for (let i = 0; i < store.getters.selectedItemsForArray.length; i++) {
31 | let item = store.getters.selectedItemsForArray[i];
32 | pos[i].x = ev.clientX - downLeft + old[i].x;
33 | pos[i].y = ev.clientY - downTop + old[i].y;
34 | $('.phone-area .phone-item').eq(item).css({
35 | 'left': pos[i].x + 'px',
36 | 'top': pos[i].y + 'px'
37 | })
38 | }
39 | return false;
40 | });
41 | $(document).on('mouseup', function () {
42 | $(document).off('mousemove');
43 | $(document).off('mouseup');
44 | if (isMove) {
45 | for (let i = 0; i < store.getters.selectedItemsForArray.length; i++) {
46 | let item = store.getters.selectedItemsForArray[i];
47 | store.dispatch('updateItem', {
48 | key: 'style',
49 | item: store.getters.currentPhone.data[item],
50 | val: {
51 | left: pos[i].x + 'px',
52 | top: pos[i].y + 'px'
53 | }
54 | });
55 | }
56 | }
57 | })
58 | })
59 | }
60 | })
61 |
--------------------------------------------------------------------------------
/backstage/src/page/list/create.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 取消
13 | 确定
14 |
15 |
16 |
17 |
18 |
73 |
74 |
76 |
--------------------------------------------------------------------------------
/h5/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | web
9 |
40 |
41 |
42 |
43 |
44 |
45 |
52 |
62 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/backstage/src/api/index.js:
--------------------------------------------------------------------------------
1 | import fetch from './fetch'
2 |
3 | /**
4 | * 获取场景列表
5 | */
6 |
7 | export const getSceneList = data => fetch('/aj/scene/list', data);
8 |
9 | /**
10 | * 创建场景
11 | */
12 |
13 | export const addScene = data => fetch('/aj/scene/add', data, 'POST');
14 |
15 | /**
16 | * 删除场景
17 | */
18 |
19 | export const delScene = data => fetch('/aj/scene/del', data);
20 |
21 | /**
22 | * 发布场景
23 | */
24 |
25 | export const publishScene = data => fetch('/aj/scene/publish', data, 'POST');
26 |
27 | /**
28 | * 更新场景
29 | */
30 |
31 | export const updateScene = data => fetch('/aj/scene/update', data, 'POST');
32 |
33 | /**
34 | * 获取指定场景
35 | */
36 |
37 | export const getScene = data => fetch('/aj/scene/get', data);
38 |
39 | /**
40 | * 保存场景
41 | */
42 |
43 | export const saveScene = data => fetch('/aj/scene/save', data, 'POST');
44 |
45 | /**
46 | * 获取形状nav
47 | */
48 |
49 | export const getShapeNav = () => fetch('/aj/shape/nav');
50 |
51 | /**
52 | * 获取形状list
53 | */
54 |
55 | export const getShape = data => fetch('/aj/shape/get', data);
56 |
57 | /**
58 | * 获取指定形状的content
59 | */
60 | export const getShapeContent = data => fetch('/aj/shape/getContent', data);
61 |
62 | /**
63 | * 获取音乐nav
64 | */
65 |
66 | export const getMusicNav = () => fetch('/aj/music/nav');
67 |
68 | /**
69 | * 获取音乐list
70 | */
71 |
72 | export const getMusic = data => fetch('/aj/music/get', data);
73 |
74 | /**
75 | * 选择音乐
76 | */
77 |
78 | export const choiceMusic = data => fetch('/aj/music/choice', data);
79 |
80 | /**
81 | * 获取图片nav
82 | */
83 |
84 | export const getImageNav = () => fetch('/aj/image/nav');
85 |
86 | /**
87 | * 获取图片list
88 | */
89 |
90 | export const getImage = data => fetch('/aj/image/get', data);
91 |
92 | /**
93 | * 选择图片
94 | */
95 |
96 | export const choiceImage = data => fetch('/aj/image/choice', data);
97 |
98 | /**
99 | * 创建二维码
100 | */
101 |
102 | export const createQRCode = data => fetch('/aj/qrcode/create', data);
103 |
104 | /**
105 | * 用户注册
106 | */
107 |
108 | export const userRegister = data => fetch('/aj/user/register', data, 'POST');
109 |
110 | /**
111 | * 用户登录
112 | */
113 |
114 | export const userLogin = data => fetch('/aj/user/login', data, 'POST');
115 |
116 | /**
117 | * 用户登出
118 | */
119 |
120 | export const userLogout = data => fetch('/aj/user/logout', data, 'POST');
121 |
122 | /**
123 | * 获取用户信息
124 | */
125 |
126 | export const getUserInfo = data => fetch('/aj/user/info', data);
127 |
128 | /**
129 | * 获取上传token
130 | */
131 |
132 | export const getToken = data => fetch('/aj/upload/token', data);
133 |
134 | /**
135 | * 上传图片
136 | */
137 |
138 | export const userUpload = data => fetch('/aj/image/user_upload', data, 'POST');
139 |
140 | /**
141 | * 上传音乐
142 | */
143 |
144 | export const userUploadMusic = data => fetch('/aj/music/user_upload', data, 'POST');
145 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "myh5",
3 | "version": "0.3.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve --open",
7 | "server": "node ./server/bin/www",
8 | "build": "vue-cli-service build",
9 | "start": "concurrently \"yarn dev\" \"yarn server\"",
10 | "lint": "vue-cli-service lint"
11 | },
12 | "dependencies": {
13 | "animate.css": "^3.6.1",
14 | "art-template": "^4.12.2",
15 | "clipboard": "^2.0.1",
16 | "cookie-parser": "^1.4.3",
17 | "cropper": "^4.0.0",
18 | "element-ui": "^2.4.1",
19 | "express-art-template": "^1.0.1",
20 | "express-session": "^1.15.6",
21 | "jquery": "^3.3.1",
22 | "jquery.cookie": "^1.4.1",
23 | "js-cookie": "^2.2.0",
24 | "lodash": "^4.17.10",
25 | "md5": "^2.2.1",
26 | "moment": "^2.22.1",
27 | "mongoose": "^5.0.14",
28 | "morgan": "^1.9.0",
29 | "particles.js": "^2.0.0",
30 | "qaep-push": "^1.0.3",
31 | "qrcode": "^1.2.0",
32 | "serve-favicon": "^2.5.0",
33 | "sha1": "^1.1.1",
34 | "superagent": "^3.8.2",
35 | "swiper": "^4.3.0",
36 | "uuid": "^3.2.1",
37 | "vue": "^2.5.13",
38 | "vue-resource": "^1.5.0",
39 | "vue-router": "^3.0.1",
40 | "vuedraggable": "^2.16.0",
41 | "vuex": "^3.0.1"
42 | },
43 | "devDependencies": {
44 | "@vue/cli-plugin-babel": "^3.0.0-beta.6",
45 | "@vue/cli-plugin-eslint": "^3.0.0-beta.6",
46 | "@vue/cli-service": "^3.0.0-beta.6",
47 | "art-template-loader": "^1.4.3",
48 | "babel-plugin-component": "^1.1.0",
49 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
50 | "connect-history-api-fallback": "^1.5.0",
51 | "node-sass": "^4.8.3",
52 | "qiniu": "^7.1.3",
53 | "rimraf": "^2.6.2",
54 | "sass-loader": "^6.0.7",
55 | "vue-template-compiler": "^2.5.13"
56 | },
57 | "babel": {
58 | "presets": [
59 | "@vue/app"
60 | ],
61 | "plugins": [
62 | [
63 | "component",
64 | {
65 | "libraryName": "element-ui",
66 | "styleLibraryName": "theme-chalk"
67 | }
68 | ]
69 | ]
70 | },
71 | "eslintConfig": {
72 | "root": true,
73 | "env": {
74 | "node": true
75 | },
76 | "extends": [
77 | "plugin:vue/essential",
78 | "eslint:recommended"
79 | ],
80 | "rules": {
81 | "no-console": "off"
82 | },
83 | "parserOptions": {
84 | "parser": "babel-eslint"
85 | }
86 | },
87 | "postcss": {
88 | "plugins": {
89 | "autoprefixer": {}
90 | }
91 | },
92 | "browserslist": [
93 | "> 1%",
94 | "last 2 versions",
95 | "not ie <= 8"
96 | ]
97 | }
98 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "myh5",
3 | "version": "0.3.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve --open",
7 | "server": "node ./server/bin/www",
8 | "build": "vue-cli-service build",
9 | "start": "concurrently \"yarn dev\" \"yarn server\"",
10 | "lint": "vue-cli-service lint"
11 | },
12 | "dependencies": {
13 | "animate.css": "^3.6.1",
14 | "art-template": "^4.12.2",
15 | "clipboard": "^2.0.1",
16 | "cookie-parser": "^1.4.3",
17 | "cropper": "^4.0.0",
18 | "element-ui": "^2.4.1",
19 | "express-art-template": "^1.0.1",
20 | "express-session": "^1.15.6",
21 | "jade": "^1.11.0",
22 | "jquery": "^3.3.1",
23 | "jquery.cookie": "^1.4.1",
24 | "js-cookie": "^2.2.0",
25 | "lodash": "^4.17.10",
26 | "md5": "^2.2.1",
27 | "moment": "^2.22.1",
28 | "mongoose": "^5.0.14",
29 | "morgan": "^1.9.0",
30 | "particles.js": "^2.0.0",
31 | "qaep-push": "^1.0.3",
32 | "qrcode": "^1.2.0",
33 | "serve-favicon": "^2.5.0",
34 | "sha1": "^1.1.1",
35 | "superagent": "^3.8.2",
36 | "swiper": "^4.3.0",
37 | "uuid": "^3.2.1",
38 | "vue": "^2.5.13",
39 | "vue-resource": "^1.5.0",
40 | "vue-router": "^3.0.1",
41 | "vuedraggable": "^2.16.0",
42 | "vuex": "^3.0.1"
43 | },
44 | "devDependencies": {
45 | "@vue/cli-plugin-babel": "^3.0.0-beta.6",
46 | "@vue/cli-plugin-eslint": "^3.0.0-beta.6",
47 | "@vue/cli-service": "^3.0.0-beta.6",
48 | "art-template-loader": "^1.4.3",
49 | "babel-plugin-component": "^1.1.0",
50 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
51 | "connect-history-api-fallback": "^1.5.0",
52 | "node-sass": "^4.8.3",
53 | "qiniu": "^7.1.3",
54 | "rimraf": "^2.6.2",
55 | "sass-loader": "^6.0.7",
56 | "vue-template-compiler": "^2.5.13"
57 | },
58 | "babel": {
59 | "presets": [
60 | "@vue/app"
61 | ],
62 | "plugins": [
63 | [
64 | "component",
65 | {
66 | "libraryName": "element-ui",
67 | "styleLibraryName": "theme-chalk"
68 | }
69 | ]
70 | ]
71 | },
72 | "eslintConfig": {
73 | "root": true,
74 | "env": {
75 | "node": true
76 | },
77 | "extends": [
78 | "plugin:vue/essential",
79 | "eslint:recommended"
80 | ],
81 | "rules": {
82 | "no-console": "off"
83 | },
84 | "parserOptions": {
85 | "parser": "babel-eslint"
86 | }
87 | },
88 | "postcss": {
89 | "plugins": {
90 | "autoprefixer": {}
91 | }
92 | },
93 | "browserslist": [
94 | "> 1%",
95 | "last 2 versions",
96 | "not ie <= 8"
97 | ]
98 | }
99 |
--------------------------------------------------------------------------------
/backstage/src/directive/select.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import $ from 'jquery'
3 | import store from '../store/index.js'
4 |
5 | Vue.directive('my-select', {
6 | inserted() {
7 | $('body').append($(''))
8 | $('#j-choice-box').css({
9 | position: 'absolute',
10 | left: 0,
11 | top: 0,
12 | width: 0,
13 | height: 0,
14 | border: '1px solid #000',
15 | display: 'none',
16 | 'z-index': 9999,
17 | background: 'rgba(0,0,0,0.3)'
18 | })
19 | },
20 | bind: function (el) {
21 | $(el).on('mousedown', (ev) => {
22 | let arr = store.getters.currentPhone.data;
23 | let oldX = ev.clientX;
24 | let oldY = ev.clientY;
25 | let x, y, w, h;
26 | $('#j-choice-box').show();
27 | const {
28 | left: phoneLeft,
29 | top: phoneTop
30 | } = $('.workspace').offset();
31 | $(document).on('mousemove', (ev) => {
32 | let nowX = ev.clientX;
33 | let nowY = ev.clientY;
34 | if (nowX > oldX) {
35 | x = oldX;
36 | w = nowX - oldX;
37 | } else {
38 | x = nowX;
39 | w = oldX - nowX;
40 | }
41 | if (nowY > oldY) {
42 | y = oldY;
43 | h = nowY - oldY;
44 | } else {
45 | y = nowY;
46 | h = oldY - nowY;
47 | }
48 | $('#j-choice-box').css({
49 | left: x + 'px',
50 | top: y + 'px',
51 | width: w + 'px',
52 | height: h + 'px',
53 | });
54 | var list = [];
55 | arr.forEach((item, index) => {
56 | var {
57 | left,
58 | top,
59 | width,
60 | height
61 | } = item.style;
62 | left = $('#' + item.id).offset().left - phoneLeft;
63 | top = $('#' + item.id).offset().top - phoneTop;
64 | width = parseFloat(width);
65 | height = parseFloat(height);
66 |
67 | if (phoneLeft + left > x + w || phoneLeft + left + width < x || phoneTop + top > y + h || phoneTop + top + height < y) {
68 | // console.log(';')
69 | } else {
70 | list.push(index);
71 | }
72 | })
73 | store.dispatch('selectItem', list)
74 | })
75 | $(document).on('mouseup', () => {
76 | $(document).off('mousemove');
77 | $(document).off('mouseup');
78 | $('#j-choice-box').css({
79 | 'display': 'none',
80 | 'width': 0,
81 | 'height': 0,
82 | 'left': 0,
83 | 'top': 0
84 | })
85 | })
86 | });
87 | }
88 | })
89 |
--------------------------------------------------------------------------------
/backstage/src/img/bg.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backstage/src/components/shape/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
22 |
23 |
24 |
89 |
112 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | let session = require('express-session')
6 | var cookieParser = require('cookie-parser');
7 | var bodyParser = require('body-parser');
8 | let url = require('url')
9 | var history = require('connect-history-api-fallback');
10 | const {
11 | AJ_STATUS,
12 | AJ_MESSAGE
13 | } = require('./const/index')
14 | // var index = require('./routes/index');
15 | // var users = require('./routes/users');
16 | const types = require('./api/types')
17 | let dbHandel = require('./db/handel.js')
18 |
19 |
20 | var app = express();
21 | // app.use(history({
22 | // index: '/Users/BraisedCakes/Desktop/2018/myh5-project/backstage/public/index.html'
23 | // }));
24 | // view engine setup
25 | // app.set('views', path.resolve(process.cwd(), 'server/views'));
26 | // app.set('view engine', 'jade');
27 | app.engine('art', require('express-art-template'));
28 | var runtime = require('art-template/lib/runtime');
29 | runtime.parseStyle = function (date, format) {
30 | let str = ''
31 | for (let attr in date) {
32 | str += attr + ':' + date[attr] + ';'
33 | }
34 | return str
35 | };
36 | app.set('view options', {
37 | debug: process.env.NODE_ENV !== 'production'
38 | });
39 | // uncomment after placing your favicon in /public
40 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
41 | app.use(logger('dev'));
42 | app.use(bodyParser.json({
43 | limit: '50mb'
44 | }));
45 | app.use(bodyParser.urlencoded({
46 | extended: false
47 | }));
48 | app.use(cookieParser());
49 | app.use(session({
50 | secret: 'who am i ?',
51 | cookie: {
52 | maxAge: 1000 * 60 * 60 * 24 * 7
53 | },
54 | saveUninitialized: true,
55 | resave: true
56 | }))
57 |
58 | app.use('/store', express.static('/Users/BraisedCakes/Desktop/2018/myh5-store/svg'));
59 |
60 | app.get('/show', function (req, res) {
61 | let myh5 = dbHandel.getModel('myh5')
62 | let id = url.parse(req.url, true).query['id']
63 | console.log(id)
64 | myh5.findOne({
65 | id: id
66 | }, (err, docs) => {
67 | res.render(path.resolve(process.cwd(), 'web/public/index.art'), {
68 | info: docs.data
69 | });
70 | });
71 | });
72 |
73 | app.all('/aj/*', function (req, res, next) {
74 | // res.header('Access-Control-Allow-Origin', 'http://localhost:8082');
75 | // res.header('Access-Control-Allow-Headers', 'Content-Type');
76 | // res.header('Access-Control-Allow-Credentials', 'true');
77 | if (req.session.username || req.path == '/app.js' || req.path == types.getPublishScene || req.path == types.getUserInfo || req.path == types.userLogin || req.path == types.userRegister) {
78 | next()
79 | } else {
80 | res.send({
81 | status: AJ_STATUS.notlogin,
82 | data: {},
83 | message: AJ_MESSAGE.error
84 | })
85 | }
86 | // next();
87 | });
88 |
89 | app.use(function (err, req, res, next) {
90 | // set locals, only providing error in development
91 | res.locals.message = err.message;
92 | res.locals.error = req.app.get('env') === 'development' ? err : {};
93 |
94 | // render the error page
95 | res.status(err.status || 500);
96 | res.render('error');
97 | // res.end(JSON.stringify(req.body, null, 2))
98 | });
99 |
100 |
101 | module.exports = app;
102 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/page-dom.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
图片背景
8 |
9 |
![]()
10 |
11 |
12 |
13 | 裁切
14 | 删除
15 | 更换
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
62 |
112 |
--------------------------------------------------------------------------------
/backstage/src/css/index.css:
--------------------------------------------------------------------------------
1 | ul {
2 | list-style: none;
3 | }
4 |
5 | a {
6 | text-decoration: none;
7 | cursor: pointer;
8 | }
9 |
10 | .icon {
11 | width: 1em;
12 | height: 1em;
13 | vertical-align: -0.15em;
14 | fill: currentColor;
15 | overflow: hidden;
16 | }
17 |
18 | em,
19 | i {
20 | font-style: normal;
21 | font-weight: 400;
22 | }
23 |
24 | html {
25 | min-height: 100vh;
26 | }
27 |
28 | body {
29 | /* -webkit-font-smoothing: antialiased;
30 | -moz-osx-font-smoothing: grayscale; */
31 | font-size: 12px;
32 | user-select: none;
33 | /* overflow: hidden; */
34 | min-height: 100vh;
35 | zoom: 1;
36 | color: #76838f;
37 | min-width: 1200px;
38 | }
39 |
40 | body>div {
41 | /* height: 100%; */
42 | }
43 |
44 | #app {
45 | min-height: 100vh;
46 | width: 100%;
47 | position: relative;
48 | left: 0;
49 | top: 0;
50 | }
51 |
52 | .el-scrollbar__view {
53 | height: 100%;
54 | }
55 |
56 | .el-scrollbar__bar {
57 | z-index: 999999 !important;
58 | }
59 |
60 | .drag-handle {
61 | cursor: move;
62 | cursor: -webkit-grabbing;
63 | }
64 |
65 | div {
66 | border-width: 0;
67 | }
68 |
69 | @keyframes fadeIn {
70 | 0% {
71 | opacity: 0
72 | }
73 | to {
74 | opacity: 1
75 | }
76 | }
77 |
78 | @keyframes fadeInLeft {
79 | 0% {
80 | opacity: 0;
81 | -webkit-transform: translate3d(-200px, 0, 0);
82 | transform: translate3d(-200px, 0, 0)
83 | }
84 | to {
85 | opacity: 1;
86 | -webkit-transform: none;
87 | transform: none
88 | }
89 | }
90 |
91 | @keyframes opacityFadeInLeft {
92 | 0% {
93 | opacity: 1;
94 | -webkit-transform: translate3d(-200px, 0, 0);
95 | transform: translate3d(-200px, 0, 0)
96 | }
97 | to {
98 | opacity: 1;
99 | -webkit-transform: none;
100 | transform: none
101 | }
102 | }
103 |
104 | .pause {
105 | animation-play-state: paused;
106 | }
107 |
108 | @-webkit-keyframes fade-scale-02 {
109 | 0% {
110 | opacity: 0;
111 | -webkit-transform: scale(.2);
112 | transform: scale(.2)
113 | }
114 | to {
115 | opacity: 1;
116 | -webkit-transform: scale(1);
117 | transform: scale(1)
118 | }
119 | }
120 |
121 | @keyframes fade-scale-02 {
122 | 0% {
123 | opacity: 0;
124 | -webkit-transform: scale(.2);
125 | -o-transform: scale(.2);
126 | transform: scale(.2)
127 | }
128 | to {
129 | opacity: 1;
130 | -webkit-transform: scale(1);
131 | -o-transform: scale(1);
132 | transform: scale(1)
133 | }
134 | }
135 |
136 | @keyframes zoomIn {
137 | 0% {
138 | opacity: 0;
139 | -webkit-transform: scale3d(0.3, 0.3, 0.3);
140 | transform: scale3d(0.3, 0.3, 0.3);
141 | }
142 | 50% {
143 | opacity: 1;
144 | }
145 | }
146 |
147 | @keyframes rotating {
148 | 0% {
149 | transform: rotate(0deg)
150 | }
151 | to {
152 | transform: rotate(1turn)
153 | }
154 | }
155 |
156 | .rotate {
157 | animation: rotating 1.2s linear infinite;
158 | }
159 |
160 | #wrapAll {
161 | width: 318px;
162 | height: 486px;
163 | overflow: hidden;
164 | position: absolute;
165 | left: 50%;
166 | top: 82px;
167 | margin-left: -159px;
168 | }
169 |
170 | .swiper-container {
171 | width: 100%;
172 | height: 100%;
173 | position: relative;
174 | }
175 |
176 | .swiper-container .swiper-wrapper {
177 | width: 100%;
178 | height: 100%;
179 | position: absolute;
180 | }
181 |
182 | .swiper-slide {
183 | overflow: hidden;
184 | }
185 |
--------------------------------------------------------------------------------
/backstage/src/img/notfound.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/h5/public/index.art:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | web
9 |
40 |
84 |
85 |
86 |
87 |
88 |
91 |
98 |
99 |
100 | {{ each info.data }}
101 |
102 |
103 | {{each $value.data}}
104 |
105 | {{@ $value.content }}
106 |
107 | {{/each}}
108 |
109 |
110 | {{/each}}
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/server/views/index.art:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | web
9 |
40 |
84 |
85 |
86 |
87 |
88 |
91 |
98 |
99 |
100 | {{ each info.data }}
101 |
102 |
103 | {{each $value.data}}
104 |
105 | {{@ $value.content }}
106 |
107 | {{/each}}
108 |
109 |
110 | {{/each}}
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/action/page.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import $ from 'jquery'
3 | import * as types from '../mutation-types.js'
4 | import app from '@/main'
5 | import * as utils from '@/utils'
6 | export default {
7 | /**
8 | * 复制指定页
9 | * @param from 被复制的页码
10 | * @param to 复制到哪页
11 | */
12 | async copyPage({
13 | commit,
14 | state,
15 | dispatch,
16 | getters
17 | }, {
18 | from = getters.currentPage,
19 | to = getters.currentPage + 1
20 | } = {}) {
21 | if (from < 0 || from >= getters.phoneData.data.length) {
22 | return;
23 | }
24 | await dispatch('addPage', {
25 | go: false,
26 | record: false
27 | });
28 | Vue.nextTick().then(async () => {
29 | let data = $.extend(true, {}, state.phone.data[from]);
30 | data.data.forEach((item) => {
31 | commit(types.ADD_CREATED_ID);
32 | item.id = `item_${state.phone.main.createdDomId}`
33 | });
34 | commit(types.CHANGE_DATA, {
35 | page: to,
36 | data: data
37 | });
38 | await dispatch('selectPage', {
39 | page: to
40 | });
41 | dispatch('record', {
42 | type: 'page',
43 | data: data
44 | })
45 | })
46 | },
47 | /**
48 | * 改变活跃页
49 | * @param {Number} page 页码
50 | */
51 | async selectPage({
52 | commit,
53 | dispatch
54 | }, {
55 | page,
56 | ani = true
57 | }) {
58 | await dispatch('cancelSelect');
59 | await commit(types.SELECT_PAGE, page);
60 | Vue.nextTick().then(() => {
61 | ani && utils.runCurPhoneAni();
62 | })
63 | },
64 | /**
65 | * 增加一页
66 | * @param {Boolean} go 是否选中新页面
67 | * @param {Boolean} record 是否记录cache
68 | */
69 | async addPage({
70 | commit,
71 | dispatch,
72 | getters
73 | }, {
74 | go = true,
75 | record = true
76 | } = {}) {
77 | commit(types.ADD_PAGE, {
78 | index: getters.currentPage,
79 | phoneData: getters.phoneData
80 | })
81 | go && await dispatch('selectPage', {
82 | page: getters.currentPage + 1
83 | });
84 | record && dispatch('record', {
85 | type: 'page',
86 | data: getters.currentPhone
87 | })
88 | },
89 | /**
90 | * 排序
91 | */
92 | async sortPage({
93 | commit,
94 | state,
95 | getters,
96 | dispatch
97 | }, data) {
98 | await dispatch('selectPage', {
99 | page: data.futureIndex,
100 | ani: false
101 | });
102 | let arr = [];
103 | console.log(data)
104 | data.value.forEach((item) => {
105 | for (let i = 0; i < getters.phoneData.data.length; i++) {
106 | if (getters.phoneData.data[i] == item) {
107 | arr.push(state.cacheData[i])
108 | }
109 | }
110 | })
111 | commit(types.CHANGE_DATA, {
112 | data: data.value
113 | });
114 | dispatch('record', {
115 | type: 'init',
116 | data: arr
117 | })
118 | },
119 | /**
120 | * 删除指定页
121 | * @param {Number} page 页码
122 | */
123 | async delPage({
124 | commit,
125 | dispatch,
126 | getters
127 | }, page) {
128 | if (getters.pageLength > 1) {
129 | commit(types.DEL_PAGE, {
130 | phoneData: getters.phoneData,
131 | page: page
132 | });
133 | if (getters.currentPage > getters.phoneData.data.length - 1) {
134 | await dispatch('selectPage', {
135 | page: getters.phoneData.data.length - 1
136 | });
137 | }
138 | dispatch('record', {
139 | type: 'delPage',
140 | page: page
141 | })
142 | } else {
143 | app.$alert('最少保留一页内容', {
144 | closeOnClickModal: true,
145 | callback: () => {}
146 | });
147 | }
148 | },
149 | }
150 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/qrcode.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 生成
18 |
19 |
20 |
21 |
22 |
![]()
23 |
24 |
28 |
29 |
30 |
31 |
32 |
80 |
--------------------------------------------------------------------------------
/server/api/scene.js:
--------------------------------------------------------------------------------
1 | let router = require('../app.js')
2 | let utils = require('../utils')
3 | let api = require('./types')
4 | let sceneModel = require('../models/scene')
5 | let {
6 | AJ_STATUS,
7 | AJ_MESSAGE
8 | } = require('../const/index')
9 |
10 | // 获取指定场景
11 | router.get(api.getSceneData, async (req, res) => {
12 | let id = req.query.id
13 | try {
14 | let data = await sceneModel.getSceneById(id)
15 | if (!data) {
16 | throw new Error('场景不存在')
17 | } else {
18 | data.portrait = data.domain + data.portrait
19 | res.send({ status: AJ_STATUS.success, message: AJ_MESSAGE.success, result: data })
20 | }
21 | } catch (e) {
22 | res.send({ status: AJ_STATUS.error, message: e.message })
23 | }
24 | })
25 |
26 | // 保存场景
27 | router.post(api.saveScene, async (req, res) => {
28 | let id = req.body.id
29 | try {
30 | let data = await sceneModel.getSceneById(id)
31 | if (!data) {
32 | throw new Error('场景不存在')
33 | } else {
34 | await sceneModel.updateSceneById(id, {
35 | data: req.body.data,
36 | updateTime: utils.getTime(),
37 | status: data.status != 0 ? 2 : 0
38 | })
39 | res.send({ status: AJ_STATUS.success, message: AJ_MESSAGE.success })
40 | }
41 | } catch (e) {
42 | res.send({ status: AJ_STATUS.error, message: e.message })
43 | }
44 | })
45 |
46 | // 更新场景信息
47 | router.post(api.updateScene, async (req, res) => {
48 | let id = req.body.id
49 | try {
50 | let data = await sceneModel.getSceneById(id)
51 | if (!data) {
52 | throw new Error('场景不存在')
53 | } else {
54 | let title = req.body.title || data.title
55 | let desc = req.body.desc || data.desc
56 | let portrait = req.body.portrait || data.portrait
57 | portrait = portrait.match(/.com\/(.+)/)[1]
58 | await sceneModel.updateSceneById(id, {
59 | title: title,
60 | desc: desc,
61 | portrait: portrait
62 | })
63 | res.send({ status: AJ_STATUS.success, message: '更新成功' })
64 | }
65 | } catch (e) {
66 | res.send({ status: AJ_STATUS.error, message: e.message })
67 | }
68 | })
69 |
70 | // 获取场景列表
71 | router.get('/aj/scene/list', async (req, res) => {
72 | // page,limit,uid,status
73 | let search = {
74 | uid: req.session.uid,
75 | status: {
76 | // 默认情况获取所有非回收站作品
77 | $in: req.query.status ? req.query.status.split(',') : [0, 1, 2]
78 | }
79 | }
80 | let page = Number(req.query.page) || 1
81 | let limit = Number(req.query.limit) || 10
82 | let [total, data] = await Promise.all([
83 | sceneModel.getSceneCount(search),
84 | sceneModel.getSceneList(search, { page, limit })
85 | ])
86 | data.forEach((item) => {
87 | item.portrait = item.domain + item.portrait
88 | })
89 | res.send({
90 | status: AJ_STATUS.success,
91 | message: AJ_MESSAGE.success,
92 | result: {
93 | info: {
94 | page: page,
95 | limit: limit,
96 | total: total,
97 | },
98 | data: data
99 | }
100 | })
101 | })
102 |
103 | // 添加一个场景
104 | router.post('/aj/scene/add', async (req, res) => {
105 | let title = req.body.title
106 | let desc = req.body.desc
107 | let uid = req.session.uid
108 |
109 | try {
110 | if (!title.length) {
111 | throw new Error('title不能为空')
112 | }
113 | let count = await sceneModel.getSceneCount()
114 | let copyItem = {}
115 | if (req.body.id) {
116 | copyItem = await sceneModel.getSceneById(req.body.id)
117 | }
118 | let post = {
119 | id: count + 1,
120 | title: title,
121 | desc: desc,
122 | uid: uid,
123 | portrait: copyItem.portrait,
124 | data: copyItem.data,
125 | createTime: utils.getTime(),
126 | updateTime: utils.getTime()
127 | }
128 | await sceneModel.addScene(post)
129 | res.send({ status: AJ_STATUS.success, message: AJ_MESSAGE.success })
130 | } catch (e) {
131 | res.send({ status: AJ_STATUS.error, message: e.message })
132 | return
133 | }
134 | })
135 |
136 | // 删除一个场景
137 | router.get('/aj/scene/del', async (req, res, next) => {
138 | let id = req.query.id
139 | try {
140 | let data = await sceneModel.getSceneById(id)
141 | if (!data) {
142 | throw new Error('该场景不存在')
143 | } else {
144 | await sceneModel.delSceneById(id)
145 | res.send({ status: AJ_STATUS.success, message: '删除成功' })
146 | }
147 | } catch (e) {
148 | res.send({ status: AJ_STATUS.error, message: e.message })
149 | }
150 | })
151 |
152 | // 发布一个场景
153 | router.post('/aj/scene/publish', async (req, res, next) => {
154 | let id = req.body.id
155 | try {
156 | let data = await sceneModel.getSceneById(id)
157 | if (!data) {
158 | throw new Error('该场景不存在')
159 | } else {
160 | await sceneModel.updateSceneById(id, {
161 | updateTime: utils.getTime(),
162 | status: 1,
163 | publishData: data.data
164 | })
165 | res.send({ status: AJ_STATUS.success, message: '发布成功' })
166 | }
167 | } catch (e) {
168 | res.send({ status: AJ_STATUS.error, message: e.message })
169 | }
170 | })
--------------------------------------------------------------------------------
/backstage/src/tpl/index.js:
--------------------------------------------------------------------------------
1 | import $ from 'jquery'
2 | import store from '@/store/index.js'
3 | import * as types from './types.js'
4 |
5 | export default {
6 | /*
7 | 文本
8 | */
9 | [types.TXT]: {
10 | create() {
11 | return {
12 | type: types.TXT,
13 | content: '空白文本',
14 | class: types.TXT.toLowerCase(),
15 | animation: [],
16 | style: {
17 | position: 'absolute',
18 | left: '0',
19 | top: '50px',
20 | color: '#666666',
21 | width: '200px',
22 | height: '100px',
23 | padding: '5px',
24 | 'border-style': 'solid'
25 | }
26 | }
27 | }
28 | },
29 | /*
30 | 形状
31 | */
32 | [types.SHAPE]: {
33 |
34 | create({
35 | content,
36 | path
37 | }) {
38 | content = $(content);
39 | let width = Math.round(parseFloat(content.attr('width')));
40 | let height = Math.round(parseFloat(content.attr('height')));
41 | if (!content.attr('viewbox')) {
42 | content.attr('viewbox', `0 0 ${width} ${height}`);
43 | }
44 | content.attr('preserveAspectRatio', 'none');
45 | if (width >= height) {
46 | let radio = 100 / height;
47 | width = radio * width;
48 | height = 100;
49 | } else {
50 | let radio = 100 / width;
51 | height = radio * width;
52 | width = 100;
53 | }
54 | width = Math.round(width);
55 | height = Math.round(height);
56 | content.attr('width', '100%');
57 | content.attr('height', '100%');
58 | content = content.prop('outerHTML');
59 | return {
60 | type: types.SHAPE,
61 | content: content,
62 | class: types.SHAPE.toLowerCase(),
63 | animation: [],
64 | fill: {},
65 | width: width,
66 | height: height,
67 | path: path,
68 | style: {
69 | position: 'absolute',
70 | left: '0',
71 | top: '50px',
72 | width: `${width}px`,
73 | height: `${height}px`,
74 | 'border-style': 'solid'
75 | }
76 | }
77 | },
78 | afterCreate(itemTpl) {
79 | let arr = [];
80 | $(itemTpl.content)
81 | .find("*")
82 | .each((index, item) => {
83 | if (
84 | $(item).attr("fill") &&
85 | arr.every(item2 => {
86 | return item2.fill != $(item).attr("fill");
87 | })
88 | ) {
89 | arr.push({
90 | fill: $(item).attr("fill"),
91 | css: $(item).css("fill")
92 | });
93 | }
94 | });
95 | for (let i = 0; i < arr.length; i++) {
96 | store.dispatch('updateItem', {
97 | key: "content",
98 | val: arr[i].css,
99 | fill: arr[i].fill
100 | });
101 | }
102 | }
103 | },
104 | /*
105 | 图片
106 | */
107 | [types.IMAGE]: {
108 | create({
109 | path,
110 | width,
111 | height
112 | }) {
113 | return {
114 | type: types.IMAGE,
115 | path: path,
116 | originPath: path,
117 | crop: {},
118 | content: `
`,
119 | class: types.IMAGE.toLowerCase(),
120 | animation: [],
121 | style: {
122 | position: 'absolute',
123 | left: '0',
124 | top: '50px',
125 | width: `${width}px`,
126 | height: `${height}px`,
127 | 'border-style': 'solid'
128 | }
129 | }
130 | }
131 | },
132 | /*
133 | 二维码
134 | */
135 | [types.QRCODE]: {
136 | create({
137 | url
138 | }) {
139 | let width = 200;
140 | let height = 200;
141 | return {
142 | type: types.QRCODE,
143 | content: `
`,
144 | class: types.IMAGE.toLowerCase(),
145 | animation: [],
146 | style: {
147 | position: 'absolute',
148 | left: '0',
149 | top: '50px',
150 | width: `${width}px`,
151 | height: `${height}px`,
152 | 'border-style': 'solid'
153 | }
154 | }
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/backstage/src/components/music/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
18 | -
22 |
{{item.name}}
23 |
25 |
27 |
29 |
30 |
31 |
32 |
33 | 已选择:{{curMusic.name}}
34 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
151 |
--------------------------------------------------------------------------------
/backstage/src/page/login/login.vue:
--------------------------------------------------------------------------------
1 |
23 |
24 |
25 |
26 |
28 |
29 |
登录
30 |
31 |
35 |
37 |
39 |
40 |
42 |
44 |
45 |
46 | 登录
48 |
49 |
注册
50 |
51 |
55 |
57 |
59 |
60 |
62 |
64 |
65 |
66 | 注册
68 |
69 |
70 |
71 |
72 |
164 |
--------------------------------------------------------------------------------
/backstage/src/components/image/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
24 |
25 |
26 |
27 |
110 |
133 |
--------------------------------------------------------------------------------
/backstage/src/components/background/main.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
24 |
25 |
26 |
27 |
110 |
133 |
--------------------------------------------------------------------------------
/server/upload/app.js:
--------------------------------------------------------------------------------
1 | // const superagent = require('superagent')
2 | // const fs = require('fs')
3 | // superagent.post('http://store.eqxiu.com/api/category/getCategoryListById?id=889875').set("Cookie", '_ga=GA1.2.1844039418.1523173010; gr_user_id=856b28d3-7797-4ad3-bf0a-e970d2d29855; _gid=GA1.2.1183794952.1523282172; _tracker_distinct_id_=5d3727a1-f0a8-457d-9fbe-47317c4011b7; _tracker_session_id_=6915a5f5-2f33-4892-afca-d78fa7b039f7; _tracker_user_id_=4a2d8af950851f490150ef39910e18f1; UM_distinctid=162be364ec91054-02381f8078fd39-33697b04-1fa400-162be364eca1bb; rememberMe=DLcTdZGZXkAzMHU5jjaPN1v2Z6yk2xDAZWR4mm5v8zCdN91USpyM8T0IGwdxQTgxjjFv43XARdAD/hDJO9G1jiIHpv8TowKQlY4E9+yh5+AVPew0MzTHiqFdAnUhElwhcAgjaecr6Lvi49oJhxc7hBg7Nj0yJc5a6wdZyBPVJCpReJ8NrDlzEpTiuzmh0n+/4nbSMEV8wshWBPOxXtMA6lON+OgitiGHFLNVc28x6oqn/yYYWrPA/VjqJU/IRkI5mtlB4Lvtba+ZblokqnQ5QGLOxTknUZ2/VyPH+2IXomiOx56gjSQ/GO8ZO4oenIBmp3kCFh0+wZqwDHkwcojLQxuPv1w9B96gqwFJUO3IU5NJpC2kf/2vCbb/a4TmpA31GmwCQpaX5XHxHaTKfO6bN20FEvTo0wy9Q/4mcSVJoihzySyOGAVYElXKqvqcYAQpyUT8XQ/FwL7STpcHxoHkGuP91fOVbXw0l7WbjtG6dADEZ3qV24TkNgqulqUdFi1tXk46dB54EEbToGoa33eZbwK1qtFRtujaZVY9088ImXQkrZV0K2dyJJkDfhTbyteFIG3MnZfjxBm4IwagzOE0uhR39bSRBQaZZGLJ2dnRgHhMowPDnLcGNWCHTBIISLw0Rjj7qY9lLHyfprfN3uet/iPvVoIHMzXxDf4l0w3m5Wp7cw/akurO4JTZMl+9iAuJY0gmvGHImXfz7W3XuEfNoP9nKPCtNVj4ewLE8FoDIjKlejDaUsR3R+2peNRJ4XGzAUysUU0JklxzlBfq3pKzWRtb4RGmFTz8+CtJQnTdocQ6V5ZC96BCSQ1gljLjzfG8JDxQ7Wj0KxUmMwC8+6L495Xg8iowmWyYdv7AHI8ippkAdkjeJ5oPsVxG4KdhD7gf2TACM5KgcezXx89tR1pMo0GDhJOWWO3PoEOCZPWbaLFEHd6vh5jyLDraUWi8KqW5MvB7pAuqqhe2Ftq2/qFwVU+xVCTpWYSUfAfNHDfGp2yomKcMckkdh5IJALDmRKvGiBSRfo/v2Q9GOGlb9PaT4gqudN2FWFWORhk0Y4Q3WW9EP++7sGOyIhjfBXf1amphc2BZG0YumdJIQoghz9FPcopQsa2HCtHF+kWuTDutVQOWAc5TcAApAMwakrYEeyyUqVFKJwZlVvu6rvpwA3+Ji3VvW2pDWsREHo5cYGLrb2KY5yffRfEUvANargC79qzamx4e5Zn3vJBsa5DjNrv46lWSEbOwj+edsYYUBHRi8GFFGA02MCpimqWls76witVUwHE5BLYA379ZP35HMr11wwmIgvIVvr76tRbMydVFKsoO5qbSbkfnD1YNtfjoqSB84OCwlrUkNU3TKXnhjnFvOg==; _tracker_launch_=1; JSESSIONID=87f8dac50f5443b3a643addcbc60dc84; gr_session_id_a17a66c1107ba80b=6aaada5d-7096-4d1a-82db-c5b19f30cf06; _gat=1').set({
4 | // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
5 | // 'Content-Type': 'application/x-www-form-urlencoded'
6 | // }).end(async function (err, res) {
7 | // // console.log(res.body.list)
8 | // let list = res.body.list;
9 | // for (let i = 0; i < list.length; i++) {
10 | // fs.appendFileSync(`/Users/BraisedCakes/Desktop/2018/myh5-store/musics/${list[i].name}.json`, '');
11 | // // break;
12 | // for (let j = 0; j < 1000; j++) {
13 | // let data = await fn(j + 1, list[i].id);
14 | // if (!data || data.length == 0) {
15 | // break;
16 | // } else {
17 | // let originData = [];
18 | // if (fs.existsSync(`/Users/BraisedCakes/Desktop/2018/myh5-store/musics/${list[i].name}.json`)) {
19 | // let docs = fs.readFileSync(`/Users/BraisedCakes/Desktop/2018/myh5-store/musics/${list[i].name}.json`, 'utf-8');
20 | // if (docs.trim() == '') {
21 | // docs = '[]'
22 | // }
23 | // originData = JSON.parse(docs);
24 | // }
25 | // originData.push(...data)
26 |
27 | // fs.writeFileSync(`/Users/BraisedCakes/Desktop/2018/myh5-store/musics/${list[i].name}.json`, JSON.stringify(originData, null, 4));
28 | // console.log(`当前type = ${list[i].name}, page = ${j+1}`)
29 | // }
30 | // }
31 | // }
32 | // });
33 |
34 |
35 | // function fn(page, id) {
36 | // return new Promise((resolve) => {
37 | // superagent.get(`http://store.eqxiu.com/api/product/cat/listProdByCate?attrGroupId=3&category=${id}&pageNo=${page}&pageSize=10`).set("Cookie", '_ga=GA1.2.1844039418.1523173010; gr_user_id=856b28d3-7797-4ad3-bf0a-e970d2d29855; _gid=GA1.2.1183794952.1523282172; _tracker_distinct_id_=5d3727a1-f0a8-457d-9fbe-47317c4011b7; _tracker_session_id_=6915a5f5-2f33-4892-afca-d78fa7b039f7; _tracker_user_id_=4a2d8af950851f490150ef39910e18f1; UM_distinctid=162be364ec91054-02381f8078fd39-33697b04-1fa400-162be364eca1bb; rememberMe=DLcTdZGZXkAzMHU5jjaPN1v2Z6yk2xDAZWR4mm5v8zCdN91USpyM8T0IGwdxQTgxjjFv43XARdAD/hDJO9G1jiIHpv8TowKQlY4E9+yh5+AVPew0MzTHiqFdAnUhElwhcAgjaecr6Lvi49oJhxc7hBg7Nj0yJc5a6wdZyBPVJCpReJ8NrDlzEpTiuzmh0n+/4nbSMEV8wshWBPOxXtMA6lON+OgitiGHFLNVc28x6oqn/yYYWrPA/VjqJU/IRkI5mtlB4Lvtba+ZblokqnQ5QGLOxTknUZ2/VyPH+2IXomiOx56gjSQ/GO8ZO4oenIBmp3kCFh0+wZqwDHkwcojLQxuPv1w9B96gqwFJUO3IU5NJpC2kf/2vCbb/a4TmpA31GmwCQpaX5XHxHaTKfO6bN20FEvTo0wy9Q/4mcSVJoihzySyOGAVYElXKqvqcYAQpyUT8XQ/FwL7STpcHxoHkGuP91fOVbXw0l7WbjtG6dADEZ3qV24TkNgqulqUdFi1tXk46dB54EEbToGoa33eZbwK1qtFRtujaZVY9088ImXQkrZV0K2dyJJkDfhTbyteFIG3MnZfjxBm4IwagzOE0uhR39bSRBQaZZGLJ2dnRgHhMowPDnLcGNWCHTBIISLw0Rjj7qY9lLHyfprfN3uet/iPvVoIHMzXxDf4l0w3m5Wp7cw/akurO4JTZMl+9iAuJY0gmvGHImXfz7W3XuEfNoP9nKPCtNVj4ewLE8FoDIjKlejDaUsR3R+2peNRJ4XGzAUysUU0JklxzlBfq3pKzWRtb4RGmFTz8+CtJQnTdocQ6V5ZC96BCSQ1gljLjzfG8JDxQ7Wj0KxUmMwC8+6L495Xg8iowmWyYdv7AHI8ippkAdkjeJ5oPsVxG4KdhD7gf2TACM5KgcezXx89tR1pMo0GDhJOWWO3PoEOCZPWbaLFEHd6vh5jyLDraUWi8KqW5MvB7pAuqqhe2Ftq2/qFwVU+xVCTpWYSUfAfNHDfGp2yomKcMckkdh5IJALDmRKvGiBSRfo/v2Q9GOGlb9PaT4gqudN2FWFWORhk0Y4Q3WW9EP++7sGOyIhjfBXf1amphc2BZG0YumdJIQoghz9FPcopQsa2HCtHF+kWuTDutVQOWAc5TcAApAMwakrYEeyyUqVFKJwZlVvu6rvpwA3+Ji3VvW2pDWsREHo5cYGLrb2KY5yffRfEUvANargC79qzamx4e5Zn3vJBsa5DjNrv46lWSEbOwj+edsYYUBHRi8GFFGA02MCpimqWls76witVUwHE5BLYA379ZP35HMr11wwmIgvIVvr76tRbMydVFKsoO5qbSbkfnD1YNtfjoqSB84OCwlrUkNU3TKXnhjnFvOg==; _tracker_launch_=1; JSESSIONID=87f8dac50f5443b3a643addcbc60dc84; gr_session_id_a17a66c1107ba80b=6aaada5d-7096-4d1a-82db-c5b19f30cf06; _gat=1').set({
38 | // "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
39 | // 'Content-Type': 'application/x-www-form-urlencoded'
40 | // }).end(function (err, res) {
41 | // setTimeout(() => {
42 | // resolve(res.body.list)
43 | // }, 500)
44 | // });
45 | // })
46 | // }
47 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/tool.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
157 |
158 |
179 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/page.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 页面属性
5 | - 元素属性
6 | - 页面管理
7 |
8 |
9 |
10 |
11 |
12 |
13 | -
14 |
15 |
16 | {{index + 1}}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 新增一页
29 |
30 |
31 |
35 |
36 |
37 |
38 |
92 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/ani.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 | 添加动画
7 |
8 | -
9 |
10 | 预览动画
11 |
12 |
13 |
14 | -
15 |
16 |
17 | 动画{{index + 1}}
18 | {{item | getLabel}}
19 |
20 |
21 | x
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
40 |
41 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
117 |
118 |
181 |
--------------------------------------------------------------------------------
/backstage/src/page/edit/phone.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
72 |
73 |
173 |
--------------------------------------------------------------------------------
/backstage/src/store/edit/modules/page.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import $ from 'jquery'
3 | import * as types from '../mutation-types.js'
4 | import * as constant from '@/constant'
5 | import app from '@/main'
6 | import * as utils from '@/utils'
7 |
8 | const page = {
9 | namespaced: true,
10 | state: {
11 | currentPage: 0,
12 | },
13 | getters: {
14 |
15 | /**
16 | * 总页码
17 | * @return {Number}
18 | */
19 |
20 | pageLength: (state, getters, rootState) => rootState.edit.phone.data.length,
21 |
22 | /**
23 | * 当前页码, 从0开始
24 | * @return {Number}
25 | */
26 |
27 | currentPage: state => state.currentPage,
28 | },
29 | actions: {
30 | /**
31 | * 复制指定页
32 | * @param from 被复制的页码
33 | * @param to 复制到哪页
34 | */
35 | async copyPage({
36 | commit,
37 | state,
38 | dispatch,
39 | getters
40 | }, {
41 | from = getters.currentPage,
42 | to = getters.currentPage + 1
43 | } = {}) {
44 | if (from < 0 || from >= getters.phoneData.data.length) {
45 | return;
46 | }
47 | await dispatch('addPage', {
48 | go: false,
49 | record: false
50 | });
51 | Vue.nextTick().then(async () => {
52 | let data = $.extend(true, {}, state.phone.data[from]);
53 | data.data.forEach((item) => {
54 | commit(types.ADD_CREATED_ID);
55 | item.id = `item_${state.phone.main.createdDomId}`
56 | });
57 | commit(types.CHANGE_DATA, {
58 | page: to,
59 | data: data
60 | });
61 | await dispatch('selectPage', {
62 | page: to
63 | });
64 | // dispatch('record', {
65 | // type: 'page',
66 | // data: data
67 | // })
68 | })
69 | },
70 | /**
71 | * 改变活跃页
72 | * @param {Number} page 页码
73 | */
74 | async selectPage({
75 | commit,
76 | dispatch,
77 | getters
78 | }, {
79 | page,
80 | ani = true
81 | }) {
82 | /* 取消所有选中元素 */
83 | await dispatch('edit/cancelSelect', null, {
84 | root: true
85 | });
86 | /* 取消所有选中元素 */
87 | await commit(types.SELECT_PAGE, {
88 | page: page
89 | });
90 | /* 执行当前页动画 */
91 | Vue.nextTick().then(() => {
92 | ani && utils.runCurPhoneAni();
93 | })
94 | },
95 | /**
96 | * 增加一页
97 | * @param {Boolean} go 是否选中新页面
98 | * @param {Boolean} record 是否记录cache
99 | */
100 | async addPage({
101 | commit,
102 | dispatch,
103 | getters,
104 | rootGetters
105 | }, {
106 | go = true,
107 | record = true
108 | } = {}) {
109 | commit(types.ADD_PAGE, {
110 | index: getters.currentPage,
111 | phoneData: rootGetters['edit/phoneData']
112 | })
113 | go && await dispatch('selectPage', {
114 | page: getters.currentPage + 1
115 | });
116 | // record && dispatch('record', {
117 | // type: 'page',
118 | // data: rootGetters.currentPhone
119 | // })
120 | },
121 | /**
122 | * 排序
123 | */
124 | async sortPage({
125 | commit,
126 | state,
127 | getters,
128 | dispatch
129 | }, data) {
130 | await dispatch('selectPage', {
131 | page: data.futureIndex,
132 | ani: false
133 | });
134 | let arr = [];
135 | data.value.forEach((item) => {
136 | for (let i = 0; i < getters.phoneData.data.length; i++) {
137 | if (getters.phoneData.data[i] == item) {
138 | arr.push(state.cacheData[i])
139 | }
140 | }
141 | })
142 | commit(types.CHANGE_DATA, {
143 | data: data.value
144 | });
145 | // dispatch('record', {
146 | // type: 'init',
147 | // data: arr
148 | // })
149 | },
150 | /**
151 | * 删除指定页
152 | * @param {Number} page 页码
153 | */
154 | async delPage({
155 | commit,
156 | dispatch,
157 | getters,
158 | rootGetters
159 | }, page) {
160 | if (getters.pageLength > 1) {
161 | commit(types.DEL_PAGE, {
162 | phoneData: rootGetters['edit/phoneData'],
163 | page: page
164 | });
165 | if (getters.currentPage > rootGetters['edit/phoneData'].data.length - 1) {
166 | await dispatch('selectPage', {
167 | page: rootGetters['edit/phoneData'].data.length - 1
168 | });
169 | }
170 | // dispatch('record', {
171 | // type: 'delPage',
172 | // page: page
173 | // })
174 | } else {
175 | app.$alert('最少保留一页内容', {
176 | closeOnClickModal: true,
177 | callback: () => {}
178 | });
179 | }
180 | },
181 | },
182 | mutations: {
183 |
184 | /**
185 | * 选择一页
186 | * @param {Number} page 页码
187 | */
188 |
189 | [types.SELECT_PAGE](state, {
190 | page,
191 | }) {
192 | state.currentPage = page;
193 | },
194 |
195 | /**
196 | * 添加一页
197 | * @param {Object} phoneData 数据列表
198 | * @param {Number} index 第index页后新增空白页
199 | */
200 |
201 | [types.ADD_PAGE](state, {
202 | index,
203 | phoneData
204 | }) {
205 | phoneData.data.splice(index + 1, 0, $.extend(true, {}, constant.BASE_BLANK));
206 | },
207 |
208 | /**
209 | * 删除指定页
210 | * @param {Number} phoneData 数据列表
211 | * @param {Number} page 要删除的页码
212 | */
213 |
214 | [types.DEL_PAGE](state, {
215 | phoneData,
216 | page
217 | }) {
218 | phoneData.data.splice(page, 1);
219 | },
220 | },
221 | };
222 |
223 | export default page;
224 |
--------------------------------------------------------------------------------
/server/db/model.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "myh5": {
3 | "id": {
4 | type: Number,
5 | required: true,
6 | description: '作品id'
7 | },
8 | "title": {
9 | type: String,
10 | required: true,
11 | description: '作品title'
12 | },
13 | 'domain': {
14 | type: String,
15 | required: false,
16 | default: 'http://p7d4z759a.bkt.clouddn.com/'
17 | },
18 | "portrait": {
19 | type: String,
20 | required: false,
21 | description: '背景图',
22 | default: 'myh5_logo.png'
23 | },
24 | "desc": {
25 | type: String,
26 | required: false,
27 | description: '作品描述'
28 | },
29 | "createTime": {
30 | type: Number,
31 | required: true,
32 | description: '创建时间'
33 | },
34 | "updateTime": {
35 | type: Number,
36 | required: true,
37 | description: '编辑时间'
38 | },
39 | "data": {
40 | type: Object,
41 | required: false,
42 | default: {},
43 | description: '作品数据'
44 | },
45 | "publishData": {
46 | type: Object,
47 | required: false,
48 | default: {},
49 | description: '发布时的数据'
50 | },
51 | "status": {
52 | type: Number,
53 | default: 0,
54 | description: `状态 0:未发布,1:已发布且无修改,2:已发布且有修改, 3:回收站, 4:彻底删除`
55 | },
56 | "uid": {
57 | type: Number,
58 | required: true,
59 | description: '创建者的uid'
60 | }
61 | },
62 | "shape": {
63 | "path": {
64 | type: String,
65 | required: true
66 | },
67 | 'domain': {
68 | type: String,
69 | required: false,
70 | default: 'http://p7d4z759a.bkt.clouddn.com/'
71 | },
72 | "space": {
73 | type: String,
74 | required: false
75 | },
76 | "content": {
77 | type: String,
78 | required: false
79 | },
80 | "name": {
81 | type: String,
82 | required: false
83 | },
84 | "id": {
85 | type: Number,
86 | required: true
87 | },
88 | "typeId": {
89 | type: String,
90 | required: false
91 | },
92 | "tagId": {
93 | type: String,
94 | required: false
95 | }
96 | },
97 | "desc": {
98 | "id": {
99 | type: Number,
100 | required: true
101 | },
102 | "shape": {
103 | type: Array,
104 | required: false
105 | },
106 | "music": {
107 | type: Array,
108 | required: false
109 | },
110 | "image": {
111 | type: Array,
112 | required: false
113 | }
114 | },
115 | "pic_admin": {
116 | types: {
117 | type: Array,
118 | required: false,
119 | default: []
120 | }
121 | },
122 | 'user': {
123 | 'password': {
124 | type: String,
125 | required: true
126 | },
127 | 'username': {
128 | type: String,
129 | required: true
130 | },
131 | 'uid': {
132 | type: String,
133 | required: true
134 | }
135 | },
136 | 'used_shapes': {
137 | 'uid': {
138 | type: Number,
139 | required: true
140 | },
141 | 'shapeId': {
142 | type: Number,
143 | required: true
144 | },
145 | 'usedTime': {
146 | type: Number,
147 | required: true
148 | }
149 | },
150 | 'used_musics': {
151 | 'uid': {
152 | type: Number,
153 | required: true
154 | },
155 | 'musicId': {
156 | type: Number,
157 | required: true
158 | },
159 | 'usedTime': {
160 | type: Number,
161 | required: true
162 | }
163 | },
164 | 'used_images': {
165 | 'uid': {
166 | type: Number,
167 | required: true
168 | },
169 | 'imageId': {
170 | type: Number,
171 | required: true
172 | },
173 | 'usedTime': {
174 | type: Number,
175 | required: true
176 | }
177 | },
178 | 'images': {
179 | 'uid': {
180 | type: Number,
181 | required: false
182 | },
183 | 'domain': {
184 | type: String,
185 | required: false,
186 | default: 'http://p7d4z759a.bkt.clouddn.com/'
187 | },
188 | 'path': {
189 | type: String,
190 | required: true
191 | },
192 | 'id': {
193 | type: Number,
194 | required: true
195 | },
196 | 'createTime': {
197 | type: Number,
198 | required: true
199 | },
200 | 'size': {
201 | type: Number,
202 | required: false
203 | },
204 | 'name': {
205 | type: String,
206 | required: false
207 | },
208 | 'typeId': {
209 | type: String,
210 | required: false
211 | },
212 | 'width': {
213 | type: Number,
214 | required: false
215 | },
216 | 'height': {
217 | type: Number,
218 | required: false
219 | },
220 | 'isPublic': {
221 | type: Boolean,
222 | required: false,
223 | default: false
224 | }
225 | },
226 | 'musics': {
227 | 'domain': {
228 | type: String,
229 | required: false,
230 | default: 'http://p7d4z759a.bkt.clouddn.com/'
231 | },
232 | 'src': {
233 | type: String,
234 | required: false
235 | },
236 | 'path': {
237 | type: String,
238 | required: true
239 | },
240 | 'name': {
241 | type: String,
242 | required: false
243 | },
244 | 'typeId': {
245 | type: String,
246 | required: false
247 | },
248 | 'id': {
249 | type: Number,
250 | required: true
251 | },
252 | 'createTime': {
253 | type: Number,
254 | required: true
255 | },
256 | 'uid': {
257 | type: Number,
258 | required: false
259 | }
260 | }
261 | }
262 |
--------------------------------------------------------------------------------