automan-cmd 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +56 -0
  3. package/bin/automan +3 -0
  4. package/bin/automan-build +3 -0
  5. package/bin/automan-config +3 -0
  6. package/bin/automan-create +3 -0
  7. package/bin/automan-publish +3 -0
  8. package/lib/automan-build.js +41 -0
  9. package/lib/automan-config.js +82 -0
  10. package/lib/automan-create.js +137 -0
  11. package/lib/automan-publish.js +331 -0
  12. package/lib/index.js +13 -0
  13. package/lib/install.js.tpl +47 -0
  14. package/lib/util.js +174 -0
  15. package/package.json +37 -0
  16. package/tpl/.babelrc +16 -0
  17. package/tpl/.browserslistrc +3 -0
  18. package/tpl/.eslintignore +2 -0
  19. package/tpl/.eslintrc.js +228 -0
  20. package/tpl/.gitignore.ejs +12 -0
  21. package/tpl/.postcssrc.js +12 -0
  22. package/tpl/README.md +1 -0
  23. package/tpl/changelog.md +1 -0
  24. package/tpl/editor/index.vue +45 -0
  25. package/tpl/icon.png +0 -0
  26. package/tpl/jsconfig.json +7 -0
  27. package/tpl/package.json.ejs +66 -0
  28. package/tpl/preview/app.vue +326 -0
  29. package/tpl/preview/attr/Data.vue +69 -0
  30. package/tpl/preview/attr/Resource.vue +79 -0
  31. package/tpl/preview/attr/com.vue +21 -0
  32. package/tpl/preview/attr/index.js +16 -0
  33. package/tpl/preview/components/Attribute.vue +365 -0
  34. package/tpl/preview/components/FitImg.vue +152 -0
  35. package/tpl/preview/components/ImgViewer.vue +80 -0
  36. package/tpl/preview/components/Loading.vue +55 -0
  37. package/tpl/preview/components/Toast.vue +111 -0
  38. package/tpl/preview/index.js +22 -0
  39. package/tpl/preview/index.tpl +13 -0
  40. package/tpl/preview/lib/ESlog.js +46 -0
  41. package/tpl/preview/lib/Util.js +57 -0
  42. package/tpl/preview/lib/fetch.js +139 -0
  43. package/tpl/preview/lib/index.js +15 -0
  44. package/tpl/preview/lib/vue/filters.js +53 -0
  45. package/tpl/preview/lib/vue/index.js +9 -0
  46. package/tpl/preview/lib/vue/mixin.js +166 -0
  47. package/tpl/preview/mint-ui/message-box/index.js +1503 -0
  48. package/tpl/preview/mint-ui/message-box/style.css +159 -0
  49. package/tpl/preview/mint-ui/popup/index.js +1046 -0
  50. package/tpl/preview/mint-ui/popup/style.css +115 -0
  51. package/tpl/preview/mint-ui/spinner/index.js +657 -0
  52. package/tpl/preview/mint-ui/spinner/style.css +227 -0
  53. package/tpl/preview/mint-ui/swipe/index.js +907 -0
  54. package/tpl/preview/mint-ui/swipe/style.css +43 -0
  55. package/tpl/preview/mint-ui/swipe-item/index.js +171 -0
  56. package/tpl/preview/mint-ui/swipe-item/style.css +1 -0
  57. package/tpl/preview/style.css +126 -0
  58. package/tpl/server.config.js +6 -0
  59. package/tpl/src/assets/css/index.scss +29 -0
  60. package/tpl/src/example.vue +165 -0
  61. package/tpl/src/index.vue.ejs +32 -0
  62. package/tpl/webpack.config.js.ejs +267 -0
  63. package/tpl/yarn.lock +6037 -0
@@ -0,0 +1,111 @@
1
+ <template>
2
+ <div
3
+ ref="toast-box"
4
+ class="component toast-box"
5
+ ></div>
6
+ </template>
7
+ <script type="text/ecmascript-6">
8
+ export default {
9
+ name: 'Toast',
10
+ mixins: [],
11
+ props: {
12
+ compromise: {
13
+ type: Boolean,
14
+ default: false
15
+ }
16
+ },
17
+ data: function() {
18
+ return {
19
+ busyQ: []
20
+ }
21
+ },
22
+ computed: {
23
+ pending() {
24
+ return this.busyQ.length > 0
25
+ }
26
+ },
27
+ mounted: function() {
28
+ this.$nextTick(() => document.body.appendChild(this.$el))
29
+ },
30
+ methods: {
31
+ render({ msg, fn }) {
32
+ const that = this
33
+ const $toastBox = that.$refs['toast-box']
34
+ const $toast = document.createElement('div')
35
+ const $toastItem = document.createElement('div')
36
+ $toast.classList.add('toast')
37
+ $toastItem.classList.add('toast-item')
38
+ $toastItem.innerText = msg
39
+ $toastItem.addEventListener('animationend', onanimationend($toast, fn))
40
+ $toastItem.addEventListener('webkitAnimationend', onanimationend($toast, fn))
41
+ $toast.appendChild($toastItem)
42
+ $toastBox.appendChild($toast)
43
+ $toastItem.classList.add('fade-in-out')
44
+ this.busyQ.push(1)
45
+ /* 部分手机机型没有animationend事件,所以用setTimeout做兼容 */
46
+ setTimeout(onanimationend($toast, fn), 2516)
47
+ function onanimationend($t, fn) {
48
+ return function() {
49
+ try {
50
+ $toastBox.removeChild($t)
51
+ that.busyQ.pop()
52
+ that.compromise && !that.pending && typeof fn === 'function' && fn()
53
+ } catch (e) {
54
+ console.log(e)
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ </script>
62
+ <style lang="stylus" rel="stylesheet/stylus" type="text/stylus">
63
+ .component.toast-box .toast {
64
+ position: fixed;
65
+ left: 50%;
66
+ top: 45%;
67
+ width: 80%;
68
+ transform: translate3D(-50%, -50%, 0);
69
+ word-wrap: break-word;
70
+ text-align: center;
71
+ z-index: 1000;
72
+
73
+ .toast-item {
74
+ position: relative;
75
+ display: inline-block;
76
+ opacity: 0;
77
+ padding: 8px 16px;
78
+ font-size: 14px;
79
+ line-height: 1;
80
+ line-height: 1.5;
81
+ border-radius: 3px;
82
+ background-color: rgba(51, 51, 51, 0.9);
83
+ color: #FFFFFF;
84
+ max-width: 100%;
85
+ }
86
+
87
+ .fade-in-out {
88
+ animation: fade-in-out 2.5s linear forwards;
89
+ }
90
+
91
+ @keyframes fade-in-out {
92
+ 0% {
93
+ opacity: 0;
94
+ }
95
+
96
+ 25% {
97
+ opacity: 1;
98
+ }
99
+
100
+ 75% {
101
+ opacity: 1;
102
+ }
103
+
104
+ 100% {
105
+ opacity: 0;
106
+ }
107
+ }
108
+ }
109
+ </style>
110
+
111
+
@@ -0,0 +1,22 @@
1
+ import './lib'
2
+ import Vue from 'vue'
3
+ import App from './app'
4
+ import VueDrag from 'vue-draggable-resizable'
5
+ import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
6
+ import ElementUI from 'element-ui'
7
+ import 'element-ui/lib/theme-chalk/index.css'
8
+ import AttrComponent from './attr'
9
+
10
+ window.Vue = Vue
11
+
12
+ Vue.use(ElementUI)
13
+
14
+ delete Vue.prototype.$confirm
15
+ delete Vue.prototype.$alert
16
+ delete Vue.prototype.$prompt
17
+ delete Vue.prototype.$loading
18
+
19
+ Vue.use(AttrComponent)
20
+ Vue.component('VueDrag', VueDrag)
21
+
22
+ new Vue(App).$mount('#app')
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
6
+ <title>组件预览</title>
7
+ <link href="https://res.cdn.changbaimg.com/!/normalize/7.0.0/normalize.min.css" rel="stylesheet">
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script src="https://res.cdn.changbaimg.com/!/babel-polyfill/6.26.0/polyfill.min.js"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,46 @@
1
+ import { getFingerPrint } from './Util'
2
+
3
+ let config = require('../config/index')
4
+ let ES_LOG_URL = `${config.API_PATH}statistics/report?`
5
+
6
+ async function track ({action, app_id, page_id, label}, noFingerprint) { // eslint-disable-line
7
+ var arg = arguments[0] || {}
8
+ if (!arg || typeof arg !== 'object') return
9
+ // if (!track.img) track.img = new Image()
10
+ var server = new Image()
11
+ if (!noFingerprint) {
12
+ try {
13
+ arg.finger_print = await getFingerPrint().then((res) => {
14
+ console.log(res)
15
+ return res
16
+ })
17
+ } catch (e) {
18
+ arg.finger_print = 'unknown'
19
+ console.warn(e)
20
+ }
21
+ }
22
+ server.src = ES_LOG_URL + serializeParmas(arg) // 除argements列出字段外,可传入自定义字段
23
+ }
24
+
25
+ function serializeParmas(obj) {
26
+ obj._t = Date.now() // 时间戳防止缓存
27
+ return Object.keys(obj).map(k => `${k}=${encodeURIComponent(obj[k])}`).join('&')
28
+ }
29
+
30
+ function pageview ({app_id, page_id, label}) { // eslint-disable-line
31
+ var arg = arguments[0]
32
+ if (!arg || typeof arg !== 'object') return
33
+ track(Object.assign(arg, {action: 'pageview'}))
34
+ }
35
+
36
+ export default {
37
+ pageview,
38
+ getFingerPrint,
39
+ track
40
+ }
41
+
42
+ export {
43
+ pageview,
44
+ track,
45
+ getFingerPrint,
46
+ }
@@ -0,0 +1,57 @@
1
+ function loadJs (url = '') {
2
+ if (!url) return
3
+ if (!loadJs.cache) loadJs.cache = {}
4
+ if (loadJs.cache[url]) return Promise.resolve()
5
+ return new Promise((resolve, reject) => {
6
+ _loadjs(
7
+ url,
8
+ () => {
9
+ loadJs.cache[url] = 'cached'
10
+ resolve()
11
+ },
12
+ () => {
13
+ console.error(`${url} 加载失败`)
14
+ reject(new Error(`${url} 加载失败`))
15
+ }
16
+ )
17
+ })
18
+
19
+ function _loadjs (url, fn, fail) {
20
+ var script = document.createElement('script')
21
+ script.src = url
22
+ script.async = true
23
+ script.onload = fn
24
+ script.onerror = fail
25
+ ;(document.body || document.head).appendChild(script)
26
+ }
27
+ }
28
+
29
+ var FINGER_PRINT_URL = 'https://cdn.staticfile.org/fingerprintjs2/1.8.0/fingerprint2.min.js'
30
+ var STORAGE_KEY = 'YMMFP'
31
+
32
+ function getFingerPrint () {
33
+ if (!getFingerPrint.promise) {
34
+ getFingerPrint.promise = new Promise((resolve) => {
35
+ var fingerPrint = localStorage.getItem(STORAGE_KEY)
36
+ if (fingerPrint) return resolve(fingerPrint)
37
+ loadJs(FINGER_PRINT_URL).then(() => {
38
+ if (!window.Fingerprint2) resolve('unknown')
39
+ window.Fingerprint2 && new window.Fingerprint2().get((res) => {
40
+ localStorage.setItem(STORAGE_KEY, res)
41
+ resolve(res)
42
+ })
43
+ })
44
+ })
45
+ }
46
+ return getFingerPrint.promise
47
+ }
48
+
49
+ export default {
50
+ loadJs,
51
+ getFingerPrint
52
+ }
53
+
54
+ export {
55
+ loadJs,
56
+ getFingerPrint
57
+ }
@@ -0,0 +1,139 @@
1
+ import axios from 'axios'
2
+ import qs from 'qs'
3
+
4
+ const getQueryStr = function(name, url) {
5
+ name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]')
6
+ if (!url) {
7
+ url = window.location.href
8
+ }
9
+ const _regexS = '[\\?&]' + name + '=([^&#]*)'
10
+ const _regex = new RegExp(_regexS)
11
+ const _results = _regex.exec(url)
12
+
13
+ if (_results == null) {
14
+ return ''
15
+ } else {
16
+ return decodeURIComponent(_results[1].replace(/\+/g, ' '))
17
+ }
18
+ }
19
+
20
+ const userId = getQueryStr('curuserid')
21
+ const token = getQueryStr('token')
22
+
23
+ // 创建axios实例
24
+ const instance = axios.create({
25
+ timeout: 30000,
26
+ headers: {
27
+ 'X-Requested-With': 'XMLHttpRequest'
28
+ },
29
+ transformRequest: [function(data, headers) {
30
+ if (data instanceof FormData) {
31
+ return data
32
+ }
33
+
34
+ if (data?.__json__ === true) {
35
+ headers['Content-Type'] = 'application/json; charset=utf-8'
36
+ data.__json__ = undefined
37
+
38
+ return JSON.stringify(data)
39
+ }
40
+
41
+ return qs.stringify(data)
42
+ }]
43
+ })
44
+
45
+ // request拦截器
46
+ instance.interceptors.request.use(config => {
47
+ if (config.method === 'get') {
48
+ config.params = config.data
49
+ }
50
+
51
+ return config
52
+ }, error => {
53
+ // Do something with request error
54
+ console.log(error) // for debug
55
+ Promise.reject(error)
56
+ })
57
+
58
+ export function fetch(url, inputOptions = {}) {
59
+ const options = { ...inputOptions }
60
+
61
+ if (!options.method) {
62
+ options.method = 'get'
63
+ }
64
+
65
+ if (options.upload === true) {
66
+ const fd = new FormData()
67
+
68
+ options.data.userid = userId
69
+ options.data.token = token
70
+
71
+ for (const key in options.data) {
72
+ if (Object.prototype.hasOwnProperty.call(options.data, key)) {
73
+ const value = options.data[key]
74
+
75
+ if (value === undefined) {
76
+ continue
77
+ }
78
+
79
+ if (Array.isArray(value)) {
80
+ value.forEach((item) => {
81
+ fd.append(`${key}[]`, item)
82
+ })
83
+ } else {
84
+ fd.append(key, value)
85
+ }
86
+ }
87
+ }
88
+
89
+ options.data = fd
90
+ } else if (options.method === 'post' && options.json === true) {
91
+ if (options.data) {
92
+ options.data.__json__ = true
93
+ }
94
+ }
95
+
96
+ if (!options.data) {
97
+ options.data = {}
98
+ }
99
+
100
+ if (options.method.toLowerCase() === 'get' && options.cache !== true) {
101
+ options.data._ = String(+new Date()) + String(Math.floor(Math.random() * 9999))
102
+ }
103
+
104
+ if (!options.data.userid) {
105
+ options.data.userid = userId
106
+ }
107
+ if (!options.data.token) {
108
+ options.data.token = token
109
+ }
110
+
111
+ if (!options.onUploadProgress && options.onUploadPercent) {
112
+ options.onUploadProgress = (progressEvent) => {
113
+ if (progressEvent.lengthComputable) {
114
+ options.onUploadPercent(Math.floor((progressEvent.loaded / progressEvent.total) * 100), progressEvent)
115
+ }
116
+ }
117
+ }
118
+
119
+ return instance(url, options)
120
+ .then((response) => {
121
+ let data = response.data
122
+
123
+ if (!data) {
124
+ data = {}
125
+ }
126
+
127
+ data.$response = response
128
+
129
+ return data
130
+ })
131
+ .catch((error) => {
132
+ return {
133
+ code: 99999,
134
+ data: {},
135
+ msg: error.msg,
136
+ $response: error
137
+ }
138
+ })
139
+ };
@@ -0,0 +1,15 @@
1
+ import VueExtend from './vue'
2
+ import {fetch} from './fetch'
3
+ import Util from './Util'
4
+
5
+ function empty () {}
6
+
7
+ window.$GP = {
8
+ Util,
9
+ VueExtend,
10
+ ESlog: {pageview: empty, track: empty, getFingerPrint: empty},
11
+ Server: {fetch},
12
+ Env: {
13
+ mode: 'development'
14
+ }
15
+ }
@@ -0,0 +1,53 @@
1
+ Date.prototype.Format = function (fmt) { // author: meizz
2
+ var o = {
3
+ 'M+': this.getMonth() + 1, // 月份
4
+ 'd+': this.getDate(), // 日
5
+ 'h+': this.getHours(), // 小时
6
+ 'm+': this.getMinutes(), // 分
7
+ 's+': this.getSeconds(), // 秒
8
+ 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
9
+ 'S': this.getMilliseconds() // 毫秒
10
+ }
11
+ if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
12
+ for (var k in o) {
13
+ if (new RegExp('(' + k + ')').test(fmt)) {
14
+ fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
15
+ }
16
+ }
17
+ return fmt
18
+ }
19
+
20
+ export default {
21
+ datetime: function (value, format) {
22
+ if (!value) return ''
23
+ return (new Date(+value)).Format(format || 'yyyy-MM-dd hh:mm')
24
+ },
25
+ moneyFormat: function (value, decimal) {
26
+ value = value / 100 // 转换为元
27
+ decimal = decimal || 2
28
+ return isNaN(value) ? 0 : +(value.toFixed(decimal))
29
+ },
30
+ strSplit: function (str, interval, split) {
31
+ split = split || ' '
32
+ str = str.replace(/\s+/g, '')
33
+ interval = toString.call(interval) == toString.call([]) ? interval : [Number(interval)]
34
+ var strArr = []
35
+ var reg
36
+ while (1) {
37
+ if (interval && interval.length) {
38
+ reg = new RegExp(`(\\w{${interval.shift()}}(?!(?:\\s|$)))(.*)`)
39
+ }
40
+ var items = str.match(reg)
41
+ if (!items) {
42
+ strArr.push(str)
43
+ break
44
+ }
45
+ strArr.push(items[1])
46
+ str = items[2]
47
+ }
48
+ return strArr.join(split)
49
+ },
50
+ replace: function (value, pattern, target) {
51
+ return (value || '').replace(pattern, target)
52
+ }
53
+ }
@@ -0,0 +1,9 @@
1
+ import mixin from './mixin'
2
+
3
+ export {
4
+ mixin
5
+ }
6
+
7
+ export default {
8
+ mixin
9
+ }
@@ -0,0 +1,166 @@
1
+ import filters from './filters'
2
+
3
+ const mixin = {
4
+ props: [],
5
+ data: function () {
6
+ return {
7
+ inscope: null
8
+ }
9
+ },
10
+ computed: {
11
+ scope() {
12
+ let data = this.inscope && this.inscope.data ? this.inscope.data : this.inscope
13
+ return data
14
+ }
15
+ },
16
+ filters,
17
+ methods: {
18
+ // 函数调用
19
+ oncallExecute: function (params, args = []) {
20
+ if (!params) return
21
+ if (typeof params === 'function') {
22
+ params = [{
23
+ method: params,
24
+ params: args
25
+ }]
26
+ params.forEach(element => {
27
+ element = element || {}
28
+ // 分割字符串参数为数组
29
+ let name = element.method
30
+ let data = [...element.params, ...args]
31
+ if (typeof this[name] === 'function') {
32
+ this[name].apply(this, data)
33
+ }
34
+ })
35
+ } else {
36
+ params.forEach(element => {
37
+ element = element || {}
38
+ // 分割字符串参数为数组 方法可能是 truck/imagehq.jump 这个样式
39
+ if (element.method) {
40
+ let info = element.method.split('.')
41
+ let target = this
42
+ let name = ''
43
+ if (info.length == 1) {
44
+ name = info[0]
45
+ } else if (info.length == 2) {
46
+ target = this.$parent.getComponent(info[0], true)
47
+ name = info[1]
48
+ }
49
+ var data = [...element.params, ...args]
50
+ if (typeof target[name] === 'function') {
51
+ target[name].apply(target, data)
52
+ }
53
+ }
54
+ })
55
+ }
56
+ },
57
+ /**
58
+ * 属性解析
59
+ * 从datahub或者父组件传入数据获取数据
60
+ */
61
+ scopeGet: function (prop) {
62
+ let text = this[prop] || ''
63
+ // 编辑环境
64
+ if (window.EDIT_TYPE == 'EDITOR') {
65
+ return this[prop] || this.$options.props[prop]['default']
66
+ }
67
+ // 预览/运行环境
68
+ // 占位编译
69
+ if (typeof text === 'string') {
70
+ text = text.replace(/\$\{([^{}]+)\}/g, (m, p) => {
71
+ p = p.replace(/\s+/g, '').split('|')
72
+ var val = p[0]
73
+ var filters = p.slice(1)
74
+ var isValue = true // 是否是值(非表达式)
75
+ // 值
76
+ try {
77
+ val = eval(p[0])
78
+ isValue = true
79
+ } catch (e) {
80
+ val = p[0]
81
+ isValue = false
82
+ }
83
+ // 非值
84
+ if (!isValue) {
85
+ if (/^\$scope\./.test(val)) {
86
+ // 由父节点传入数据 如列表容器
87
+ val = (this.scope && baseGet(this.scope, val)) || ''
88
+ } else {
89
+ // 由数据总线获取数据
90
+ val = this.dataHubGet && this.dataHubGet(val) || ''
91
+ }
92
+ }
93
+ // 过滤器
94
+ if (filters && filters.length) {
95
+ val = filters.reduce((a, b) => {
96
+ return evalFilter(b, a, this)
97
+ }, val)
98
+ }
99
+ return val
100
+ })
101
+ }
102
+
103
+ // 计算值 || 默认值
104
+ return text || this.$options.props[prop]['default']
105
+
106
+ function baseGet(target = {}, path = '') {
107
+ path = String(path).trim().replace(/^\$scope\./, '')
108
+ var val
109
+ try {
110
+ val = path.split('.').reduce((a, b) => a && a[b], target)
111
+ } catch (e) {
112
+ console.error(e)
113
+ }
114
+ return val
115
+ }
116
+
117
+ function evalFilter(fnstr, val, context) {
118
+ var parms = fnstr.match(/^([_$0-9A-Za-z]+)\(([^()]+)\)$/) || ['', fnstr]
119
+ var fn = parms[1]
120
+ var args = [val]
121
+ try {
122
+ args = args.concat(eval(`[${parms[2]}]`))
123
+ } catch (e) {
124
+ console.log(e)
125
+ }
126
+ var filterFn = context.$options.filters && context.$options.filters[fn]
127
+ if (typeof filterFn == 'function') {
128
+ return filterFn.apply(context, args)
129
+ }
130
+ return fnstr
131
+ }
132
+ },
133
+ }
134
+ }
135
+
136
+ if (window.EDIT_TYPE === undefined || window.EDIT_TYPE === null) {
137
+ var services = {
138
+ $toast: function () {
139
+ window.toast && window.toast.apply(window, arguments)
140
+ },
141
+ $confirm: function () {
142
+ window.confirm && window.confirm.apply(window, arguments)
143
+ },
144
+ $alert: function () {
145
+ window.alert && window.alert.apply(window, arguments)
146
+ },
147
+ $msgBox: function () {
148
+ window.msgBox && window.msgBox.apply(window, arguments)
149
+ },
150
+ $prompt: function () {
151
+ window.prompt && window.prompt.apply(window, arguments)
152
+ },
153
+ $loading: function () {
154
+ window.loading && window.loading()
155
+ },
156
+ $hideLoading: function () {
157
+ window.hideLoading ? window.hideLoading() : window.loading && window.loading(1)
158
+ },
159
+ $viewImg: function () {
160
+ window.viewImg && window.viewImg.apply(window, arguments)
161
+ }
162
+ }
163
+ Object.assign(mixin.methods, services)
164
+ }
165
+
166
+ export default mixin