Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
quantum-blocks-h5
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ui
quantum-blocks-h5
Commits
c7027cf3
Commit
c7027cf3
authored
Mar 05, 2021
by
郝聪敏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feature: 优化
parent
67a5e0c2
Changes
44
Show whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
923 additions
and
4371 deletions
+923
-4371
editor.api.ts
app/web/api/editor.api.ts
+1
-2
operation.api.ts
app/web/api/operation.api.ts
+0
-175
index.ts
app/web/component/layout/activity/index.ts
+1
-0
index.vue
app/web/component/layout/activity/index.vue
+2
-1
dev.config.ts
app/web/config/dev.config.ts
+3
-4
http.config.ts
app/web/config/http.config.ts
+96
-0
prod.config.ts
app/web/config/prod.config.ts
+1
-2
test.config.ts
app/web/config/test.config.ts
+2
-3
app.ts
app/web/framework/app.ts
+6
-0
index.vue
app/web/lib/Advertisement/index.vue
+0
-44
coupon-bg@2x.png
app/web/lib/Coupon/images/coupon-bg@2x.png
+0
-0
index.vue
app/web/lib/Coupon/index.vue
+0
-244
close@2x.png
app/web/lib/DownloadGuide/images/close@2x.png
+0
-0
xyqb@2x.png
app/web/lib/DownloadGuide/images/xyqb@2x.png
+0
-0
index.vue
app/web/lib/DownloadGuide/index.vue
+0
-60
api.ts
app/web/lib/Form/api/api.ts
+0
-49
close@2x.png
app/web/lib/Form/images/close@2x.png
+0
-0
landing-bg.png
app/web/lib/Form/images/landing-bg.png
+0
-0
landing-des.png
app/web/lib/Form/images/landing-des.png
+0
-0
landing-submit.png
app/web/lib/Form/images/landing-submit.png
+0
-0
xyqb@2x.png
app/web/lib/Form/images/xyqb@2x.png
+0
-0
index.vue
app/web/lib/Form/index.vue
+0
-339
jy.less
app/web/lib/Form/jy/jy.less
+0
-132
jy.ts
app/web/lib/Form/jy/jy.ts
+0
-277
shopping-cart@2x.png
app/web/lib/Goods/images/shopping-cart@2x.png
+0
-0
special-recommend.png
app/web/lib/Goods/images/special-recommend.png
+0
-0
index.vue
app/web/lib/Goods/index.vue
+0
-258
index.vue
app/web/lib/GoodsTabs/index.vue
+0
-95
index.vue
app/web/lib/GuideCube/index.vue
+0
-174
index.vue
app/web/lib/Marquee/index.vue
+0
-106
index.vue
app/web/lib/Placeholder/index.vue
+0
-22
config.ts
app/web/lib/config.ts
+642
-641
index.ts
app/web/page/activity/component/FreedomContainer/index.ts
+1
-2
index.ts
app/web/page/activity/view/activity/index.ts
+2
-8
index.ts
app/web/page/store/modules/activity/index.ts
+1
-1
eventBus.service.ts
app/web/service/eventBus.service.ts
+0
-2
http.service.ts
app/web/service/http.service.ts
+65
-88
init.service.ts
app/web/service/init.service.ts
+30
-0
qg.service.ts
app/web/service/qg.service.ts
+2
-1
qiniu.service.ts
app/web/service/qiniu.service.ts
+0
-1637
sa.service.ts
app/web/service/sa.service.ts
+44
-0
utils.service.ts
app/web/service/utils.service.ts
+17
-0
package.json
package.json
+4
-4
webpack.config.js
webpack.config.js
+3
-0
No files found.
app/web/api/editor.api.ts
View file @
c7027cf3
import
http
from
'
../service/http.service
'
;
import
http
from
'
../service/http.service
'
;
import
config
from
'
../config
'
;
import
config
from
'
../config
'
;
import
axios
from
'
axios
'
;
export
default
{
export
default
{
getPageById
(
params
)
{
getPageById
(
params
)
{
return
http
.
get
(
`editor/get/
${
params
.
pageId
}
`
);
return
http
.
get
(
`
${
config
.
apiHost
}
editor/get/
${
params
.
pageId
}
`
);
}
}
};
};
\ No newline at end of file
app/web/api/operation.api.ts
deleted
100644 → 0
View file @
67a5e0c2
import
http
from
'
../service/http.service
'
;
import
config
from
'
../config
'
;
export
default
{
// 商品列表-查询
skuInfo
(
params
)
{
return
http
.
post
(
`
${
config
.
opapiHost
}
/kdspOp/api/kdsp/activity/activity-goods/sku-info/list`
,
params
,
{
accessToken
:
true
});
},
// 获取商品类目
categoryQuery
()
{
return
http
.
get
(
`
${
config
.
opapiHost
}
/kdspOp/api/kdsp/op/rear-category/query/all`
,
{
accessToken
:
true
});
},
// 优惠券搜索列表
couponList
(
params
)
{
return
http
.
post
(
`
${
config
.
opapiHost
}
/kdspOp/api/kdsp/op/coupon/list`
,
params
,
{
accessToken
:
true
});
},
// 商品管理-商品专题列表_分页
specialPage
(
params
)
{
return
http
.
post
(
`
${
config
.
opapiHost
}
/kdspOp/api/kdsp/activity/activity-goods/special/list-page`
,
params
,
{
accessToken
:
true
});
},
// todo: 对外接口需提供x-auth-token
// 购物车-添加商品
addShopCart
(
params
)
{
return
http
.
post
(
`
${
config
.
kdspHost
}
/api/kdsp/shop-cart/add-update`
,
params
);
},
// 商品组或专题查询
getGoods
(
params
)
{
// return http.post(`${config.kdspHost}/api/kdsp/activity/activity-goods-special/skus`, params);
return
{
skus
:
[
{
skuNo
:
'
100014565800
'
,
skuName
:
'
【自营】【自营】小米手机 陶瓷黑 8GB+128GB 官方标配
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
2.85
,
marketPrice
:
293
},
{
skuNo
:
'
100014565820
'
,
skuName
:
'
【自营】[自营][自营]0
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
264
,
marketPrice
:
300
},
{
skuNo
:
'
100014565820
'
,
skuName
:
'
【自营】[自营][自营]0
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
264
,
marketPrice
:
300
},
{
skuNo
:
'
100014565800
'
,
skuName
:
'
【自营】【自营】小米手机 陶瓷黑 8GB+128GB 官方标配
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
2.85
,
marketPrice
:
293
},
{
skuNo
:
'
100014565820
'
,
skuName
:
'
【自营】[自营][自营]0
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
264
,
marketPrice
:
300
},
{
skuNo
:
'
100014565820
'
,
skuName
:
'
【自营】[自营][自营]0
'
,
skuUrl
:
'
https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
'
,
salePrice
:
264
,
marketPrice
:
300
}
]
};
},
// 根据id查询优惠券列表
getCoupons
(
params
)
{
// return http.post(`${config.kdspHost}/api/kdsp/coupon/list`, params, {
// hideToken: true,
// headers: {
// 'x-auth-token': '97466ed6-ec03-452e-be8f-763a8ffafefe'
// }
// });
return
{
coupons
:
[
{
id
:
1
,
pickupId
:
1
,
name
:
'
3C数码会场
'
,
startDate
:
'
2021-02-22
'
,
endDate
:
'
2021-02-22
'
,
faceValue
:
100
,
limitAmount
:
300
,
limitDesc
:
'
满300减100
'
,
couponCategory
:
1
,
iconUrl
:
'
in esse
'
,
description
:
'
officia do
'
,
status
:
19667180
,
navUrl
:
'
exercitation est
'
,
pickupAble
:
false
,
publishCountFinished
:
false
},
{
id
:
2
,
pickupId
:
1
,
name
:
'
3C数码会场
'
,
startDate
:
'
2021-02-22
'
,
endDate
:
'
2021-02-22
'
,
faceValue
:
100
,
limitAmount
:
300
,
limitDesc
:
'
满300减100
'
,
couponCategory
:
1
,
iconUrl
:
'
oc
'
,
description
:
'
minim dolore tempor
'
,
status
:
63205995
,
navUrl
:
'
cupidat
'
,
pickupAble
:
true
,
publishCountFinished
:
false
},
{
id
:
3
,
pickupId
:
1
,
name
:
'
3C数码会场
'
,
startDate
:
'
2021-02-22
'
,
endDate
:
'
2021-02-22
'
,
faceValue
:
100
,
limitAmount
:
300
,
limitDesc
:
'
满300减100
'
,
couponCategory
:
1
,
iconUrl
:
'
eu fugiat commodo voluptate exercitation
'
,
description
:
'
nisi
'
,
status
:
43999314
,
navUrl
:
'
commodo in reprehenderit
'
,
pickupAble
:
false
,
publishCountFinished
:
true
},
{
id
:
4
,
pickupId
:
1
,
name
:
'
3C数码会场
'
,
startDate
:
'
2021-02-22
'
,
endDate
:
'
2021-02-22
'
,
faceValue
:
100
,
limitAmount
:
300
,
limitDesc
:
'
满300减100
'
,
couponCategory
:
1
,
iconUrl
:
'
eu fugiat commodo voluptate exercitation
'
,
description
:
'
nisi
'
,
status
:
43999314
,
navUrl
:
'
commodo in reprehenderit
'
,
pickupAble
:
false
,
publishCountFinished
:
true
}
]
};
},
// 领取优惠券
pickupCoupon
(
params
)
{
return
http
.
post
(
`
${
config
.
kdspHost
}
/api/kdsp/coupon/pickup`
,
params
,
{
// todo: header里二者参数需特殊处理
headers
:
{
'
x-user-terminal
'
:
'
H5
'
,
'
vccChannel
'
:
''
,
}
});
},
};
\ No newline at end of file
app/web/component/layout/activity/index.ts
View file @
c7027cf3
...
@@ -23,6 +23,7 @@ export default class Layout extends Vue {
...
@@ -23,6 +23,7 @@ export default class Layout extends Vue {
@
Prop
({
type
:
String
,
default
:
'
Vue,TypeScript,Isomorphic
'
})
keywords
?:
string
;
@
Prop
({
type
:
String
,
default
:
'
Vue,TypeScript,Isomorphic
'
})
keywords
?:
string
;
isNode
:
boolean
=
EASY_ENV_IS_NODE
;
isNode
:
boolean
=
EASY_ENV_IS_NODE
;
scriptSrc
:
string
=
`<script src="https://activitystatic.lkbang.net/sa-sdk-javascript/1.15.16/sensorsdata.min.js"></script>`
;
created
()
{
created
()
{
console
.
log
(
'
>>EASY_ENV_IS_NODE create
'
,
EASY_ENV_IS_NODE
);
console
.
log
(
'
>>EASY_ENV_IS_NODE create
'
,
EASY_ENV_IS_NODE
);
...
...
app/web/component/layout/activity/index.vue
View file @
c7027cf3
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
</head>
</head>
<body>
<body>
<div
id=
"app"
><slot></slot></div>
<div
id=
"app"
><slot></slot></div>
<template
v-html=
"scriptSrc"
></
template
>
</body>
</body>
</html>
</html>
<div
v-else-if=
"!isNode"
id=
"app"
><slot></slot></div>
<div
v-else-if=
"!isNode"
id=
"app"
><slot></slot></div>
...
...
app/web/config/dev.config.ts
View file @
c7027cf3
const
protocol
=
EASY_ENV_IS_BROWSER
?
window
.
location
.
protocol
:
'
http
'
;
const
protocol
=
EASY_ENV_IS_BROWSER
?
window
.
location
.
protocol
:
'
http
'
;
export
default
{
export
default
{
apiHost
:
`http://localhost:7002/`
,
//
apiHost: `http://localhost:7002/`,
// apiHost: `http://192.168.28.199:7001/`,
// apiHost: `http://192.168.28.199:7001/`,
// apiHost: 'https://quantum-vcc2.liangkebang.net/',
apiHost
:
'
https://quantum-blocks-vcc2.liangkebang.net/
'
,
qiniuHost
:
`https://appsync.lkbang.net/`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=default`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=default`
,
opapiHost
:
`https://opapi-vcc2.liangkebang.net`
,
opapiHost
:
`https://opapi-vcc2.liangkebang.net`
,
qiniuUpHost
:
`
${
protocol
}
//up-z0.qiniup.com`
,
kdspHost
:
'
https://kdsp-api-vcc2.liangkebang.net
'
,
kdspHost
:
'
https://kdsp-api-vcc2.liangkebang.net
'
,
test
:
true
};
};
app/web/config/http.config.ts
0 → 100644
View file @
c7027cf3
// tslint:disable
import
{
isAndroid
,
isIOS
,
isWechat
}
from
'
@/service/utils.service
'
;
import
localStorage
from
'
@/service/localStorage.service
'
;
import
Toast
from
'
@qg/cherry-ui/src/toast
'
;
function
getURLSearchParams
(
json
)
{
if
(
!
json
)
return
''
;
const
dataArray
=
Object
.
keys
(
json
).
map
(
key
=>
{
if
(
json
[
key
]
===
undefined
)
return
''
;
return
encodeURIComponent
(
key
)
+
'
=
'
+
encodeURIComponent
(
json
[
key
]);
});
return
dataArray
.
filter
(
item
=>
item
!==
undefined
&&
item
!==
null
).
join
(
'
&
'
);
}
function
getVccChannel
()
{
return
isWechat
?
localStorage
.
get
(
'
vccChannel
'
)
||
''
:
(
isAndroid
?
'
159905
'
:
isIOS
?
'
159904
'
:
localStorage
.
get
(
'
vccChannel
'
))
||
''
;
}
export
default
{
service
:
{
response
(
res
)
{
const
{
data
,
config
}
=
res
;
// api需要返回原始响应
const
returnRawData
=
config
.
rawData
;
if
(
returnRawData
)
return
[
data
,
null
];
const
success
=
(
data
.
code
===
0
&&
data
.
business_code
===
0
)
||
(
data
.
code
===
'
0000
'
&&
data
.
businessCode
===
'
0000
'
);
// 业务完成,返回有效载荷
if
(
success
)
{
return
[
data
.
data
,
null
];
}
// 接下来处理异常业务
const
msg
=
data
.
msg
||
'
服务异常
'
;
if
(
!
config
.
hideToast
||
!
data
.
noAlert
)
{
Toast
(
msg
);
}
// 给用户提示信息,明确发生错误
// 请求参数和响应数据都可以控制不提示
const
error
=
new
Error
(
msg
);
error
.
response
=
data
;
console
.
error
(
error
);
// 业务代码可以根据response进行再处理
return
[
null
,
error
];
},
request
(
cfg
)
{
const
{
method
,
hideVccChannel
}
=
cfg
;
cfg
.
headers
[
'
X-Auth-Token
'
]
=
localStorage
.
get
(
'
vccToken
'
)
||
''
;
if
(
cfg
.
customHeader
)
{
Object
.
assign
(
cfg
.
headers
,
cfg
.
customHeader
);
}
if
(
cfg
.
creditToken
)
{
cfg
.
headers
[
'
X-Auth-Token
'
]
=
localStorage
.
get
(
'
creditToken
'
);
}
if
(
!
hideVccChannel
)
{
cfg
.
headers
[
'
vccChannel
'
]
=
getVccChannel
();
}
if
(
method
===
'
post
'
&&
cfg
.
emulateJSON
)
{
cfg
.
headers
[
'
Content-Type
'
]
=
'
application/x-www-form-urlencoded
'
;
cfg
.
data
=
getURLSearchParams
(
cfg
.
data
);
}
return
cfg
;
}
}
// unique: {
// response(res) {
// const { data, config } = res;
// if (data.code === 0) {
// return [data.data, null];
// }
// if (!config.hideToast) {
// Toast(data.msg);
// }
// let error = new Error(data.msg);
// error.response = data;
// console.error(error);
// return [null, error];
// },
// request(cfg) {
// const { method } = cfg;
// cfg.headers['X-Auth-Token'] = localStorage.get('vccToken') || '';
// if (cfg.creditToken) {
// cfg.headers['X-Auth-Token'] = localStorage.get('creditToken');
// }
// cfg.headers['vccChannel'] = getVccChannel();
// if (method === 'post' && cfg.emulateJSON) {
// cfg.headers['Content-Type'] = 'application/x-www-form-urlencoded';
// cfg.data = getURLSearchParams(cfg.data);
// }
// return cfg;
// }
// }
};
app/web/config/prod.config.ts
View file @
c7027cf3
...
@@ -2,8 +2,7 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'https';
...
@@ -2,8 +2,7 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'https';
export
default
{
export
default
{
apiHost
:
`https://quantum-blocks.q-gp.com/`
,
apiHost
:
`https://quantum-blocks.q-gp.com/`
,
qiniuHost
:
`https://appsync.lkbang.net/`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=production`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=production`
,
opapiHost
:
`
${
protocol
}
//opapi.q-gp.com`
,
opapiHost
:
`
${
protocol
}
//opapi.q-gp.com`
,
qiniuUpHost
:
`
${
protocol
}
//up-z0.qiniup.com`
,
test
:
false
};
};
app/web/config/test.config.ts
View file @
c7027cf3
...
@@ -3,7 +3,6 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'https';
...
@@ -3,7 +3,6 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'https';
export
default
{
export
default
{
apiHost
:
`https://quantum-blocks-vcc2.liangkebang.net/`
,
apiHost
:
`https://quantum-blocks-vcc2.liangkebang.net/`
,
opApiHost
:
'
https://opapi-vcc2.liangkebang.net
'
,
opApiHost
:
'
https://opapi-vcc2.liangkebang.net
'
,
qiniuHost
:
`https://appsync.lkbang.net/`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=default`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=production`
,
test
:
true
qiniuUpHost
:
`
${
protocol
}
//up-z0.qiniup.com`
,
};
};
app/web/framework/app.ts
View file @
c7027cf3
import
Vue
from
'
vue
'
;
import
Vue
from
'
vue
'
;
import
{
sync
}
from
'
vuex-router-sync
'
;
import
{
sync
}
from
'
vuex-router-sync
'
;
import
initService
from
'
@/service/init.service
'
;
export
default
class
App
{
export
default
class
App
{
config
:
any
;
config
:
any
;
...
@@ -21,6 +22,11 @@ export default class App {
...
@@ -21,6 +22,11 @@ export default class App {
const
store
=
createStore
(
initState
);
const
store
=
createStore
(
initState
);
const
router
=
createRouter
();
const
router
=
createRouter
();
sync
(
store
,
router
);
sync
(
store
,
router
);
if
(
EASY_ENV_IS_BROWSER
)
{
const
{
initSa
}
=
require
(
'
@/service/sa.service
'
);
initService
.
init
(
router
);
initSa
(
router
);
}
return
{
return
{
router
,
router
,
store
,
store
,
...
...
app/web/lib/Advertisement/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
:class=
"['ad',
{ 'ad_one': column === 1, 'ad_two': column === 2, 'ad_three': column === 3 }]">
<a
:href=
"item.link"
v-for=
"(item, index) in list"
:key=
"index"
>
<cr-image
:src=
"item.img"
height=
"2.61rem"
width=
"100%"
></cr-image>
</a>
</div>
</
template
>
<
script
>
export
default
{
props
:
{
column
:
{
type
:
Number
,
default
:
2
},
list
:
{
type
:
Array
,
default
:
()
=>
([])
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.image-width(@width) {
a {
width: @width;
}
}
.ad {
display: flex;
justify-content: space-between;
margin: 0 12px;
&_one {
.image-width(100%);
}
&_two {
.image-width(49%);
}
&_three {
.image-width(32%);
}
}
</
style
>
\ No newline at end of file
app/web/lib/Coupon/images/coupon-bg@2x.png
deleted
100644 → 0
View file @
67a5e0c2
30.7 KB
app/web/lib/Coupon/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"coupon"
v-if=
"column === 1"
>
<div
class=
"coupon-item_one"
:style=
"style"
:key=
"coupon.id"
v-for=
"coupon in couponList"
>
<div
class=
"Gi_one-left"
>
<p>
¥
<span>
{{
coupon
.
faceValue
||
'
-
'
}}
</span></p>
<p>
{{
coupon
.
limitDesc
}}
</p>
</div>
<div
class=
"Gi_one-middle"
>
<p>
{{
coupon
.
name
}}
</p>
<p>
{{
`${coupon.startDate
}
- ${coupon.endDate
}
`
}}
<
/p
>
<
/div
>
<
cr
-
button
class
=
"
Gi_one-right
"
type
=
"
primary
"
@
click
=
"
getCoupon(coupon)
"
>
{{
btnText
(
coupon
.
pickupAble
)
}}
<
/cr-button
>
<
div
class
=
"
coupon-item-mask
"
v
-
if
=
"
!coupon.pickupAble && coupon.publishCountFinished
"
>
<
p
>
已抢空
<
/p
>
<
/div
>
<
/div
>
<
/div
>
<
div
v
-
else
:
class
=
"
['coupon', {'coupon_two': column === 2, 'coupon_multiple': column === 3
}
]
"
>
<
div
class
=
"
coupon-item
"
:
style
=
"
style
"
:
key
=
"
coupon.id
"
v
-
for
=
"
coupon in couponList
"
>
<
p
class
=
"
coupon-item-title
"
>
{{
coupon
.
name
}}
<
/p
>
<
p
class
=
"
coupon-item-amount
"
>
¥
<
span
>
{{
coupon
.
faceValue
||
'
-
'
}}
<
/span></
p
>
<
p
class
=
"
coupon-item-amount
"
>
{{
coupon
.
limitDesc
}}
<
/p
>
<
cr
-
button
shape
=
"
circle
"
type
=
"
primary
"
@
click
=
"
getCoupon(coupon)
"
>
{{
btnText
(
coupon
.
pickupAble
)
}}
<
/cr-button
>
<
div
class
=
"
coupon-item-mask
"
v
-
if
=
"
!coupon.pickupAble && coupon.publishCountFinished
"
>
<
p
>
已抢空
<
/p
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
script
>
import
operationApi
from
'
@api/operation.api
'
;
export
default
{
inject
:
[
'
editor
'
],
props
:
{
couponsList
:
Array
,
couponsNumber
:
Number
,
column
:
{
type
:
Number
,
default
:
3
}
,
bgImage
:
String
,
bgColor
:
{
type
:
String
,
default
:
'
#fff
'
}
}
,
data
()
{
return
{
list
:
[]
}
}
,
computed
:
{
couponList
()
{
if
(
this
.
editor
)
this
.
$nextTick
(()
=>
this
.
editor
.
adjustHeight
());
return
this
.
list
.
slice
(
0
,
this
.
couponsNumber
);
}
,
style
()
{
return
{
background
:
this
.
bgImage
?
`url(${this.bgImage
}
) no-repeat 0 0 / cover`
:
''
,
backgroundColor
:
this
.
bgColor
}
}
}
,
watch
:
{
couponsList
:
{
handler
:
async
function
(
newVal
)
{
const
{
coupons
}
=
await
operationApi
.
getCoupons
({
couponIds
:
newVal
.
join
(
'
,
'
)
}
);
if
(
coupons
&&
coupons
.
length
)
this
.
list
=
coupons
;
// console.log('coupons', this.list);
}
,
immediate
:
true
}
}
,
methods
:
{
async
getCoupon
(
coupon
)
{
if
(
!
coupon
.
pickupAble
)
{
await
operationApi
.
pickupCoupon
({
couponId
:
coupon
.
couponId
}
);
this
.
$toast
.
success
(
'
领取成功
'
);
}
else
{
window
.
location
.
href
=
coupon
.
navUrl
;
}
}
,
btnText
(
pickupAble
)
{
return
pickupAble
?
'
去使用
'
:
'
立即领取
'
;
}
}
}
<
/script
>
<
style
lang
=
"
less
"
scoped
>
::
-
webkit
-
scrollbar
{
display
:
none
;
/* Chrome Safari */
}
.
coupon
{
width
:
100
%
;
padding
:
0
12
px
;
box
-
sizing
:
border
-
box
;
font
-
size
:
0
;
&-
item
{
position
:
relative
;
padding
:
4
px
8
px
;
display
:
inline
-
flex
;
flex
-
direction
:
column
;
justify
-
content
:
space
-
around
;
align
-
items
:
center
;
height
:
88
px
;
text
-
align
:
center
;
background
:
url
(
'
./images/coupon-bg@2x.png
'
)
no
-
repeat
0
0
/
cover
;
font
-
size
:
12
px
;
line
-
height
:
18
px
;
&
:
last
-
child
{
margin
-
right
:
0
;
}
&-
title
{
color
:
#
EC1500
;
}
&-
amount
{
color
:
#
EC1500
;
span
{
font
-
size
:
20
px
;
line
-
height
:
26
px
;
font
-
weight
:
600
;
}
}
&-
condition
{
color
:
#
999999
;
}
&-
mask
{
position
:
absolute
;
width
:
100
%
;
height
:
100
%
;
background
:
#
fff
;
opacity
:
0.7
;
p
{
position
:
absolute
;
top
:
50
%
;
left
:
50
%
;
transform
:
translate
(
-
50
%
,
-
50
%
);
width
:
66
px
;
height
:
66
px
;
line
-
height
:
66
px
;
text
-
align
:
center
;
border
-
radius
:
50
%
;
background
-
color
:
#
000
;
color
:
#
fff
;
font
-
weight
:
600
;
}
}
}
&
_multiple
{
overflow
-
x
:
auto
;
white
-
space
:
nowrap
;
padding
:
0
4
px
;
.
coupon
-
item
{
width
:
114
px
;
margin
-
right
:
4
px
;
}
}
&
_two
{
display
:
flex
;
flex
-
wrap
:
wrap
;
justify
-
content
:
space
-
between
;
.
coupon
-
item
{
margin
-
bottom
:
8
px
;
width
:
170
px
;
&
_empty
{
padding
:
0
;
margin
:
0
;
height
:
0
;
}
}
}
&-
item_one
{
position
:
relative
;
margin
-
bottom
:
8
px
;
display
:
flex
;
justify
-
content
:
space
-
between
;
align
-
items
:
center
;
font
-
size
:
12
px
;
.
Gi_one
-
left
{
position
:
relative
;
padding
:
8
px
0
;
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
space
-
around
;
width
:
90
px
;
&
:
after
{
content
:
""
;
position
:
absolute
;
right
:
0
;
height
:
100
%
;
border
-
style
:
dashed
;
border
-
width
:
0
1
px
0
0
;
border
-
color
:
#
EC3333
;
transform
:
scaleX
(.
5
);
}
p
{
line
-
height
:
18
px
;
color
:
#
EC3333
;
span
{
font
-
size
:
20
px
;
line
-
height
:
26
px
;
font
-
weight
:
600
;
}
}
}
.
Gi_one
-
middle
{
flex
:
1
;
padding
:
8
px
0
;
margin
-
left
:
8
px
;
text
-
align
:
left
;
p
{
&
:
first
-
child
{
font
-
size
:
14
px
;
line
-
height
:
20
px
;
font
-
weight
:
600
;
}
&
:
last
-
child
{
line
-
height
:
24
px
;
}
}
}
.
Gi_one
-
right
{
width
:
56
px
;
height
:
80
px
!
important
;
}
}
// 组件库替换变量处理
/deep/
.
cr
-
button
--
primary
{
height
:
20
px
;
line
-
height
:
20
px
;
border
:
0
;
font
-
size
:
12
px
;
background
:
linear
-
gradient
(
269
deg
,
#
ff5d00
12
%
,
#
ff1900
86
%
);
}
}
<
/style>
\ No newline at end of file
app/web/lib/DownloadGuide/images/close@2x.png
deleted
100644 → 0
View file @
67a5e0c2
352 Bytes
app/web/lib/DownloadGuide/images/xyqb@2x.png
deleted
100644 → 0
View file @
67a5e0c2
12.6 KB
app/web/lib/DownloadGuide/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"top-bar"
>
<img
class=
"top-bar-left"
:src=
"leftImg"
/>
<div
class=
"top-bar-right"
>
<a
:href=
"href"
>
<button
class=
"top-bar-button"
>
打开APP
</button>
</a>
<img
class=
"top-bar-close"
@
click=
"close"
src=
"./images/close@2x.png"
/>
</div>
</div>
</
template
>
<
script
>
export
default
{
name
:
"
DownloadGuide
"
,
props
:
{
href
:
String
,
leftImg
:
String
},
methods
:
{
close
()
{
this
.
$emit
(
'
delete
'
);
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.top-bar {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 40px;
background-color: #d7e6ff;
padding: 0 20px 0 15px;
.top-bar-left {
width: 92px;
height: 24px;
}
.top-bar-right {
display: flex;
align-items: center;
a {
margin-right: 15px;
font-size: 0;
.top-bar-button {
width: 70px;
height: 24px;
line-height: 24px;
border-radius: 24px !important;
background-color: #5573eb !important;
font-size: 13px;
}
}
.top-bar-close {
width: 20px;
height: 20px;
}
}
}
</
style
>
\ No newline at end of file
app/web/lib/Form/api/api.ts
deleted
100644 → 0
View file @
67a5e0c2
import
Http
from
'
@/service/http.service.ts
'
;
import
Cookies
from
'
@/service/cookieStorage.service.ts
'
;
import
localStorage
from
'
@/service/localStorage.service.ts
'
;
import
qs
from
'
qs
'
;
// const ApiBaseUrl = 'http://passportapi.q-gp.com';
const
ApiBaseUrl
=
'
https://passportapi-fe.liangkebang.net
'
;
export
default
{
getCaptcha
()
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/captcha
'
);
},
sendVcode
(
phone
,
captcha
,
captchaId
)
{
const
params
=
{
phoneNo
:
phone
,
captchaId
,
captchaValue
:
captcha
,
};
return
Http
.
post
(
ApiBaseUrl
+
'
/api/sms/send_login_code_new_forH5
'
,
qs
.
stringify
(
params
));
},
sendGtVcode
(
gt
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/sms/send_login_code_new_forH5
'
,
qs
.
stringify
(
gt
));
},
fastLogin
(
phone
,
vcode
,
clickId
,
uniqueKey
,
registerFrom
=
1
)
{
const
headers
=
{
Authorization
:
'
Verification
'
+
btoa
(
phone
+
'
:
'
+
vcode
),
};
const
params
=
{
channelId
:
1
,
createdFrom
:
registerFrom
,
key
:
'
xyqb
'
,
btRegisterChannelId
:
''
,
dimension
:
''
,
click_id
:
clickId
,
uniqueKey
,
};
return
Http
.
post
(
ApiBaseUrl
+
'
/user/login/fastV1
'
,
qs
.
stringify
(
params
),
{
headers
,
});
},
// 判断极验还是qg
verifyMode
(
clientType
,
phoneNo
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/api/captcha/new
'
,
{
clientType
,
phoneNo
});
},
goNext
(
params
)
{
return
Http
.
post
(
ApiBaseUrl
+
'
/platform/api/page/next
'
,
qs
.
stringify
(
params
));
}
};
app/web/lib/Form/images/close@2x.png
deleted
100644 → 0
View file @
67a5e0c2
352 Bytes
app/web/lib/Form/images/landing-bg.png
deleted
100644 → 0
View file @
67a5e0c2
69.4 KB
app/web/lib/Form/images/landing-des.png
deleted
100644 → 0
View file @
67a5e0c2
12.4 KB
app/web/lib/Form/images/landing-submit.png
deleted
100644 → 0
View file @
67a5e0c2
7.07 KB
app/web/lib/Form/images/xyqb@2x.png
deleted
100644 → 0
View file @
67a5e0c2
12.6 KB
app/web/lib/Form/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<cr-form
class=
"login-form"
ref=
"loginForm"
show-error
validate-trigger=
"onBlur"
@
submit=
"login"
@
failed=
"onFormFailed"
>
<cr-field
v-model=
"formData.phoneNo"
name=
"phoneNo"
type=
"tel"
label=
""
placeholder=
"请填写您的手机号"
:rules=
"validOptions[0]"
/>
<cr-field
v-if=
"captchaShow"
class=
"send-sms-field"
v-model=
"formData.captcha"
name=
"captcha"
type=
"digit"
label=
""
placeholder=
"请填写图片验证码"
:rules=
"validOptions[1]"
>
<template
slot=
"button"
>
<img
:src=
"captchaUrl"
@
click=
"getCaptcha()"
class=
"captchaUrl"
/>
</
template
>
</cr-field>
<cr-field
class=
"send-sms-field"
v-model=
"formData.verifyCode"
name=
"verifyCode"
type=
"tel"
label=
""
placeholder=
"请填写验证码"
:rules=
"validOptions[1]"
>
<
template
slot=
"button"
>
<a
href=
"javascript:;"
:style=
"vcStyles"
:class=
"['login-form-send',
{ 'not-allow': noAllowSend || showCount }]"
ref="sendVcode"
>
{{
captchaBtnText
}}
</a>
</
template
>
</cr-field>
<cr-button
:color=
"btnColor"
:style=
"btnStyles"
shape=
'circle'
block
native-type=
"submit"
class=
"login-form-submit"
>
{{ btnTxt }}
</cr-button>
</cr-form>
</template>
<
script
>
import
Vue
from
'
vue
'
;
import
Storage
from
'
@/service/localStorage.service.ts
'
;
import
Cookies
from
'
@/service/cookieStorage.service.ts
'
;
import
{
isPhone
}
from
'
@/service/utils.service.ts
'
;
import
Api
from
'
./api/api.ts
'
;
import
config
from
'
@/config/index
'
;
const
validOptions
=
[
[
{
required
:
true
,
message
:
"
请填写您的手机号
"
},
{
validator
:
isPhone
,
message
:
"
请填写正确的手机号码
"
}
],
[{
required
:
true
,
message
:
"
请填写验证码
"
}]
];
let
timer
=
null
;
let
sa
=
null
;
export
default
{
name
:
"
KALoginForm
"
,
props
:
{
btnTxt
:
String
,
btnColor
:
{
type
:
String
,
default
:
'
#000
'
},
btnImage
:
String
,
vcBgColor
:
String
,
registerFrom
:
String
,
},
data
()
{
return
{
showCount
:
false
,
count
:
null
,
captchaUrl
:
""
,
captchaShow
:
false
,
gtShow
:
false
,
captchaId
:
""
,
gt
:
{
clientType
:
"
h5
"
,
verifyType
:
"
gt
"
,
geetest_challenge
:
""
,
geetest_validate
:
""
,
geetest_seccode
:
""
,
phoneNo
:
""
},
uniqueKey
:
""
,
formData
:
{
phoneNo
:
""
,
verifyCode
:
""
,
captcha
:
""
},
validOptions
};
},
computed
:
{
noAllowSend
()
{
return
!
isPhone
(
this
.
formData
.
phoneNo
);
},
captchaBtnText
()
{
return
this
.
showCount
?
`剩余
${
this
.
count
}
秒`
:
'
获取验证码
'
;
},
btnStyles
()
{
return
this
.
btnImage
?
{
background
:
`url(
${
this
.
btnImage
}
) no-repeat 0 0 / 100%`
,
}
:
{};
},
vcStyles
()
{
return
{
backgroundColor
:
this
.
vcBgColor
};
}
},
mounted
()
{
require
(
'
./jy/jy.ts
'
);
this
.
initSa
();
this
.
verifyMode
();
},
methods
:
{
initSa
()
{
sa
=
require
(
'
sa-sdk-javascript
'
);
//神策数据埋点
sa
.
init
({
server_url
:
config
.
shenceUrl
,
heatmap
:
{
//是否开启点击图,默认 default 表示开启,自动采集 $WebClick 事件,可以设置 'not_collect' 表示关闭
clickmap
:
'
default
'
,
//是否开启触达注意力图,默认 default 表示开启,自动采集 $WebStay 事件,可以设置 'not_collect' 表示关闭
scroll_notice_map
:
'
default
'
,
//判断外层是否有 App 的 SDK ,如果有的话,会往 App 的 SDK 发数据。如果没有,就正常发送数据。
// use_app_track: true,
},
show_log
:
process
.
env
.
NODE_ENV
!==
'
production
'
});
//添加公共属性
sa
.
registerPage
({
platformType
:
'
H5
'
});
this
.
$nextTick
(()
=>
{
sa
.
quick
(
"
autoTrackSinglePage
"
);
});
},
async
verifyMode
()
{
const
res
=
await
Api
.
verifyMode
(
this
.
gt
.
clientType
,
this
.
formData
.
phoneNo
);
this
.
uniqueKey
=
res
?.
uniqueKey
;
if
(
res
?.
verifyType
===
'
gt
'
)
{
this
.
getJyParam
(
res
);
}
else
{
this
.
getCaptcha
();
}
},
getJyParam
({
gt
,
challenge
,
success
})
{
var
vm
=
this
;
initGeetest
(
{
width
:
"
100%
"
,
gt
:
gt
,
challenge
:
challenge
,
offline
:
!
success
,
product
:
"
bind
"
},
function
(
captchaObj
)
{
vm
.
$refs
.
sendVcode
.
addEventListener
(
'
click
'
,
function
()
{
if
(
!
isPhone
(
vm
.
formData
.
phoneNo
))
{
vm
.
$notify
({
type
:
"
warning
"
,
message
:
"
请填写正确的手机号码
"
});
return
;
}
if
(
vm
.
showCount
)
return
;
captchaObj
.
verify
();
});
captchaObj
.
onSuccess
(
function
()
{
var
result
=
captchaObj
.
getValidate
();
vm
.
gt
.
geetest_challenge
=
result
.
geetest_challenge
;
vm
.
gt
.
geetest_validate
=
result
.
geetest_validate
;
vm
.
gt
.
geetest_seccode
=
result
.
geetest_seccode
;
vm
.
getCode
(
captchaObj
);
});
captchaObj
.
onError
(
function
()
{
vm
.
$toast
(
"
尝试过多,请点击重试
"
);
});
}
);
},
async
getCaptcha
()
{
this
.
captchaShow
=
true
;
const
res
=
await
Api
.
getCaptcha
();
({
image
:
this
.
captchaUrl
,
imageId
:
this
.
captchaId
}
=
res
);
},
async
getCode
(
captchaObj
)
{
if
(
!
isPhone
(
this
.
formData
.
phoneNo
))
{
this
.
$notify
({
type
:
"
warning
"
,
message
:
"
请填写正确的手机号码
"
});
return
;
}
if
(
timer
)
return
;
try
{
await
this
.
sendCode
();
this
.
smsCount
();
this
.
$notify
({
type
:
"
success
"
,
message
:
"
短信验证码已发送,请注意查收
"
});
}
finally
{
this
.
resetJyState
(
captchaObj
);
}
},
async
sendCode
()
{
const
{
phoneNo
,
captcha
}
=
this
.
formData
;
if
(
this
.
captchaShow
)
{
await
Api
.
sendVcode
(
phoneNo
,
captcha
,
this
.
captchaId
);
}
else
{
await
Api
.
sendGtVcode
({
...
this
.
gt
,
phoneNo
:
phoneNo
});
}
},
smsCount
()
{
this
.
showCount
=
true
;
this
.
count
=
60
;
timer
=
setInterval
(()
=>
{
if
(
this
.
count
>
0
&&
this
.
count
<=
60
)
{
this
.
count
--
;
}
else
{
this
.
showCount
=
false
;
clearInterval
(
timer
);
timer
=
null
;
}
},
1000
);
},
resetJyState
(
captchaObj
)
{
if
(
captchaObj
)
captchaObj
.
reset
();
},
async
login
()
{
let
le_is_login_success
=
false
;
try
{
const
{
phoneNo
,
verifyCode
}
=
this
.
formData
;
const
user
=
await
Api
.
fastLogin
(
phoneNo
,
verifyCode
,
null
,
this
.
uniqueKey
,
this
.
registerFrom
);
this
.
saveInfo
(
user
);
le_is_login_success
=
true
;
this
.
goNext
();
}
finally
{
sa
.
track
(
'
LoginEvent
'
,
{
le_login_action
:
'
注册/登录
'
,
le_login_type
:
'
验证码登录
'
,
le_is_login_success
,
le_channel_code
:
this
.
registerFrom
,
});
}
},
async
goNext
()
{
const
extData
=
{
redirectURL
:
null
,
productId
:
1
};
const
params
=
{
key
:
'
xyqb
'
,
target
:
'
cashTarget4
'
,
currentPage
:
'
login
'
};
const
{
transition
}
=
await
Api
.
goNext
(
params
);
window
.
location
.
replace
(
transition
+
'
?phoneNo=
'
+
Storage
.
get
(
'
phoneNo
'
)
+
'
&protocol=
'
+
window
.
location
.
protocol
+
'
&token=
'
+
Storage
.
get
(
'
token
'
)
+
(
extData
?
'
&extData=
'
+
btoa
(
JSON
.
stringify
(
extData
))
:
''
)
);
},
onFormFailed
(
errorInfo
)
{
const
{
errors
}
=
errorInfo
;
this
.
$notify
({
type
:
"
warning
"
,
message
:
errors
[
0
].
message
});
},
saveInfo
({
token
,
phoneNo
,
uuid
})
{
Storage
.
set
(
'
token
'
,
token
);
Cookies
.
set
(
'
phoneNo
'
,
phoneNo
);
if
(
uuid
)
{
Cookies
.
set
(
'
userid
'
,
uuid
);
sa
.
login
(
uuid
);
}
}
},
};
</
script
>
<
style
lang=
"less"
>
@import './jy/jy.less';
.login-form {
padding: 0 20px;
width: 100%;
.cr-field--error-message {
display: none;
}
.cr-cell {
&__value {
overflow: initial;
}
&-group {
&::after {
display: none;
}
}
background-color: #fff;
border-radius: 8px;
margin-bottom: 12px;
align-items: center;
padding: 12.5px 16px;
&::after {
display: none;
}
&__title {
color: #333333;
display: flex;
align-items: center;
}
}
&-btn {
width: 90px;
position: relative;
}
&-send {
padding: 5px 10px 4px;
border-radius: 8px;
background-color: #97d5ff;
color: #fff;
&.not-allow {
background-color: #eaeaea !important;
color: #999;
}
}
&-submit {
height: 50px !important;
border-radius: 8px !important;
border: 0 !important;
}
}
.send-sms-field {
padding: 8px 6px 8px 15px !important;
}
</
style
>
app/web/lib/Form/jy/jy.less
deleted
100644 → 0
View file @
67a5e0c2
//覆盖弹出框 滑动模块形式
.geetest_wind.geetest_panel .geetest_panel_box.geetest_panelshowslide{
width: 278px !important;
height: 285px !important;
}
.geetest_holder.geetest_mobile.geetest_ant.geetest_popup .geetest_popup_box {
width: 278px !important;
height: 285px !important;
max-width:none !important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_slider .geetest_slider_track .geetest_slider_tip {
font-size: 14px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_panel .geetest_copyright .geetest_copyright_tip {
font-size: 11px!important;
}
.geetest_holder.geetest_wind .geetest_radar_btn, .geetest_holder.geetest_wind .geetest_success_btn {
height: 44px!important;
}
.geetest_holder.geetest_wind .geetest_radar_tip, .geetest_holder.geetest_wind .geetest_success_radar_tip {
height: 44px!important;
line-height: 44px!important;
font-size: 14px!important;
// padding: 0 0 0 46px!important;
}
.geetest_holder.geetest_wind {
height: 44px!important;
min-width: 260px!important;
}
.geetest_holder.geetest_wind .geetest_logo, .geetest_holder.geetest_wind .geetest_success_logo {
width: 20px!important;
height: 20px!important;
top: 11px!important;
right: 12px!important;
}
.geetest_holder.geetest_wind .geetest_wait .geetest_wait_dot {
width: 20px!important;
height: 20px!important;
margin: 2px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_widget .geetest_window .geetest_result.geetest_fail {
height: 24px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_widget .geetest_window .geetest_result {
height: 24px!important;
bottom: -25px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_widget .geetest_window .geetest_showTip {
bottom:0px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_widget .geetest_window .geetest_result .geetest_result_content {
font-size: 14px!important;
text-indent: 16px!important;
line-height: 24px!important;
height: 24px!important;
bottom: -25px!important;
}
// 点击形式
.geetest_wind.geetest_panel .geetest_panel_box.geetest_panelshowclick {
width: 320px !important;
height: 410px !important;
}
.geetest_holder.geetest_silver.geetest_popup .geetest_popup_box {
min-width: 210px!important;
max-width: 348px!important;
}
.geetest_holder.geetest_silver .geetest_head .geetest_tips {
font-size: 16px!important;
}
.geetest_holder.geetest_silver .geetest_head .geetest_tips .geetest_tip_content {
font-size: 16px!important;
height: 20px!important;
}
.geetest_holder.geetest_silver .geetest_head .geetest_tips .geetest_tip_img {
width: 116px!important;
height: 40px!important;
right: -116px!important;
top: -10px!important;
}
.geetest_holder.geetest_silver .geetest_panel .geetest_small {
height: 23px!important;
margin-top: -11.5px!important;
}
.geetest_holder.geetest_silver .geetest_panel a.geetest_close, .geetest_holder.geetest_silver .geetest_panel a.geetest_refresh, .geetest_holder.geetest_silver .geetest_panel a.geetest_feedback{
height: 23px!important;
width: 23px!important;
}
.geetest_holder.geetest_silver .geetest_panel .geetest_commit .geetest_commit_tip {
margin-top: -10px!important;
height: 20px!important;
line-height: 20px!important;
font-size: 16px!important;
letter-spacing: 2px!important;
}
.geetest_holder.geetest_silver .geetest_panel .geetest_commit {
border-radius: 2px!important;
}
.geetest_holder.geetest_silver .geetest_table_box .geetest_result_tip {
bottom: -29px!important;
height: 28px!important;
text-indent: 9px!important;
font-size: 16px!important;
line-height: 29px!important;
}
.geetest_holder.geetest_silver .geetest_table_box .geetest_result_tip.geetest_up {
bottom:0px!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_panel .geetest_copyright {
display: none!important;
}
.geetest_holder.geetest_mobile.geetest_ant .geetest_panel a.geetest_feedback {
display: none!important;
}
.geetest_holder.geetest_wind.geetest_radar_error .geetest_logo {
display: none!important;
}
.geetest_holder.geetest_silver .geetest_panel a.geetest_feedback {
display: none!important;
}
.geetest_holder.geetest_wind .geetest_logo, .geetest_holder.geetest_wind .geetest_success_logo {
display: none!important;
}
.geetest_holder.geetest_silver .geetest_table_box .geetest_window .geetest_item .geetest_big_mark .geetest_mark_no {
// height: 24px!important;
// line-height: 24px!important;
font-size: 18px!important;
}
.geetest_holder.geetest_wind .geetest_radar_tip, .geetest_holder.geetest_wind .geetest_success_radar_tip {
padding: 0!important;
}
app/web/lib/Form/jy/jy.ts
deleted
100644 → 0
View file @
67a5e0c2
// tslint:disable
/* initGeetest 1.0.0
* 用于加载id对应的验证码库,并支持宕机模式
* 暴露 initGeetest 进行验证码的初始化
* 一般不需要用户进行修改
*/
(
function
(
global
,
factory
)
{
'
use strict
'
;
if
(
typeof
module
===
'
object
'
&&
typeof
module
.
exports
===
'
object
'
)
{
// CommonJS
module
.
exports
=
global
.
document
?
factory
(
global
,
true
)
:
function
(
w
)
{
if
(
!
w
.
document
)
{
throw
new
Error
(
'
Geetest requires a window with a document
'
);
}
return
factory
(
w
);
};
}
else
{
factory
(
global
);
}
})(
typeof
window
!==
'
undefined
'
?
window
:
this
,
function
(
window
,
noGlobal
)
{
'
use strict
'
;
if
(
typeof
window
===
'
undefined
'
)
{
throw
new
Error
(
'
Geetest requires browser environment
'
);
}
const
document
=
window
.
document
;
const
Math
=
window
.
Math
;
const
head
=
document
.
getElementsByTagName
(
'
head
'
)[
0
];
function
_Object
(
obj
)
{
this
.
_obj
=
obj
;
}
_Object
.
prototype
=
{
_each
(
process
)
{
const
_obj
=
this
.
_obj
;
for
(
const
k
in
_obj
)
{
if
(
_obj
.
hasOwnProperty
(
k
))
{
process
(
k
,
_obj
[
k
]);
}
}
return
this
;
}
};
function
Config
(
config
)
{
const
self
=
this
;
new
_Object
(
config
).
_each
(
function
(
key
,
value
)
{
self
[
key
]
=
value
;
});
}
Config
.
prototype
=
{
api_server
:
'
api.geetest.com
'
,
protocol
:
'
http://
'
,
type_path
:
'
/gettype.php
'
,
fallback_config
:
{
slide
:
{
static_servers
:
[
'
static.geetest.com
'
,
'
dn-staticdown.qbox.me
'
],
type
:
'
slide
'
,
slide
:
'
/static/js/geetest.0.0.0.js
'
},
fullpage
:
{
static_servers
:
[
'
static.geetest.com
'
,
'
dn-staticdown.qbox.me
'
],
type
:
'
fullpage
'
,
fullpage
:
'
/static/js/fullpage.0.0.0.js
'
}
},
_get_fallback_config
()
{
const
self
=
this
;
if
(
isString
(
self
.
type
))
{
return
self
.
fallback_config
[
self
.
type
];
}
else
if
(
self
.
new_captcha
)
{
return
self
.
fallback_config
.
fullpage
;
}
else
{
return
self
.
fallback_config
.
slide
;
}
},
_extend
(
obj
)
{
const
self
=
this
;
new
_Object
(
obj
).
_each
(
function
(
key
,
value
)
{
self
[
key
]
=
value
;
});
}
};
const
isNumber
=
function
(
value
)
{
return
(
typeof
value
===
'
number
'
);
};
const
isString
=
function
(
value
)
{
return
(
typeof
value
===
'
string
'
);
};
const
isBoolean
=
function
(
value
)
{
return
(
typeof
value
===
'
boolean
'
);
};
const
isObject
=
function
(
value
)
{
return
(
typeof
value
===
'
object
'
&&
value
!==
null
);
};
const
isFunction
=
function
(
value
)
{
return
(
typeof
value
===
'
function
'
);
};
const
callbacks
=
{};
const
status
=
{};
const
random
=
function
()
{
return
parseInt
(
Math
.
random
()
*
10000
)
+
(
new
Date
()).
valueOf
();
};
const
loadScript
=
function
(
url
,
cb
)
{
const
script
=
document
.
createElement
(
'
script
'
);
script
.
charset
=
'
UTF-8
'
;
script
.
async
=
true
;
script
.
onerror
=
function
()
{
cb
(
true
);
};
let
loaded
=
false
;
script
.
onload
=
script
.
onreadystatechange
=
function
()
{
if
(
!
loaded
&&
(
!
script
.
readyState
||
'
loaded
'
===
script
.
readyState
||
'
complete
'
===
script
.
readyState
))
{
loaded
=
true
;
setTimeout
(
function
()
{
cb
(
false
);
},
0
);
}
};
script
.
src
=
url
;
head
.
appendChild
(
script
);
};
const
normalizeDomain
=
function
(
domain
)
{
return
domain
.
replace
(
/^https
?
:
\/\/
|
\/
$/g
,
''
);
};
const
normalizePath
=
function
(
path
)
{
path
=
path
.
replace
(
/
\/
+/g
,
'
/
'
);
if
(
path
.
indexOf
(
'
/
'
)
!==
0
)
{
path
=
'
/
'
+
path
;
}
return
path
;
};
const
normalizeQuery
=
function
(
query
)
{
if
(
!
query
)
{
return
''
;
}
let
q
=
'
?
'
;
new
_Object
(
query
).
_each
(
function
(
key
,
value
)
{
if
(
isString
(
value
)
||
isNumber
(
value
)
||
isBoolean
(
value
))
{
q
=
q
+
encodeURIComponent
(
key
)
+
'
=
'
+
encodeURIComponent
(
value
)
+
'
&
'
;
}
});
if
(
q
===
'
?
'
)
{
q
=
''
;
}
return
q
.
replace
(
/&$/
,
''
);
};
const
makeURL
=
function
(
protocol
,
domain
,
path
,
query
)
{
domain
=
normalizeDomain
(
domain
);
let
url
=
normalizePath
(
path
)
+
normalizeQuery
(
query
);
if
(
domain
)
{
url
=
protocol
+
domain
+
url
;
}
return
url
;
};
const
load
=
function
(
protocol
,
domains
,
path
,
query
,
cb
)
{
const
tryRequest
=
function
(
at
)
{
const
url
=
makeURL
(
protocol
,
domains
[
at
],
path
,
query
);
loadScript
(
url
,
function
(
err
)
{
if
(
err
)
{
if
(
at
>=
domains
.
length
-
1
)
{
cb
(
true
);
}
else
{
tryRequest
(
at
+
1
);
}
}
else
{
cb
(
false
);
}
});
};
tryRequest
(
0
);
};
const
jsonp
=
function
(
domains
,
path
,
config
,
callback
)
{
if
(
isObject
(
config
.
getLib
))
{
config
.
_extend
(
config
.
getLib
);
callback
(
config
);
return
;
}
if
(
config
.
offline
)
{
callback
(
config
.
_get_fallback_config
());
return
;
}
const
cb
=
'
geetest_
'
+
random
();
window
[
cb
]
=
function
(
data
)
{
if
(
data
.
status
===
'
success
'
)
{
callback
(
data
.
data
);
}
else
if
(
!
data
.
status
)
{
callback
(
data
);
}
else
{
callback
(
config
.
_get_fallback_config
());
}
window
[
cb
]
=
undefined
;
try
{
delete
window
[
cb
];
}
catch
(
e
)
{
}
};
load
(
config
.
protocol
,
domains
,
path
,
{
gt
:
config
.
gt
,
callback
:
cb
},
function
(
err
)
{
if
(
err
)
{
callback
(
config
.
_get_fallback_config
());
}
});
};
const
throwError
=
function
(
errorType
,
config
)
{
const
errors
=
{
networkError
:
'
网络错误
'
};
if
(
typeof
config
.
onError
===
'
function
'
)
{
config
.
onError
(
errors
[
errorType
]);
}
else
{
throw
new
Error
(
errors
[
errorType
]);
}
};
const
detect
=
function
()
{
return
!!
window
.
Geetest
;
};
if
(
detect
())
{
status
.
slide
=
'
loaded
'
;
}
const
initGeetest
=
function
(
userConfig
,
callback
)
{
const
config
=
new
Config
(
userConfig
);
if
(
userConfig
.
https
)
{
config
.
protocol
=
'
https://
'
;
}
else
if
(
!
userConfig
.
protocol
)
{
config
.
protocol
=
window
.
location
.
protocol
+
'
//
'
;
}
jsonp
([
config
.
api_server
||
config
.
apiserver
],
config
.
type_path
,
config
,
function
(
newConfig
)
{
const
type
=
newConfig
.
type
;
const
init
=
function
()
{
config
.
_extend
(
newConfig
);
callback
(
new
window
.
Geetest
(
config
));
};
callbacks
[
type
]
=
callbacks
[
type
]
||
[];
const
s
=
status
[
type
]
||
'
init
'
;
if
(
s
===
'
init
'
)
{
status
[
type
]
=
'
loading
'
;
callbacks
[
type
].
push
(
init
);
load
(
config
.
protocol
,
newConfig
.
static_servers
||
newConfig
.
domains
,
newConfig
[
type
]
||
newConfig
.
path
,
null
,
function
(
err
)
{
if
(
err
)
{
status
[
type
]
=
'
fail
'
;
throwError
(
'
networkError
'
,
config
);
}
else
{
status
[
type
]
=
'
loaded
'
;
const
cbs
=
callbacks
[
type
];
for
(
let
i
=
0
,
len
=
cbs
.
length
;
i
<
len
;
i
=
i
+
1
)
{
const
cb
=
cbs
[
i
];
if
(
isFunction
(
cb
))
{
cb
();
}
}
callbacks
[
type
]
=
[];
}
});
}
else
if
(
s
===
'
loaded
'
)
{
init
();
}
else
if
(
s
===
'
fail
'
)
{
throwError
(
'
networkError
'
,
config
);
}
else
if
(
s
===
'
loading
'
)
{
callbacks
[
type
].
push
(
init
);
}
});
};
window
.
initGeetest
=
initGeetest
;
return
initGeetest
;
});
app/web/lib/Goods/images/shopping-cart@2x.png
deleted
100644 → 0
View file @
67a5e0c2
951 Bytes
app/web/lib/Goods/images/special-recommend.png
deleted
100644 → 0
View file @
67a5e0c2
243 KB
app/web/lib/Goods/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"container"
>
<cr-image
width=
"100%"
height=
"2.4rem"
:src=
"specialRecommend"
@
click=
"go('special')"
v-if=
"showSpecial"
></cr-image>
<div
class=
"goods"
v-if=
"column === 1"
>
<div
class=
"goods-item goods-item_one"
@
click=
"go('detail', goods.skuNo)"
v-for=
"goods in goodsList"
:key=
"goods.id"
>
<cr-image
width=
"100%"
height=
"3.15rem"
class=
"goods-item-img"
fit=
"contain"
:src=
"goods.skuUrl"
></cr-image>
<div
class=
"goods-item_one-right"
>
<p
class=
"goods-item-title"
>
{{
goods
.
skuName
}}
</p>
<div
class=
"goods-item-bottom"
>
<div
class=
"Gi-bottom-left"
>
<p>
¥
{{
goods
.
salePrice
||
'
-
'
}}
</p>
<p>
¥
{{
goods
.
marketPrice
||
'
-
'
}}
</p>
</div>
<cr-button
shape=
"circle"
type=
"primary"
@
click=
"go('detail', goods.skuNo)"
>
立即抢购
</cr-button>
</div>
</div>
</div>
</div>
<div
class=
"goods"
v-else
>
<div
:class=
"['goods-item',
{'goods-item_three': column === 3, 'goods-item_two': column === 2}]" v-for="goods in goodsList" :key="goods.id" @click="go('detail', goods.skuNo)">
<cr-image
width=
"100%"
height=
"3.15rem"
class=
"goods-item-img"
fit=
"contain"
:src=
"goods.skuUrl"
></cr-image>
<p
class=
"goods-item-title"
>
{{
goods
.
skuName
}}
</p>
<div
class=
"goods-item-bottom"
>
<div
class=
"Gi-bottom-left"
>
<p>
¥
{{
goods
.
salePrice
||
'
-
'
}}
</p>
<p>
¥
{{
goods
.
marketPrice
||
'
-
'
}}
</p>
</div>
<div
class=
"Gi-bottom-right"
@
click=
"addShopCart(goods)"
>
<cr-image
width=
"0.45rem"
height=
"0.45rem"
:src=
"shoppingCart"
></cr-image>
</div>
</div>
</div>
<div
class=
"goods-item goods-item_three goods-item_empty"
v-if=
"showEmpty"
></div>
</div>
</div>
</
template
>
<
script
>
import
shoppingCart
from
'
./images/shopping-cart@2x.png
'
;
import
specialRecommend
from
'
./images/special-recommend.png
'
;
import
operationApi
from
'
@api/operation.api
'
;
export
default
{
inject
:
[
'
editor
'
],
props
:
{
goods
:
{
type
:
Object
,
default
:
()
=>
({
type
:
'
goodsGroup
'
,
ids
:
[]
})
},
goodsNumber
:
Number
,
column
:
{
type
:
Number
,
default
:
2
},
showSpecial
:
{
type
:
Boolean
,
default
:
true
},
specialUrl
:
String
,
specialLink
:
String
,
},
data
()
{
return
{
list
:
[],
shoppingCart
,
specialRecommend
}
},
computed
:
{
goodsList
()
{
if
(
this
.
editor
)
this
.
$nextTick
(()
=>
this
.
editor
.
adjustHeight
());
return
this
.
list
.
slice
(
0
,
this
.
goodsNumber
);
},
showEmpty
()
{
return
this
.
column
===
3
&&
this
.
goodsNumber
%
3
===
2
;
}
},
watch
:
{
goods
:
{
handler
:
async
function
(
newVal
)
{
if
(
newVal
.
ids
.
length
)
{
let
records
=
[];
if
(
newVal
.
type
===
'
goodsGroup
'
)
{
({
skus
:
records
}
=
await
operationApi
.
getGoods
({
specialId
:
newVal
.
ids
[
0
]
}));
}
else
if
(
newVal
.
type
===
'
goods
'
)
{
({
skus
:
records
}
=
await
operationApi
.
getGoods
({
skus
:
newVal
.
ids
}));
}
if
(
records
.
length
)
this
.
list
=
records
;
}
// console.log('watch', this.list);
},
immediate
:
true
}
},
methods
:
{
go
(
type
,
params
)
{
if
(
type
===
'
special
'
&&
this
.
specialLink
)
{
window
.
location
.
href
=
this
.
specialLink
;
}
else
if
(
type
===
'
goodsDetail
'
)
{
window
.
location
.
href
=
`xyqb://homepage/goodsdetail?skuNo=
${
params
}
`
;
}
},
async
addShopCart
(
goods
)
{
const
{
skuId
,
skuNum
,
skuSource
}
=
goods
;
const
params
=
{
skuId
,
skuNum
,
skuSource
,
type
:
1
}
await
operationApi
.
addShopCart
(
params
);
this
.
$toast
.
success
(
'
添加成功
'
);
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.container {
margin: 0 12px;
.goods {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 4px;
font-size: 0;
&-item {
border-radius: 8px;
background: #fff;
margin-bottom: 4px;
overflow: hidden;
&-title {
height: 36px;
font-size: 12px;
line-height: 18px;
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-align: left;
}
&-bottom {
display: flex;
justify-content: space-between;
align-items: center;
.Gi-bottom-left {
display: flex;
flex-direction: column;
align-items: center;
p {
max-width: 55px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-align: left;
&:first-child {
font-size: 15px;
color: #EC3333;
}
&:last-child {
font-size: 13px;
color: #999999;
text-decoration:line-through;
}
}
}
.Gi-bottom-right {
width: 30px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
background: #FFF3F3;
border-radius: 50%;
/deep/ .cr-image {
width: 18px !important;
height: 18px !important;
}
}
}
&_one {
display: flex;
width: 100%;
.goods-item-img {
width: 112px !important;
height: 109px !important;
}
&-right {
padding: 6px 8px;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.Gi-bottom-left {
margin-right: 10px;
flex: 1;
display: flex;
justify-content: space-around;
flex-direction: row;
align-items: flex-end;
p {
max-width: 55px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
// 组件库替换变量处理
/deep/ .cr-button--primary {
height: 24px;
line-height: 24px;
border: 0;
background: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
}
}
}
&_two {
width: 49%;
.goods-item-img {
width: 100% !important;
height: 180px !important;
}
.goods-item-title {
margin: 8px 8px;
}
.goods-item-bottom {
margin: 0 8px 6px;
}
}
&_three {
width: 32%;
.goods-item-img {
width: 100% !important;
height: 117px !important;
}
.goods-item-title {
margin: 8px 4px;
}
.goods-item-bottom {
margin: 0 4px 6px;
.goods-item-bottom {
}
}
}
&_empty {
height: 0;
}
}
}
}
</
style
>
\ No newline at end of file
app/web/lib/GoodsTabs/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"tabs"
>
<cr-tabs
sticky
ref=
"GoodsTabs"
@
change=
"tabsChange"
animated
:color=
"underlineColor"
:title-active-color=
"activeColor"
:title-inactive-color=
"inactiveColor"
>
<cr-tab
v-for=
"(tab, index) in tabs"
:key=
"index"
:name=
"index"
:title=
"tab.tabTitle"
>
<component
:is=
"tab.name"
v-bind=
"tab.props"
:style=
"transformStyle(tab.commonStyle)"
></component>
</cr-tab>
</cr-tabs>
</div>
</
template
>
<
script
>
import
Goods
from
'
../Goods/index.vue
'
;
import
Coupon
from
'
../Coupon/index.vue
'
;
export
default
{
name
:
'
goods-tabs
'
,
components
:
{
Goods
,
Coupon
},
props
:
{
list
:
{
type
:
Array
,
default
:
()
=>
[]
},
childItem
:
{
type
:
Object
,
default
:
()
=>
({
child
:
[]
})
},
activeColor
:
{
type
:
String
,
default
:
'
#323233
'
},
inactiveColor
:
{
type
:
String
,
default
:
'
#646566
'
},
underlineColor
:
{
type
:
String
,
default
:
'
#1989fa
'
}
},
data
()
{
return
{
}
},
computed
:
{
tabs
()
{
const
list
=
this
.
list
.
map
(
tab
=>
{
const
rs
=
{
...
tab
};
this
.
childItem
?.
child
.
forEach
(
ele
=>
{
if
(
tab
.
componentId
===
ele
.
id
)
Object
.
assign
(
rs
,
tab
,
ele
);
})
return
rs
;
});
// console.log('tabs', this.childItem.child, list);
return
list
;
}
},
mounted
()
{
setTimeout
(()
=>
{
this
.
$refs
.
GoodsTabs
.
resize
();
})
},
methods
:
{
tabsChange
(
name
)
{
// console.log('change', name);
},
transformStyle
(
styleObj
=
{})
{
// console.log('transformStyle', styleObj);
const
style
=
{};
for
(
const
key
of
Object
.
keys
(
styleObj
))
{
style
[
key
]
=
styleObj
[
key
];
if
(
key
===
'
backgroundImage
'
&&
style
.
backgroundImage
)
{
style
.
background
=
`url(
${
style
.
backgroundImage
}
) no-repeat 0 0 / cover`
;
}
}
return
style
;
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
/deep/ .cr-tabs__nav {
background-color: transparent;
}
/deep/ .cr-swipe-item {
&:nth-child(odd) {
background-color: #66c6f2;
}
&:nth-child(2n) {
background-color: #39a9ed;
}
height: 500px;
}
</
style
>
\ No newline at end of file
app/web/lib/GuideCube/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"guide-cube"
>
<div
v-if=
"showSwiper"
class=
"guide-cube-swiper"
ref=
"mySwiper"
v-swiper:mySwiper=
"swiperOptions"
>
<div
class=
"swiper-wrapper"
>
<div
:style=
"style"
:class=
"
{'swiper-slide_two': slidesPerColumn === 2, 'swiper-slide_one': slidesPerColumn === 1, 'swiper-slide': true }" :key="index" v-for="(item, index) in list" @click="go(item.link)">
<cr-image
width=
""
height=
""
:src=
"item.img"
fit=
"cover"
:show-loading=
"false"
></cr-image>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
Vue
from
"
vue
"
;
import
'
swiper/dist/css/swiper.css
'
;
if
(
EASY_ENV_IS_BROWSER
)
{
const
VueAwesomeSwiper
=
require
(
'
vue-awesome-swiper/dist/ssr
'
)
Vue
.
use
(
VueAwesomeSwiper
)
}
export
default
{
inject
:
[
'
editor
'
],
props
:
{
list
:
{
type
:
Array
,
default
:
()
=>
([])
},
slidesPerColumn
:
{
type
:
Number
,
default
:
1
},
loop
:
Boolean
,
autoplay
:
Boolean
,
animation
:
Boolean
},
data
()
{
const
vm
=
this
;
let
isEven
=
true
;
let
lastEvenProgress
=
0
;
let
lastProgress
=
0
;
return
{
showSwiper
:
false
,
// style: {},
swiperOptions
:
{
loop
:
this
.
loop
,
slidesPerView
:
4
,
slidesPerColumn
:
this
.
slidesPerColumn
,
spaceBetween
:
8
,
observer
:
true
,
observeParents
:
true
,
watchSlidesProgress
:
true
,
autoplay
:
this
.
autoplay
,
on
:
{
progress
:
function
()
{
const
slidesLength
=
this
.
slides
.
length
;
if
(
!
vm
.
animation
)
return
;
let
ratio
=
Math
.
abs
(
this
.
slides
[
0
].
progress
%
1
).
toFixed
(
10
)
*
0.2
;
if
([
0
,
1
].
includes
(
Math
.
abs
(
this
.
slides
[
0
].
progress
%
2
)))
{
isEven
=
Math
.
abs
(
this
.
slides
[
0
].
progress
%
2
)
===
0
?
true
:
false
;
}
if
(
Math
.
abs
(
this
.
slides
[
0
].
progress
-
lastEvenProgress
)
>
1
)
{
lastEvenProgress
=
Math
.
floor
(
this
.
slides
[
0
].
progress
);
isEven
=
!
isEven
;
}
const
isLeft
=
lastProgress
<
this
.
slides
[
0
].
progress
;
lastProgress
=
this
.
slides
[
0
].
progress
;
for
(
let
i
=
0
;
i
<
this
.
slides
.
length
;
i
++
)
{
const
slide
=
this
.
slides
.
eq
(
i
);
let
scale
=
1
;
if
(
Math
.
abs
(
this
.
slides
[
0
].
progress
%
2
)
===
0
)
{
scale
=
vm
.
memorys
[
i
]
?
0.8
:
1
;
}
else
if
(
Math
.
abs
(
this
.
slides
[
0
].
progress
%
2
)
===
1
)
{
scale
=
vm
.
memorys
[
i
]
?
1
:
0.8
;
}
else
if
(
isEven
)
{
if
(
isLeft
)
{
if
(
vm
.
memorys
[
i
])
{
scale
=
0.8
+
ratio
;
}
else
{
scale
=
1
-
ratio
;
}
}
else
{
if
(
vm
.
memorys
[
i
])
{
scale
=
1
-
ratio
;
}
else
{
scale
=
0.8
+
ratio
;
}
}
}
else
if
(
!
isEven
)
{
if
(
isLeft
)
{
if
(
vm
.
memorys
[
i
])
{
scale
=
1
-
ratio
;
}
else
{
scale
=
0.8
+
ratio
;
}
}
else
{
if
(
vm
.
memorys
[
i
])
{
scale
=
0.8
+
ratio
;
}
else
{
scale
=
1
-
ratio
;
}
}
}
slide
.
transform
(
`scale3d(
${
scale
}
,
${
scale
}
, 1)`
);
}
}
},
}
}
},
computed
:
{
swiper
()
{
return
this
.
$refs
.
mySwiper
.
swiper
},
memorys
()
{
const
length
=
this
.
list
.
length
;
const
baseNumber
=
this
.
slidesPerColumn
===
1
?
2
:
4
;
return
new
Array
(
length
).
fill
(
0
).
map
((
v
,
i
)
=>
[
0
,
3
].
includes
(
i
%
baseNumber
)
?
1
:
0
);
},
style
()
{
return
{
transition
:
'
all .2s cubic-bezier(.4, 0, .2, 1)
'
};
}
},
watch
:
{
slidesPerColumn
(
newVal
)
{
this
.
refreshSwiper
(
'
slidesPerColumn
'
,
newVal
);
},
autoplay
(
newVal
)
{
this
.
refreshSwiper
(
'
autoplay
'
,
newVal
);
},
loop
(
newVal
)
{
this
.
refreshSwiper
(
'
loop
'
,
newVal
);
},
},
mounted
()
{
this
.
showSwiper
=
true
;
},
methods
:
{
go
(
url
)
{
window
.
location
.
href
=
url
;
},
refreshSwiper
(
key
,
val
)
{
this
.
swiperOptions
[
key
]
=
val
;
this
.
showSwiper
=
false
;
this
.
$nextTick
(()
=>
this
.
showSwiper
=
true
);
if
(
this
.
editor
)
setTimeout
(()
=>
this
.
editor
.
adjustHeight
(),
0
);
}
},
}
</
script
>
<
style
lang=
"less"
scoped
>
.guide-cube {
width: 100%;
padding: 12px;
&-swiper {
width: 100%;
.swiper-slide {
display: flex;
justify-content: center;
align-items: center;
width: 81px;
height: 81px;
/deep/ .cr-image {
width: 100%;
height: 100%;
border-radius: 8px;
overflow: hidden;
}
}
}
}
</
style
>
\ No newline at end of file
app/web/lib/Marquee/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"marquee"
>
<div
class=
"marquee-swiper"
v-if=
'showSwiper'
ref=
"mySwiper"
v-swiper:mySwiper=
"swiperOptions"
>
<div
class=
"swiper-wrapper"
>
<div
class=
"swiper-slide"
:key=
"index"
v-for=
"(item, index) in list"
>
<a
class=
"swiper-slide-a"
@
click=
"go(item.link)"
>
<span
:style=
"styles"
>
{{
item
.
text
}}
</span>
</a>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
Vue
from
"
vue
"
;
import
'
swiper/dist/css/swiper.css
'
;
if
(
EASY_ENV_IS_BROWSER
)
{
const
VueAwesomeSwiper
=
require
(
'
vue-awesome-swiper/dist/ssr
'
)
Vue
.
use
(
VueAwesomeSwiper
)
}
export
default
{
inject
:
[
'
editor
'
],
props
:
{
list
:
{
type
:
Array
,
default
:
()
=>
([])
},
fontColor
:
{
type
:
String
,
default
:
'
#666666
'
}
},
data
()
{
return
{
showSwiper
:
false
,
swiperOptions
:
{
loop
:
true
,
observer
:
true
,
observeParents
:
true
,
direction
:
'
vertical
'
,
allowTouchMove
:
false
,
autoplay
:
true
}
}
},
computed
:
{
swiper
()
{
return
this
.
$refs
.
mySwiper
.
swiper
},
styles
()
{
return
{
color
:
this
.
fontColor
}
}
},
watch
:
{
list
:
{
deep
:
true
,
handler
()
{
this
.
refreshSwiper
();
}
}
},
mounted
()
{
this
.
showSwiper
=
true
;
},
methods
:
{
go
(
link
)
{
window
.
location
.
href
=
link
;
},
refreshSwiper
()
{
console
.
log
(
'
refreshSwiper
'
);
this
.
showSwiper
=
false
;
this
.
$nextTick
(()
=>
this
.
showSwiper
=
true
);
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.marquee {
width: 100%;
height: 30px;
border-radius: 8px;
background-color: #D8D8D8;
.swiper-container {
height: 100%;
.swiper-slide {
display: flex;
justify-content: center;
align-items: center;
a {
display: flex;
justify-content: center;
align-items: center;
}
span {
font-size: 14px;
line-height: 20px;
color: #666666;
}
}
}
}
</
style
>
\ No newline at end of file
app/web/lib/Placeholder/index.vue
deleted
100644 → 0
View file @
67a5e0c2
<
template
>
<div
class=
"placeholder"
:style=
"style"
></div>
</
template
>
<
script
>
export
default
{
props
:
{
height
:
Number
,
},
computed
:
{
style
()
{
return
{
height
:
`
${
this
.
height
}
px`
}
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.placeholder {
min-height: 10px;
}
</
style
>
\ No newline at end of file
app/web/lib/config.ts
View file @
c7027cf3
// export const basic
Components = require('@qg/cherry-ui/md/index.json');
const
cr
Components
=
require
(
'
@qg/cherry-ui/md/index.json
'
);
//
export const kaLoginForm = require('@qg/citrus-ui/md/index.json');
export
const
kaLoginForm
=
require
(
'
@qg/citrus-ui/md/index.json
'
);
export
const
basicComponents
=
[
export
const
basicComponents
=
[
{
{
...
@@ -23,644 +23,645 @@ export const basicComponents = [
...
@@ -23,644 +23,645 @@ export const basicComponents = [
},
},
commonStyle
:
{}
commonStyle
:
{}
},
},
{
...
crComponents
eleName
:
'
cr-button
'
,
// {
title
:
'
Button 按钮
'
,
// eleName: 'cr-button',
config
:
[
// title: 'Button 按钮',
{
// config: [
key
:
'
type
'
,
// {
name
:
'
类型
'
,
// key: 'type',
desc
:
'
类型,可选值为
'
,
// name: '类型',
options
:
[
// desc: '类型,可选值为',
'
default
'
,
// options: [
'
primary
'
,
// 'default',
'
info
'
,
// 'primary',
'
danger
'
,
// 'info',
'
waring
'
,
// 'danger',
'
success
'
// 'waring',
],
// 'success'
type
:
'
select
'
// ],
},
// type: 'select'
{
// },
key
:
'
size
'
,
// {
name
:
'
尺寸
'
,
// key: 'size',
desc
:
'
尺寸,可选值为
'
,
// name: '尺寸',
options
:
[
// desc: '尺寸,可选值为',
'
normal
'
,
// options: [
'
large
'
,
// 'normal',
'
small
'
,
// 'large',
'
mini
'
// 'small',
],
// 'mini'
type
:
'
select
'
// ],
},
// type: 'select'
{
// },
key
:
'
color
'
,
// {
name
:
'
颜色
'
,
// key: 'color',
desc
:
'
按钮颜色,支持传入
'
,
// name: '颜色',
type
:
'
ColorSelector
'
// desc: '按钮颜色,支持传入',
},
// type: 'ColorSelector'
{
// },
key
:
'
icon
'
,
// {
name
:
'
图标
'
,
// key: 'icon',
desc
:
'
左侧
'
,
// name: '图标',
type
:
'
text
'
// desc: '左侧',
},
// type: 'text'
{
// },
key
:
'
block
'
,
// {
name
:
'
块级元素
'
,
// key: 'block',
desc
:
'
是否为块级元素
'
,
// name: '块级元素',
type
:
'
checkbox
'
// desc: '是否为块级元素',
},
// type: 'checkbox'
{
// },
key
:
'
shape
'
,
// {
name
:
'
形状
'
,
// key: 'shape',
desc
:
'
按钮形状,可选值为
'
,
// name: '形状',
options
:
[
// desc: '按钮形状,可选值为',
'
square
'
,
// options: [
'
circle
'
// 'square',
],
// 'circle'
type
:
'
select
'
// ],
},
// type: 'select'
{
// },
key
:
'
disabled
'
,
// {
name
:
'
禁用
'
,
// key: 'disabled',
desc
:
'
是否禁用按钮
'
,
// name: '禁用',
type
:
'
checkbox
'
// desc: '是否禁用按钮',
},
// type: 'checkbox'
{
// },
key
:
'
plain
'
,
// {
name
:
'
朴素按钮
'
,
// key: 'plain',
desc
:
'
朴素按钮
'
,
// name: '朴素按钮',
type
:
'
checkbox
'
// desc: '朴素按钮',
},
// type: 'checkbox'
{
// },
key
:
'
hairline
'
,
// {
name
:
'
细边框
'
,
// key: 'hairline',
desc
:
'
细边框
'
,
// name: '细边框',
type
:
'
checkbox
'
// desc: '细边框',
},
// type: 'checkbox'
{
// },
key
:
'
loading
'
,
// {
name
:
'
加载中
'
,
// key: 'loading',
desc
:
'
是否显示为加载状态
'
,
// name: '加载中',
type
:
'
checkbox
'
// desc: '是否显示为加载状态',
},
// type: 'checkbox'
{
// },
key
:
'
loadingText
'
,
// {
name
:
'
加载文字
'
,
// key: 'loadingText',
desc
:
'
加载状态提示文字
'
,
// name: '加载文字',
type
:
'
text
'
// desc: '加载状态提示文字',
},
// type: 'text'
{
// },
key
:
'
loadingType
'
,
// {
name
:
'
加载图标类型
'
,
// key: 'loadingType',
desc
:
''
,
// name: '加载图标类型',
options
:
[
// desc: '',
'
circular
'
,
// options: [
'
spinner
'
// 'circular',
],
// 'spinner'
type
:
'
select
'
// ],
},
// type: 'select'
{
// },
key
:
'
loadingSize
'
,
// {
name
:
'
加载图标大小
'
,
// key: 'loadingSize',
desc
:
'
加载图标大小
'
,
// name: '加载图标大小',
type
:
'
text
'
// desc: '加载图标大小',
}
// type: 'text'
],
// }
value
:
{
// ],
type
:
'
default
'
,
// value: {
size
:
'
normal
'
,
// type: 'default',
color
:
''
,
// size: 'normal',
icon
:
''
,
// color: '',
block
:
false
,
// icon: '',
shape
:
'
square
'
,
// block: false,
disabled
:
false
,
// shape: 'square',
plain
:
false
,
// disabled: false,
hairline
:
false
,
// plain: false,
loading
:
false
,
// hairline: false,
loadingText
:
''
,
// loading: false,
loadingType
:
'
circular
'
,
// loadingText: '',
loadingSize
:
'
20px
'
// loadingType: 'circular',
},
// loadingSize: '20px'
commonStyle
:
{}
// },
},
// commonStyle: {}
{
// },
eleName
:
'
cr-image
'
,
// {
title
:
'
图片
'
,
// eleName: 'cr-image',
config
:
[
// title: '图片',
{
// config: [
key
:
'
width
'
,
// {
name
:
'
宽度
'
,
// key: 'width',
type
:
'
text
'
// name: '宽度',
},
// type: 'text'
{
// },
key
:
'
height
'
,
// {
name
:
'
高度
'
,
// key: 'height',
type
:
'
text
'
// name: '高度',
},
// type: 'text'
{
// },
key
:
'
src
'
,
// {
name
:
'
图片
'
,
// key: 'src',
type
:
'
Upload
'
// name: '图片',
},
// type: 'Upload'
],
// },
value
:
{
// ],
width
:
'
5.067rem
'
,
// value: {
height
:
'
3.733rem
'
,
// width: '5.067rem',
src
:
'
https://appsync.lkbang.net/Fs0qmUsMry39AjHDf_W-qgn8XEy6
'
,
// height: '3.733rem',
fit
:
'
contain
'
,
// src: 'https://appsync.lkbang.net/Fs0qmUsMry39AjHDf_W-qgn8XEy6',
},
// fit: 'contain',
commonStyle
:
{}
// },
},
// commonStyle: {}
{
// },
eleName
:
'
cr-nav-bar
'
,
// {
title
:
'
NavBar 导航栏
'
,
// eleName: 'cr-nav-bar',
config
:
[
// title: 'NavBar 导航栏',
{
// config: [
key
:
'
title
'
,
// {
name
:
'
标题
'
,
// key: 'title',
desc
:
'
标题
'
,
// name: '标题',
propType
:
'
string
'
,
// desc: '标题',
options
:
[],
// propType: 'string',
type
:
'
text
'
// options: [],
},
// type: 'text'
{
// },
key
:
'
leftText
'
,
// {
name
:
'
左侧文案
'
,
// key: 'leftText',
desc
:
'
左侧文案
'
,
// name: '左侧文案',
propType
:
'
string
'
,
// desc: '左侧文案',
options
:
[],
// propType: 'string',
type
:
'
text
'
// options: [],
},
// type: 'text'
{
// },
key
:
'
rightText
'
,
// {
name
:
'
右侧文案
'
,
// key: 'rightText',
desc
:
'
右侧文案
'
,
// name: '右侧文案',
default
:
''
,
// desc: '右侧文案',
options
:
[
// default: '',
'
info
'
,
// options: [
'
danger
'
,
// 'info',
'
primary
'
,
// 'danger',
'
warning
'
// 'primary',
],
// 'warning'
type
:
'
text
'
// ],
},
// type: 'text'
{
// },
key
:
'
leftArrow
'
,
// {
name
:
'
左侧箭头
'
,
// key: 'leftArrow',
desc
:
'
是否显示左侧箭头
'
,
// name: '左侧箭头',
propType
:
'
boolean
'
,
// desc: '是否显示左侧箭头',
options
:
[],
// propType: 'boolean',
type
:
'
checkbox
'
// options: [],
},
// type: 'checkbox'
{
// },
key
:
'
border
'
,
// {
name
:
'
边框
'
,
// key: 'border',
desc
:
'
是否显示下边框
'
,
// name: '边框',
propType
:
'
boolean
'
,
// desc: '是否显示下边框',
options
:
[],
// propType: 'boolean',
type
:
'
checkbox
'
// options: [],
},
// type: 'checkbox'
{
// },
key
:
'
fixed
'
,
// {
name
:
'
固定导航栏
'
,
// key: 'fixed',
desc
:
'
是否固定导航栏
'
,
// name: '固定导航栏',
propType
:
'
boolean
'
,
// desc: '是否固定导航栏',
options
:
[],
// propType: 'boolean',
type
:
'
checkbox
'
// options: [],
},
// type: 'checkbox'
{
// },
key
:
'
zIndex
'
,
// {
name
:
'
z-index
'
,
// key: 'zIndex',
desc
:
'
元素z-index
'
,
// name: 'z-index',
propType
:
[
// desc: '元素z-index',
'
number
'
,
// propType: [
'
string
'
// 'number',
],
// 'string'
options
:
[],
// ],
type
:
'
text
'
// options: [],
}
// type: 'text'
],
// }
value
:
{
// ],
title
:
''
,
// value: {
leftText
:
'
返回
'
,
// title: '',
rightText
:
''
,
// leftText: '返回',
leftArrow
:
true
,
// rightText: '',
border
:
true
,
// leftArrow: true,
fixed
:
true
,
// border: true,
zIndex
:
'
9999
'
// fixed: true,
},
// zIndex: '9999'
commonStyle
:
{}
// },
}
// commonStyle: {}
// }
];
];
export
const
businessComponents
=
[
// export const businessComponents = [
// kaLoginForm,
// // kaLoginForm,
{
// {
eleName
:
'
cs-ka-login-form
'
,
// eleName: 'cs-ka-login-form',
title
:
'
KA登陆表单
'
,
// title: 'KA登陆表单',
h
:
224
,
// h: 224,
config
:
[
// config: [
{
// {
key
:
'
btnTxt
'
,
// key: 'btnTxt',
name
:
'
按钮文案
'
,
// name: '按钮文案',
type
:
'
text
'
// type: 'text'
},
// },
{
// {
key
:
'
btnColor
'
,
// key: 'btnColor',
name
:
'
按钮颜色
'
,
// name: '按钮颜色',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
{
// {
key
:
'
btnImage
'
,
// key: 'btnImage',
name
:
'
按钮图片
'
,
// name: '按钮图片',
type
:
'
Upload
'
// type: 'Upload'
},
// },
{
// {
key
:
'
vcBgColor
'
,
// key: 'vcBgColor',
name
:
'
验证码背景色(可点击态)
'
,
// name: '验证码背景色(可点击态)',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
{
// {
key
:
'
registerFrom
'
,
// key: 'registerFrom',
name
:
'
渠道号
'
,
// name: '渠道号',
type
:
'
text
'
// type: 'text'
},
// },
],
// ],
value
:
{
// value: {
btnTxt
:
''
,
// btnTxt: '',
btnColor
:
'
#ee0a24
'
,
// btnColor: '#ee0a24',
btnImage
:
'
http://activitystatic.q-gp.com/landing-submit.png
'
,
// btnImage: 'http://activitystatic.q-gp.com/landing-submit.png',
registerFrom
:
''
,
// registerFrom: '',
vcBgColor
:
'
#97d5ff
'
// vcBgColor: '#97d5ff'
},
// },
commonStyle
:
{}
// commonStyle: {}
},
// },
{
// {
eleName
:
'
download-guide
'
,
// eleName: 'download-guide',
title
:
'
下载引导
'
,
// title: '下载引导',
h
:
40
,
// h: 40,
config
:
[
// config: [
{
// {
key
:
'
href
'
,
// key: 'href',
name
:
'
跳转链接
'
,
// name: '跳转链接',
type
:
'
text
'
// type: 'text'
},
// },
{
// {
key
:
'
leftImg
'
,
// key: 'leftImg',
name
:
'
logo
'
,
// name: 'logo',
type
:
'
Upload
'
// type: 'Upload'
}
// }
],
// ],
value
:
{
// value: {
href
:
'
https://s.xyqb.com/4
'
,
// href: 'https://s.xyqb.com/4',
leftImg
:
'
http://activitystatic.q-gp.com/xyqb%402x.png
'
// leftImg: 'http://activitystatic.q-gp.com/xyqb%402x.png'
},
// },
commonStyle
:
{}
// commonStyle: {}
},
// },
{
// {
eleName
:
'
goods-tabs
'
,
// eleName: 'goods-tabs',
title
:
'
商品导航
'
,
// title: '商品导航',
config
:
[
// config: [
{
// {
title
:
'
标签录入
'
,
// title: '标签录入',
children
:
[
// children: [
{
// {
key
:
'
list
'
,
// key: 'list',
name
:
'
添加菜单
'
,
// name: '添加菜单',
type
:
'
FormList
'
,
// type: 'FormList',
formControl
:
[
// formControl: [
{
// {
key
:
'
tabTitle
'
,
// key: 'tabTitle',
name
:
'
名称
'
,
// name: '名称',
type
:
'
text
'
// type: 'text'
},
// },
{
// {
key
:
'
componentId
'
,
// key: 'componentId',
name
:
'
组件
'
,
// name: '组件',
type
:
'
ComponentSelect
'
,
// componentSelect
// type: 'ComponentSelect', // componentSelect
}
// }
]
// ]
}
// }
]
// ]
},
// },
{
// {
title
:
'
标签样式
'
,
// title: '标签样式',
children
:
[
// children: [
{
// {
key
:
'
activeColor
'
,
// key: 'activeColor',
name
:
'
选中态文字颜色
'
,
// name: '选中态文字颜色',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
{
// {
key
:
'
inactiveColor
'
,
// key: 'inactiveColor',
name
:
'
默认态文字颜色
'
,
// name: '默认态文字颜色',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
{
// {
key
:
'
underlineColor
'
,
// key: 'underlineColor',
name
:
'
下划线颜色
'
,
// name: '下划线颜色',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
]
// ]
}
// }
],
// ],
value
:
{
// value: {
list
:
[{
// list: [{
tabTitle
:
'
tab1
'
,
// tabTitle: 'tab1',
componentId
:
'
1
'
// componentId: '1'
},
{
// }, {
tabTitle
:
'
tab2
'
,
// tabTitle: 'tab2',
componentId
:
'
2
'
// componentId: '2'
}],
// }],
activeColor
:
'
#323233
'
,
// activeColor: '#323233',
inactiveColor
:
'
#646566
'
,
// inactiveColor: '#646566',
underlineColor
:
'
#1989fa
'
,
// underlineColor: '#1989fa',
},
// },
commonStyle
:
{}
// commonStyle: {}
},
// },
{
// {
eleName
:
'
Goods
'
,
// eleName: 'Goods',
title
:
'
商品
'
,
// title: '商品',
config
:
[
// config: [
{
// {
title
:
'
商品录入
'
,
// title: '商品录入',
children
:
[{
// children: [{
key
:
'
column
'
,
// key: 'column',
name
:
'
商品列数
'
,
// name: '商品列数',
type
:
'
ColumnSelector
'
// type: 'ColumnSelector'
},
// },
{
// {
key
:
'
goods
'
,
// key: 'goods',
name
:
'
选择商品
'
,
// name: '选择商品',
type
:
'
GoodsTableModal
'
,
// type: 'GoodsTableModal',
formControl
:
[
// formControl: [
{
// {
key
:
'
goodsNumber
'
,
// key: 'goodsNumber',
name
:
'
商品数量
'
,
// name: '商品数量',
type
:
'
number
'
// type: 'number'
}
// }
]
// ]
}]
// }]
},
// },
{
// {
title
:
'
专题推荐
'
,
// title: '专题推荐',
children
:
[
// children: [
{
// {
key
:
'
showSpecial
'
,
// key: 'showSpecial',
name
:
'
显示专题
'
,
// name: '显示专题',
type
:
'
checkbox
'
// type: 'checkbox'
},
// },
{
// {
key
:
'
specialUrl
'
,
// key: 'specialUrl',
name
:
'
专题图片
'
,
// name: '专题图片',
type
:
'
Upload
'
// type: 'Upload'
},
// },
{
// {
key
:
'
specialLink
'
,
// key: 'specialLink',
name
:
'
专题链接
'
,
// name: '专题链接',
type
:
'
text
'
// type: 'text'
},
// },
]
// ]
}
// }
],
// ],
value
:
{
// value: {
goods
:
{
// goods: {
type
:
'
goodsGroup
'
,
// type: 'goodsGroup',
ids
:
[]
// ids: []
},
// },
goodsNumber
:
3
,
// goodsNumber: 3,
column
:
2
,
// column: 2,
showSpecial
:
true
,
// showSpecial: true,
specialUrl
:
''
,
// specialUrl: '',
specialLink
:
''
// specialLink: ''
},
// },
commonStyle
:
{}
// commonStyle: {}
},
// },
{
// {
eleName
:
'
Coupon
'
,
// eleName: 'Coupon',
title
:
'
优惠券
'
,
// title: '优惠券',
config
:
[
// config: [
{
// {
title
:
'
优惠券录入
'
,
// title: '优惠券录入',
children
:
[
// children: [
{
// {
key
:
'
column
'
,
// key: 'column',
name
:
'
优惠券列数
'
,
// name: '优惠券列数',
type
:
'
ColumnSelector
'
// type: 'ColumnSelector'
},
// },
{
// {
key
:
'
couponsList
'
,
// key: 'couponsList',
name
:
'
选择优惠券
'
,
// name: '选择优惠券',
type
:
'
CouponTableModal
'
,
// type: 'CouponTableModal',
formControl
:
[
// formControl: [
{
// {
key
:
'
couponsNumber
'
,
// key: 'couponsNumber',
name
:
'
优惠券数量
'
,
// name: '优惠券数量',
type
:
'
number
'
// type: 'number'
}
// }
]
// ]
},
// },
],
// ],
},
// },
{
// {
title
:
'
优惠券样式
'
,
// title: '优惠券样式',
children
:
[
// children: [
{
// {
key
:
'
bgImage
'
,
// key: 'bgImage',
name
:
'
优惠券背景图片
'
,
// name: '优惠券背景图片',
type
:
'
Upload
'
// type: 'Upload'
},
// },
{
// {
key
:
'
bgColor
'
,
// key: 'bgColor',
name
:
'
优惠券背景颜色
'
,
// name: '优惠券背景颜色',
type
:
'
ColorSelector
'
// type: 'ColorSelector'
},
// },
]
// ]
}
// }
],
// ],
value
:
{
// value: {
couponsList
:
[],
// couponsList: [],
couponsNumber
:
3
,
// couponsNumber: 3,
column
:
3
,
// column: 3,
bgColor
:
''
,
// bgColor: '',
bgImage
:
''
,
// bgImage: '',
},
// },
commonStyle
:
{}
// commonStyle: {}
},
// },
{
// {
eleName
:
'
Advertisement
'
,
// eleName: 'Advertisement',
title
:
'
广告
'
,
// title: '广告',
config
:
[
// config: [
{
// {
key
:
'
column
'
,
// key: 'column',
name
:
'
广告列数
'
,
// name: '广告列数',
type
:
'
ColumnSelector
'
// type: 'ColumnSelector'
},
// },
{
// {
key
:
'
list
'
,
// key: 'list',
name
:
'
添加广告
'
,
// name: '添加广告',
type
:
'
FormList
'
,
// type: 'FormList',
formControl
:
[
// formControl: [
{
// {
key
:
'
img
'
,
// key: 'img',
name
:
'
图片
'
,
// name: '图片',
type
:
'
Upload
'
// type: 'Upload'
},
// },
{
// {
key
:
'
link
'
,
// key: 'link',
name
:
'
链接
'
,
// name: '链接',
type
:
'
text
'
,
// componentSelect
// type: 'text', // componentSelect
}
// }
]
// ]
}
// }
],
// ],
value
:
{
// value: {
list
:
[{
// list: [{
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
}],
// }],
column
:
2
// column: 2
}
// }
},
// },
{
// {
eleName
:
'
Placeholder
'
,
// eleName: 'Placeholder',
title
:
'
楼层间隔
'
,
// title: '楼层间隔',
config
:
[
// config: [
{
// {
key
:
'
height
'
,
// key: 'height',
name
:
'
间隔高度
'
,
// name: '间隔高度',
type
:
'
Slider
'
// type: 'Slider'
},
// },
],
// ],
value
:
{
// value: {
height
:
10
// height: 10
}
// }
},
// },
{
// {
eleName
:
'
GuideCube
'
,
// eleName: 'GuideCube',
title
:
'
导购魔方
'
,
// title: '导购魔方',
config
:
[
// config: [
{
// {
key
:
'
slidesPerColumn
'
,
// key: 'slidesPerColumn',
name
:
'
行数
'
,
// name: '行数',
type
:
'
InputNumber
'
// type: 'InputNumber'
},
// },
{
// {
key
:
'
loop
'
,
// key: 'loop',
name
:
'
循环
'
,
// name: '循环',
type
:
'
checkbox
'
// type: 'checkbox'
},
// },
{
// {
key
:
'
autoplay
'
,
// key: 'autoplay',
name
:
'
自动播放
'
,
// name: '自动播放',
type
:
'
checkbox
'
// type: 'checkbox'
},
// },
{
// {
key
:
'
animation
'
,
// key: 'animation',
name
:
'
切换动画
'
,
// name: '切换动画',
type
:
'
checkbox
'
// type: 'checkbox'
},
// },
{
// {
key
:
'
list
'
,
// key: 'list',
name
:
'
添加导购
'
,
// name: '添加导购',
type
:
'
FormList
'
,
// type: 'FormList',
formControl
:
[
// formControl: [
{
// {
key
:
'
img
'
,
// key: 'img',
name
:
'
图片
'
,
// name: '图片',
type
:
'
Upload
'
// type: 'Upload'
},
// },
{
// {
key
:
'
link
'
,
// key: 'link',
name
:
'
链接
'
,
// name: '链接',
type
:
'
text
'
,
// componentSelect
// type: 'text', // componentSelect
}
// }
]
// ]
}
// }
],
// ],
value
:
{
// value: {
list
:
[{
// list: [{
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
},
{
// }, {
img
:
'
http://activitystatic.q-gp.com/landing-bg.png
'
,
// img: 'http://activitystatic.q-gp.com/landing-bg.png',
link
:
'
http://activitystatic.q-gp.com
'
// link: 'http://activitystatic.q-gp.com'
}],
// }],
slidesPerColumn
:
1
,
// slidesPerColumn: 1,
loop
:
false
,
// loop: false,
autoplay
:
false
,
// autoplay: false,
animation
:
false
// animation: false
}
// }
},
// },
{
// {
eleName
:
'
CustomMarquee
'
,
// eleName: 'CustomMarquee',
title
:
'
跑马灯
'
,
// title: '跑马灯',
config
:
[
// config: [
{
// {
key
:
'
fontColor
'
,
// key: 'fontColor',
name
:
'
字体颜色
'
,
// name: '字体颜色',
type
:
'
ColorSelector
'
,
// type: 'ColorSelector',
},
// },
{
// {
key
:
'
list
'
,
// key: 'list',
name
:
'
添加数据
'
,
// name: '添加数据',
type
:
'
FormList
'
,
// type: 'FormList',
formControl
:
[
// formControl: [
{
// {
key
:
'
text
'
,
// key: 'text',
name
:
'
文案
'
,
// name: '文案',
type
:
'
text
'
// type: 'text'
},
// },
{
// {
key
:
'
link
'
,
// key: 'link',
name
:
'
链接
'
,
// name: '链接',
type
:
'
text
'
// type: 'text'
},
// },
]
// ]
}
// }
],
// ],
value
:
{
// value: {
fontColor
:
'
#666666
'
,
// fontColor: '#666666',
list
:
[{
// list: [{
text
:
'
请输入文案
'
// text: '请输入文案'
},
{
// }, {
text
:
'
请输入文案
'
// text: '请输入文案'
}]
// }]
}
// }
},
// },
];
// ];
\ No newline at end of file
\ No newline at end of file
app/web/page/activity/component/FreedomContainer/index.ts
View file @
c7027cf3
import
{
Component
,
Prop
,
Vue
,
Mixins
}
from
'
vue-property-decorator
'
;
import
{
Component
,
Prop
,
Vue
,
Mixins
}
from
'
vue-property-decorator
'
;
import
{
Action
,
Mutation
,
State
,
Getter
}
from
'
vuex-class
'
;
import
{
Action
,
Mutation
,
State
,
Getter
}
from
'
vuex-class
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
CustomMarquee
from
'
@/lib/Marquee/index.vue
'
;
import
{
resizeDiv
}
from
'
@/service/utils.service
'
;
import
{
resizeDiv
}
from
'
@/service/utils.service
'
;
@
Component
({
components
:
{
CustomMarquee
},
name
:
'
FreedomContainer
'
})
@
Component
({
name
:
'
FreedomContainer
'
})
export
default
class
FreedomContainer
extends
Mixins
(
TransformStyleMixin
)
{
export
default
class
FreedomContainer
extends
Mixins
(
TransformStyleMixin
)
{
@
Getter
(
'
pageData
'
)
pageData
;
@
Getter
(
'
pageData
'
)
pageData
;
@
State
(
state
=>
state
.
activity
.
curChildIndex
)
curChildIndex
;
@
State
(
state
=>
state
.
activity
.
curChildIndex
)
curChildIndex
;
...
...
app/web/page/activity/view/activity/index.ts
View file @
c7027cf3
import
{
Vue
,
Component
,
Watch
,
Provide
,
Mixins
}
from
'
vue-property-decorator
'
;
import
{
Vue
,
Component
,
Watch
,
Provide
,
Mixins
}
from
'
vue-property-decorator
'
;
import
{
Getter
,
State
,
Mutation
}
from
'
vuex-class
'
;
import
FreedomContainer
from
'
../../component/FreedomContainer/index.vue
'
;
import
FreedomContainer
from
'
../../component/FreedomContainer/index.vue
'
;
import
GridLayout
from
'
../../component/VueGridLayout/GridLayout.vue
'
;
import
GridLayout
from
'
../../component/VueGridLayout/GridLayout.vue
'
;
import
GridItem
from
'
../../component/VueGridLayout/GridItem.vue
'
;
import
GridItem
from
'
../../component/VueGridLayout/GridItem.vue
'
;
// import LoginForm from '@/lib/Form/index.vue';
import
DownloadGuide
from
'
@/lib/DownloadGuide/index.vue
'
;
import
{
Getter
,
State
,
Mutation
}
from
'
vuex-class
'
;
import
GuideCube
from
'
@/lib/GuideCube/index.vue
'
;
import
GoodsTabs
from
'
@/lib/GoodsTabs/index.vue
'
;
import
Coupon
from
'
@/lib/Coupon/index.vue
'
;
import
Advertisement
from
'
@/lib/Advertisement/index.vue
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
{
getStyle
}
from
'
@/service/utils.service
'
;
import
{
getStyle
}
from
'
@/service/utils.service
'
;
@
Component
({
components
:
{
FreedomContainer
,
GridLayout
,
GridItem
,
DownloadGuide
,
GoodsTabs
,
GuideCube
,
Advertisement
,
Coupon
},
name
:
'
Activity
'
})
@
Component
({
components
:
{
FreedomContainer
,
GridLayout
,
GridItem
},
name
:
'
Activity
'
})
export
default
class
Activity
extends
Mixins
(
TransformStyleMixin
)
{
export
default
class
Activity
extends
Mixins
(
TransformStyleMixin
)
{
@
Getter
(
'
pageData
'
)
pageData
;
@
Getter
(
'
pageData
'
)
pageData
;
@
State
(
state
=>
state
.
activity
.
pageInfo
.
pageName
)
pageName
;
@
State
(
state
=>
state
.
activity
.
pageInfo
.
pageName
)
pageName
;
...
...
app/web/page/store/modules/activity/index.ts
View file @
c7027cf3
...
@@ -17,7 +17,7 @@ export default class EditorModule implements Module<EditorState, RootState> {
...
@@ -17,7 +17,7 @@ export default class EditorModule implements Module<EditorState, RootState> {
actions
:
ActionTree
<
EditorState
,
RootState
>
=
{
actions
:
ActionTree
<
EditorState
,
RootState
>
=
{
async
getPageDate
({
commit
},
condition
)
{
async
getPageDate
({
commit
},
condition
)
{
const
res
=
await
api
.
getPageById
(
condition
);
const
[
res
]
=
await
api
.
getPageById
(
condition
);
const
{
page
,
...
rest
}
=
res
as
PageInfo
;
const
{
page
,
...
rest
}
=
res
as
PageInfo
;
commit
(
SET_PAGE_INFO
,
{
...
rest
,
page
:
JSON
.
parse
(
page
as
string
)
});
commit
(
SET_PAGE_INFO
,
{
...
rest
,
page
:
JSON
.
parse
(
page
as
string
)
});
}
}
...
...
app/web/service/eventBus.service.ts
deleted
100644 → 0
View file @
67a5e0c2
import
Vue
from
'
vue
'
;
export
default
new
Vue
();
\ No newline at end of file
app/web/service/http.service.ts
View file @
c7027cf3
// tslint:disable
// import store from '@/store';
import
Toast
from
'
@qg/cherry-ui/src/toast
'
;
import
axios
from
'
axios
'
;
import
axios
from
'
axios
'
;
import
basicConfig
from
'
../config
'
;
import
strategyModes
from
'
@/config/http.config
'
;
import
localStorage
from
'
./localStorage.service
'
;
// import { Notify } from '@qg/cherry-ui';
import
Notify
from
'
@qg/cherry-ui/src/notify
'
;
const
ERR_MESSAGE_MAP
=
{
const
ERR_MESSAGE_MAP
=
{
status
:
{
status
:
{
400
:
'
错误请求
'
,
400
:
'
错误请求
'
,
401
:
'
未授权
,请重新登录
'
,
401
:
'
您未登录或登录超时
,请重新登录
'
,
403
:
'
拒绝访问
'
,
403
:
'
拒绝访问
'
,
404
:
'
请求错误,未找到该资源
'
,
404
:
'
请求错误,未找到该资源
'
,
405
:
'
请求方法未允许
'
,
405
:
'
请求方法未允许
'
,
...
@@ -20,125 +20,102 @@ const ERR_MESSAGE_MAP = {
...
@@ -20,125 +20,102 @@ const ERR_MESSAGE_MAP = {
505
:
'
http版本不支持该请求
'
505
:
'
http版本不支持该请求
'
}
}
};
};
const
defaultStratege
=
{
default
:
{
request
(
cfg
)
{
return
cfg
;
},
response
(
res
)
{
return
res
.
data
;
}
}
};
const
config
=
{
timeout
:
15000
};
const
CancelToken
=
axios
.
CancelToken
;
const
CancelToken
=
axios
.
CancelToken
;
const
instance
=
axios
.
create
(
config
);
const
pending
=
{};
const
pending
=
{};
let
reqNum
=
0
;
let
reqNum
=
0
;
axios
.
defaults
.
baseURL
=
basicConfig
.
apiHost
;
let
timeId
=
null
;
axios
.
defaults
.
timeout
=
30000
;
strategyModes
.
default
=
defaultStratege
;
axios
.
defaults
.
xsrfHeaderName
=
'
x-csrf-token
'
;
axios
.
defaults
.
xsrfCookieName
=
'
csrfToken
'
;
const
wait
=
async
seconds
=>
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
seconds
));
// 体验优化暂时下掉loading
function
beforeRequest
()
{
function
beforeRequest
()
{
reqNum
++
;
reqNum
++
;
// store.dispatch("setIsLoading", true);
clearTimeout
(
timeId
);
timeId
=
setTimeout
(()
=>
{
// store.dispatch('change_loading', true);
},
1300
);
}
}
function
afterRequest
()
{
function
afterRequest
()
{
clearRequest
();
// setTimeout(clearRequest, 300);
}
function
clearRequest
()
{
reqNum
--
;
reqNum
--
;
if
(
reqNum
<=
0
)
{
if
(
reqNum
<=
0
)
{
// store.dispatch("setIsLoading", false);
clearRequest
();
// store.dispatch('change_loading', false);
}
}
}
}
const
instance
=
axios
.
create
();
function
clearRequest
()
{
clearTimeout
(
timeId
);
}
// 请求拦截器
// 请求拦截器
instance
.
interceptors
.
request
.
use
(
instance
.
interceptors
.
request
.
use
(
config
=>
{
config
=>
{
// op-api识别API使用
!
config
.
hideLoading
&&
beforeRequest
(
config
?.
url
||
''
);
config
.
headers
[
'
X-Requested-With
'
]
=
'
XMLHttpRequest
'
;
// beforeRequest();
// 发起请求时,取消掉当前正在进行的相同请求
// 发起请求时,取消掉当前正在进行的相同请求
if
(
pending
[
config
.
url
as
string
])
{
// 发起请求时,取消掉当前正在进行的相同请求
pending
[
config
.
url
as
string
](
'
取消重复请求
'
);
if
(
pending
[
config
.
url
])
{
pending
[
config
.
url
](
'
取消重复请求
'
);
}
}
config
.
cancelToken
=
new
CancelToken
(
c
=>
(
pending
[(
config
.
url
+
JSON
.
stringify
(
config
.
data
))
as
string
]
=
c
));
config
.
cancelToken
=
new
CancelToken
(
c
=>
(
pending
[
config
.
url
]
=
c
));
// 添加token
// 使用默认响应处理策略
const
token
=
localStorage
.
get
(
'
token
'
);
if
(
!
config
.
strategy
)
{
if
(
token
&&
!
config
.
hideToken
)
{
config
.
strategy
=
'
service
'
;
config
.
headers
[
'
X-Auth-Token
'
]
=
token
;
}
if
(
config
.
accessToken
)
{
config
.
headers
[
'
Access-Token
'
]
=
token
;
}
if
(
strategyModes
[
config
.
strategy
].
request
)
{
config
=
strategyModes
[
config
.
strategy
].
request
(
config
);
}
}
return
config
;
return
config
;
},
},
error
=>
{
error
=>
{
return
Promise
.
reject
(
error
)
;
return
[
null
,
error
]
;
}
}
);
);
// 响应拦截器即异常处理
// 响应拦截器即异常处理
instance
.
interceptors
.
response
.
use
(
instance
.
interceptors
.
response
.
use
(
response
=>
{
response
=>
{
let
notifyType
=
'
danger
'
;
if
(
response
.
config
?.
url
)
{
// afterRequest();
!
config
.
hideLoading
&&
afterRequest
();
delete
pending
[
response
.
config
?.
url
||
''
];
delete
pending
[
response
.
config
.
url
as
string
];
const
codeArr
=
[
'
0000
'
,
2000
];
if
(
codeArr
.
includes
(
response
.
data
.
code
))
{
return
response
.
data
.
data
;
}
// 后端返回异常信息时提出警告
if
(
response
.
data
.
code
&&
response
.
data
.
msg
)
{
notifyType
=
'
warning
'
;
}
Notify
({
type
:
notifyType
,
message
:
response
.
data
.
msg
||
'
后端服务异常
'
,
duration
:
notifyType
===
'
warning
'
?
6000
:
3000
});
if
(
response
.
data
.
code
===
'
40100
'
)
{
localStorage
.
remove
(
'
Token
'
);
}
return
Promise
.
reject
(
response
.
data
);
},
async
err
=>
{
// afterRequest();
// 判断是否取消请求
if
(
err
?.
message
===
'
取消重复请求
'
)
{
const
res
=
{
status
:
409
,
data
:
{}
};
return
Promise
.
resolve
(
res
);
}
// 提示网络错误时尝试重试
if
(
err
.
message
===
'
Network Error
'
&&
(
!
err
.
config
?.
retryCount
||
err
.
config
?.
retryCount
<=
3
)
)
{
if
(
!
err
.
config
?.
retryCount
)
{
err
.
config
.
retryCount
=
1
;
}
err
.
config
.
retryCount
++
;
await
wait
(
3000
);
return
axios
.
request
(
err
.
config
);
}
}
if
(
err
.
response
)
{
return
strategyModes
[
response
.
config
?.
strategy
].
response
(
response
);
switch
(
err
.
response
.
status
)
{
},
case
401
:
err
=>
{
window
.
location
.
href
=
`
${
window
.
location
.
origin
}
/editor/login`
;
!
config
.
hideLoading
&&
afterRequest
();
return
;
}
}
// 错误提示
let
message
=
''
;
let
message
=
''
;
if
(
err
.
response
)
{
let
showToast
=
true
;
message
=
ERR_MESSAGE_MAP
.
status
[
err
.
response
.
status
]
||
`连接错误
${
err
.
response
.
status
}
`
;
}
else
{
if
(
err
.
message
===
'
Network Error
'
&&
!
err
.
response
)
{
message
=
'
连接到服务器失败
'
;
// 网络异常: 错误域名,
message
=
'
服务不可用
'
;
}
else
if
(
err
.
response
&&
err
.
response
?.
status
)
{
message
=
ERR_MESSAGE_MAP
.
status
[
err
.
response
?.
status
]
||
`未知异常码:
${
err
.
response
?.
status
}
`;
} else if (err.message === '取消重复请求') {
message = '取消重复请求';
showToast = false;
}
}
Notify
({
type
:
'
danger
'
,
message
});
showToast && Toast(message || '服务异常,请稍后重试');
return
Promise
.
reject
(
err
);
const error = new Error(message);
console.error(error);
return [null, error];
}
}
);
);
export default instance;
export default instance;
app/web/service/init.service.ts
0 → 100644
View file @
c7027cf3
// import store from '../store';
import
{
isWechat
,
isApp
}
from
'
./utils.service
'
;
import
Cookies
from
'
./cookieStorage.service
'
;
import
localStorage
from
'
./localStorage.service
'
;
// formXcxPage:标识是从小程序跳转过来的;
const
localStorageParams
=
[
'
creditToken
'
,
'
vccToken
'
,
'
vccChannel
'
,
'
formXcxPage
'
];
const
cookiesParams
=
[
'
h
'
];
export
default
{
// token校验,整个流程都是登陆后的
init
:
router
=>
{
router
.
beforeEach
((
to
,
from
,
next
)
=>
{
// 所有自定义路由字段在此处理
const
{
meta
}
=
to
;
// meta?.has?.header && store.commit('CHANGE_HEADER', meta.has.header); // 改变header
localStorageParams
.
forEach
(
item
=>
{
to
.
query
[
item
]
&&
localStorage
.
set
(
item
,
to
.
query
[
item
]);
});
cookiesParams
.
forEach
(
item
=>
{
to
.
query
[
item
]
&&
Cookies
.
set
(
item
,
to
.
query
[
item
]);
});
// (isWechat || isApp || Cookies.get('h') === '0') && store.commit('CHANGE_HEADER', false); // 改变header
// document.body.className = store.state.pay.header ? 'has-header' : '';
// store.commit('CHANGE_TITLE', meta?.title); // 改变title
next
();
});
}
};
app/web/service/qg.service.ts
View file @
c7027cf3
...
@@ -38,6 +38,7 @@ import Tabs from '@qg/cherry-ui/src/tabs';
...
@@ -38,6 +38,7 @@ import Tabs from '@qg/cherry-ui/src/tabs';
import
BackTop
from
'
@qg/cherry-ui/src/back-top
'
;
import
BackTop
from
'
@qg/cherry-ui/src/back-top
'
;
import
Notify
from
'
@qg/cherry-ui/src/notify
'
;
import
Notify
from
'
@qg/cherry-ui/src/notify
'
;
import
Toast
from
'
@qg/cherry-ui/src/toast
'
;
import
Toast
from
'
@qg/cherry-ui/src/toast
'
;
import
citrusUi
from
'
@qg/citrus-ui
'
;
Vue
.
use
(
Button
);
Vue
.
use
(
Button
);
Vue
.
use
(
Image
);
Vue
.
use
(
Image
);
...
@@ -66,7 +67,7 @@ Vue.use(Tabs);
...
@@ -66,7 +67,7 @@ Vue.use(Tabs);
// Vue.use(Swipe);
// Vue.use(Swipe);
Vue
.
use
(
BackTop
);
Vue
.
use
(
BackTop
);
// Vue.use(KaLoginForm
);
Vue
.
use
(
citrusUi
);
Vue
.
prototype
.
$notify
=
Notify
;
Vue
.
prototype
.
$notify
=
Notify
;
Vue
.
prototype
.
$toast
=
Toast
;
Vue
.
prototype
.
$toast
=
Toast
;
app/web/service/qiniu.service.ts
deleted
100644 → 0
View file @
67a5e0c2
// tslint:disable
/*!
* qiniu-js-sdk v1.0.19
*
* Copyright 2015 by Qiniu
* Released under GPL V2 License.
*
* GitHub: http://github.com/qiniu/js-sdk
*
* Date: 2017-3-
*/
/* global plupload ,mOxie */
/* global ActiveXObject */
/* exported Qiniu */
/* exported QiniuJsSDK */
/*eslint-disable*/
(
function
(
global
)
{
/**
* Creates new cookie or removes cookie with negative expiration
* @param key The key or identifier for the store
* @param value Contents of the store
* @param exp Expiration - creation defaults to 30 days
*/
function
createCookie
(
key
,
value
,
exp
)
{
const
date
=
new
Date
();
date
.
setTime
(
date
.
getTime
()
+
exp
*
24
*
60
*
60
*
1000
);
const
expires
=
'
; expires=
'
+
date
.
toGMTString
();
document
.
cookie
=
key
+
'
=
'
+
value
+
expires
+
'
; path=/
'
;
}
/**
* Returns contents of cookie
* @param key The key or identifier for the store
*/
function
readCookie
(
key
)
{
const
nameEQ
=
key
+
'
=
'
;
const
ca
=
document
.
cookie
.
split
(
'
;
'
);
for
(
let
i
=
0
,
max
=
ca
.
length
;
i
<
max
;
i
++
)
{
let
c
=
ca
[
i
];
while
(
c
.
charAt
(
0
)
===
'
'
)
{
c
=
c
.
substring
(
1
,
c
.
length
);
}
if
(
c
.
indexOf
(
nameEQ
)
===
0
)
{
return
c
.
substring
(
nameEQ
.
length
,
c
.
length
);
}
}
return
null
;
}
// if current browser is not support localStorage
// use cookie to make a polyfill
if
(
!
window
.
localStorage
)
{
window
.
localStorage
=
{
setItem
(
key
,
value
)
{
createCookie
(
key
,
value
,
30
);
},
getItem
(
key
)
{
return
readCookie
(
key
);
},
removeItem
(
key
)
{
createCookie
(
key
,
''
,
-
1
);
},
};
}
function
QiniuJsSDK
()
{
const
that
=
this
;
/**
* detect IE version
* if current browser is not IE
* it will return false
* else
* it will return version of current IE browser
* @return {Number|Boolean} IE version or false
*/
this
.
detectIEVersion
=
function
()
{
let
v
=
4
;
const
div
=
document
.
createElement
(
'
div
'
);
const
all
=
div
.
getElementsByTagName
(
'
i
'
);
while
(((
div
.
innerHTML
=
'
<!--[if gt IE
'
+
v
+
'
]><i></i><![endif]-->
'
),
all
[
0
]))
{
v
++
;
}
return
v
>
4
?
v
:
false
;
};
const
logger
=
{
MUTE
:
0
,
FATA
:
1
,
ERROR
:
2
,
WARN
:
3
,
INFO
:
4
,
DEBUG
:
5
,
TRACE
:
6
,
level
:
0
,
};
function
log
(
type
,
args
)
{
const
header
=
'
[qiniu-js-sdk][
'
+
type
+
'
]
'
;
let
msg
=
header
;
for
(
let
i
=
0
;
i
<
args
.
length
;
i
++
)
{
if
(
typeof
args
[
i
]
===
'
string
'
)
{
msg
+=
'
'
+
args
[
i
];
}
else
{
msg
+=
'
'
+
that
.
stringifyJSON
(
args
[
i
]);
}
}
if
(
that
.
detectIEVersion
())
{
// http://stackoverflow.com/questions/5538972/console-log-apply-not-working-in-ie9
// var log = Function.prototype.bind.call(console.log, console);
// log.apply(console, args);
console
.
log
(
msg
);
}
else
{
args
.
unshift
(
header
);
console
.
log
.
apply
(
console
,
args
);
}
if
(
document
.
getElementById
(
'
qiniu-js-sdk-log
'
))
{
document
.
getElementById
(
'
qiniu-js-sdk-log
'
).
innerHTML
+=
'
<p>
'
+
msg
+
'
</p>
'
;
}
}
function
makeLogFunc
(
code
)
{
const
func
=
code
.
toLowerCase
();
logger
[
func
]
=
function
()
{
// logger[func].history = logger[func].history || [];
// logger[func].history.push(arguments);
if
(
window
.
console
&&
window
.
console
.
log
&&
logger
.
level
>=
logger
[
code
])
{
const
args
=
Array
.
prototype
.
slice
.
call
(
arguments
);
log
(
func
,
args
);
}
};
}
for
(
const
property
in
logger
)
{
if
(
logger
.
hasOwnProperty
(
property
)
&&
typeof
logger
[
property
]
===
'
number
'
&&
!
logger
.
hasOwnProperty
(
property
.
toLowerCase
()))
{
makeLogFunc
(
property
);
}
}
let
qiniuUploadUrl
;
if
(
window
.
location
.
protocol
===
'
https:
'
)
{
qiniuUploadUrl
=
'
https://up.qbox.me
'
;
}
else
{
qiniuUploadUrl
=
'
http://upload.qiniu.com
'
;
}
/**
* qiniu upload urls
* 'qiniuUploadUrls' is used to change target when current url is not avaliable
* @type {Array}
*/
const
qiniuUploadUrls
=
[
'
http://upload.qiniu.com
'
,
'
http://up.qiniu.com
'
];
const
qiniuUpHosts
=
{
http
:
[
'
http://upload.qiniu.com
'
,
'
http://up.qiniu.com
'
],
https
:
[
'
https://up.qbox.me
'
],
};
let
changeUrlTimes
=
0
;
/**
* reset upload url
* if current page protocal is https
* it will always return 'https://up.qbox.me'
* else
* it will set 'qiniuUploadUrl' value with 'qiniuUploadUrls' looply
*/
this
.
resetUploadUrl
=
function
()
{
const
hosts
=
window
.
location
.
protocol
===
'
https:
'
?
qiniuUpHosts
.
https
:
qiniuUpHosts
.
http
;
const
i
=
changeUrlTimes
%
hosts
.
length
;
qiniuUploadUrl
=
hosts
[
i
];
changeUrlTimes
++
;
logger
.
debug
(
'
resetUploadUrl:
'
+
qiniuUploadUrl
);
};
// this.resetUploadUrl();
/**
* is image
* @param {String} url of a file
* @return {Boolean} file is a image or not
*/
this
.
isImage
=
function
(
url
)
{
url
=
url
.
split
(
/
[
?#
]
/
)[
0
];
return
/
\.(
png|jpg|jpeg|gif|bmp
)
$/i
.
test
(
url
);
};
/**
* get file extension
* @param {String} filename
* @return {String} file extension
* @example
* input: test.txt
* output: txt
*/
this
.
getFileExtension
=
function
(
filename
)
{
const
tempArr
=
filename
.
split
(
'
.
'
);
let
ext
;
if
(
tempArr
.
length
===
1
||
(
tempArr
[
0
]
===
''
&&
tempArr
.
length
===
2
))
{
ext
=
''
;
}
else
{
ext
=
tempArr
.
pop
().
toLowerCase
();
// get the extension and make it lower-case
}
return
ext
;
};
/**
* encode string by utf8
* @param {String} string to encode
* @return {String} encoded string
*/
this
.
utf8_encode
=
function
(
argString
)
{
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: sowberry
// + tweaked by: Jack
// + bugfixed by: Onno Marsman
// + improved by: Yves Sucaet
// + bugfixed by: Onno Marsman
// + bugfixed by: Ulrich
// + bugfixed by: Rafal Kukawski
// + improved by: kirilloid
// + bugfixed by: kirilloid
// * example 1: this.utf8_encode('Kevin van Zonneveld');
// * returns 1: 'Kevin van Zonneveld'
if
(
argString
===
null
||
typeof
argString
===
'
undefined
'
)
{
return
''
;
}
const
string
=
argString
+
''
;
// .replace(/\r\n/g, '\n').replace(/\r/g, '\n');
let
utftext
=
''
;
let
start
;
let
end
;
let
stringl
=
0
;
start
=
end
=
0
;
stringl
=
string
.
length
;
for
(
let
n
=
0
;
n
<
stringl
;
n
++
)
{
let
c1
=
string
.
charCodeAt
(
n
);
let
enc
=
null
;
if
(
c1
<
128
)
{
end
++
;
}
else
if
(
c1
>
127
&&
c1
<
2048
)
{
enc
=
String
.
fromCharCode
((
c1
>>
6
)
|
192
,
(
c1
&
63
)
|
128
);
}
else
if
((
c1
&
0xf800
)
^
(
0xd800
>
0
))
{
enc
=
String
.
fromCharCode
((
c1
>>
12
)
|
224
,
((
c1
>>
6
)
&
63
)
|
128
,
(
c1
&
63
)
|
128
);
}
else
{
// surrogate pairs
if
((
c1
&
0xfc00
)
^
(
0xd800
>
0
))
{
throw
new
RangeError
(
'
Unmatched trail surrogate at
'
+
n
);
}
const
c2
=
string
.
charCodeAt
(
++
n
);
if
((
c2
&
0xfc00
)
^
(
0xdc00
>
0
))
{
throw
new
RangeError
(
'
Unmatched lead surrogate at
'
+
(
n
-
1
));
}
c1
=
((
c1
&
0x3ff
)
<<
10
)
+
(
c2
&
0x3ff
)
+
0x10000
;
enc
=
String
.
fromCharCode
((
c1
>>
18
)
|
240
,
((
c1
>>
12
)
&
63
)
|
128
,
((
c1
>>
6
)
&
63
)
|
128
,
(
c1
&
63
)
|
128
);
}
if
(
enc
!==
null
)
{
if
(
end
>
start
)
{
utftext
+=
string
.
slice
(
start
,
end
);
}
utftext
+=
enc
;
start
=
end
=
n
+
1
;
}
}
if
(
end
>
start
)
{
utftext
+=
string
.
slice
(
start
,
stringl
);
}
return
utftext
;
};
this
.
base64_decode
=
function
(
data
)
{
// http://kevin.vanzonneveld.net
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Thunder.m
// + input by: Aman Gupta
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Onno Marsman
// + bugfixed by: Pellentesque Malesuada
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + input by: Brett Zamir (http://brett-zamir.me)
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
// * returns 1: 'Kevin van Zonneveld'
// mozilla has this native
// - but breaks in 2.0.0.12!
// if (typeof this.window['atob'] == 'function') {
// return atob(data);
// }
const
b64
=
'
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
'
;
let
o1
;
let
o2
;
let
o3
;
let
h1
;
let
h2
;
let
h3
;
let
h4
;
let
bits
;
let
i
=
0
;
let
ac
=
0
;
let
dec
=
''
;
const
tmp_arr
=
[];
if
(
!
data
)
{
return
data
;
}
data
+=
''
;
do
{
// unpack four hexets into three octets using index points in b64
h1
=
b64
.
indexOf
(
data
.
charAt
(
i
++
));
h2
=
b64
.
indexOf
(
data
.
charAt
(
i
++
));
h3
=
b64
.
indexOf
(
data
.
charAt
(
i
++
));
h4
=
b64
.
indexOf
(
data
.
charAt
(
i
++
));
bits
=
(
h1
<<
18
)
|
(
h2
<<
12
)
|
(
h3
<<
6
)
|
h4
;
o1
=
(
bits
>>
16
)
&
0xff
;
o2
=
(
bits
>>
8
)
&
0xff
;
o3
=
bits
&
0xff
;
if
(
h3
===
64
)
{
tmp_arr
[
ac
++
]
=
String
.
fromCharCode
(
o1
);
}
else
if
(
h4
===
64
)
{
tmp_arr
[
ac
++
]
=
String
.
fromCharCode
(
o1
,
o2
);
}
else
{
tmp_arr
[
ac
++
]
=
String
.
fromCharCode
(
o1
,
o2
,
o3
);
}
}
while
(
i
<
data
.
length
);
dec
=
tmp_arr
.
join
(
''
);
return
dec
;
};
/**
* encode data by base64
* @param {String} data to encode
* @return {String} encoded data
*/
this
.
base64_encode
=
function
(
data
)
{
// http://kevin.vanzonneveld.net
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Bayron Guevara
// + improved by: Thunder.m
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Pellentesque Malesuada
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// - depends on: this.utf8_encode
// * example 1: this.base64_encode('Kevin van Zonneveld');
// * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
// mozilla has this native
// - but breaks in 2.0.0.12!
// if (typeof this.window['atob'] == 'function') {
// return atob(data);
// }
const
b64
=
'
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
'
;
let
o1
;
let
o2
;
let
o3
;
let
h1
;
let
h2
;
let
h3
;
let
h4
;
let
bits
;
let
i
=
0
;
let
ac
=
0
;
let
enc
=
''
;
const
tmp_arr
=
[];
if
(
!
data
)
{
return
data
;
}
data
=
this
.
utf8_encode
(
data
+
''
);
do
{
// pack three octets into four hexets
o1
=
data
.
charCodeAt
(
i
++
);
o2
=
data
.
charCodeAt
(
i
++
);
o3
=
data
.
charCodeAt
(
i
++
);
bits
=
(
o1
<<
16
)
|
(
o2
<<
8
)
|
o3
;
h1
=
(
bits
>>
18
)
&
0x3f
;
h2
=
(
bits
>>
12
)
&
0x3f
;
h3
=
(
bits
>>
6
)
&
0x3f
;
h4
=
bits
&
0x3f
;
// use hexets to index into b64, and append result to encoded string
tmp_arr
[
ac
++
]
=
b64
.
charAt
(
h1
)
+
b64
.
charAt
(
h2
)
+
b64
.
charAt
(
h3
)
+
b64
.
charAt
(
h4
);
}
while
(
i
<
data
.
length
);
enc
=
tmp_arr
.
join
(
''
);
switch
(
data
.
length
%
3
)
{
case
1
:
enc
=
enc
.
slice
(
0
,
-
2
)
+
'
==
'
;
break
;
case
2
:
enc
=
enc
.
slice
(
0
,
-
1
)
+
'
=
'
;
break
;
}
return
enc
;
};
/**
* encode string in url by base64
* @param {String} string in url
* @return {String} encoded string
*/
this
.
URLSafeBase64Encode
=
function
(
v
)
{
v
=
this
.
base64_encode
(
v
);
return
v
.
replace
(
/
\/
/g
,
'
_
'
).
replace
(
/
\+
/g
,
'
-
'
);
};
this
.
URLSafeBase64Decode
=
function
(
v
)
{
v
=
v
.
replace
(
/_/g
,
'
/
'
).
replace
(
/-/g
,
'
+
'
);
return
this
.
base64_decode
(
v
);
};
// TODO: use mOxie
/**
* craete object used to AJAX
* @return {Object}
*/
this
.
createAjax
=
function
(
argument
)
{
let
xmlhttp
=
{};
if
(
window
.
XMLHttpRequest
)
{
xmlhttp
=
new
XMLHttpRequest
();
}
else
{
xmlhttp
=
new
ActiveXObject
(
'
Microsoft.XMLHTTP
'
);
}
return
xmlhttp
;
};
// TODO: enhance IE compatibility
/**
* parse json string to javascript object
* @param {String} json string
* @return {Object} object
*/
this
.
parseJSON
=
function
(
data
)
{
// Attempt to parse using the native JSON parser first
if
(
window
.
JSON
&&
window
.
JSON
.
parse
)
{
return
window
.
JSON
.
parse
(
data
);
}
// var rx_one = /^[\],:{}\s]*$/,
// rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
// rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
// rx_four = /(?:^|:|,)(?:\s*\[)+/g,
const
rx_dangerous
=
/
[\u
0000
\u
00ad
\u
0600-
\u
0604
\u
070f
\u
17b4
\u
17b5
\u
200c-
\u
200f
\u
2028-
\u
202f
\u
2060-
\u
206f
\u
feff
\u
fff0-
\u
ffff
]
/g
;
// var json;
let
text
=
String
(
data
);
rx_dangerous
.
lastIndex
=
0
;
if
(
rx_dangerous
.
test
(
text
))
{
text
=
text
.
replace
(
rx_dangerous
,
function
(
a
)
{
return
'
\\
u
'
+
(
'
0000
'
+
a
.
charCodeAt
(
0
).
toString
(
16
)).
slice
(
-
4
);
});
}
// todo 使用一下判断,增加安全性
// if (
// rx_one.test(
// text
// .replace(rx_two, '@')
// .replace(rx_three, ']')
// .replace(rx_four, '')
// )
// ) {
// return eval('(' + text + ')');
// }
return
eval
(
'
(
'
+
text
+
'
)
'
);
};
/**
* parse javascript object to json string
* @param {Object} object
* @return {String} json string
*/
this
.
stringifyJSON
=
function
(
obj
)
{
// Attempt to parse using the native JSON parser first
if
(
window
.
JSON
&&
window
.
JSON
.
stringify
)
{
return
window
.
JSON
.
stringify
(
obj
);
}
switch
(
typeof
obj
)
{
case
'
string
'
:
return
'
"
'
+
obj
.
replace
(
/
([
"
\\])
/g
,
'
\\
$1
'
)
+
'
"
'
;
case
'
array
'
:
return
'
[
'
+
obj
.
map
(
that
.
stringifyJSON
).
join
(
'
,
'
)
+
'
]
'
;
case
'
object
'
:
if
(
obj
instanceof
Array
)
{
const
strArr
=
[];
const
len
=
obj
.
length
;
for
(
let
i
=
0
;
i
<
len
;
i
++
)
{
strArr
.
push
(
that
.
stringifyJSON
(
obj
[
i
]));
}
return
'
[
'
+
strArr
.
join
(
'
,
'
)
+
'
]
'
;
}
else
if
(
obj
===
null
)
{
return
'
null
'
;
}
else
{
const
string
=
[];
for
(
const
property
in
obj
)
{
if
(
obj
.
hasOwnProperty
(
property
))
{
string
.
push
(
that
.
stringifyJSON
(
property
)
+
'
:
'
+
that
.
stringifyJSON
(
obj
[
property
]));
}
}
return
'
{
'
+
string
.
join
(
'
,
'
)
+
'
}
'
;
}
break
;
case
'
number
'
:
return
obj
;
case
false
:
return
obj
;
case
'
boolean
'
:
return
obj
;
}
};
/**
* trim space beside text
* @param {String} untrimed string
* @return {String} trimed string
*/
this
.
trim
=
function
(
text
)
{
return
text
===
null
?
''
:
text
.
replace
(
/^
\s
+|
\s
+$/g
,
''
);
};
/**
* create a uploader by QiniuJsSDK
* @param {object} options to create a new uploader
* @return {object} uploader
*/
this
.
uploader
=
function
(
op
)
{
/** ******** inner function define start **********/
// according the different condition to reset chunk size
// and the upload strategy according with the chunk size
// when chunk size is zero will cause to direct upload
// see the statement binded on 'BeforeUpload' event
const
reset_chunk_size
=
function
()
{
const
ie
=
that
.
detectIEVersion
();
let
BLOCK_BITS
,
MAX_CHUNK_SIZE
,
chunk_size
;
// case Safari 5、Windows 7、iOS 7 set isSpecialSafari to true
const
isSpecialSafari
=
(
mOxie
.
Env
.
browser
===
'
Safari
'
&&
mOxie
.
Env
.
version
<=
5
&&
mOxie
.
Env
.
os
===
'
Windows
'
&&
mOxie
.
Env
.
osVersion
===
'
7
'
)
||
(
mOxie
.
Env
.
browser
===
'
Safari
'
&&
mOxie
.
Env
.
os
===
'
iOS
'
&&
mOxie
.
Env
.
osVersion
===
'
7
'
);
// case IE 9-,chunk_size is not empty and flash is included in runtimes
// set op.chunk_size to zero
// if (ie && ie < 9 && op.chunk_size && op.runtimes.indexOf('flash') >= 0) {
if
(
ie
&&
ie
<
9
&&
op
.
chunk_size
&&
op
.
runtimes
.
indexOf
(
'
flash
'
)
>=
0
)
{
// link: http://www.plupload.com/docs/Frequently-Asked-Questions#when-to-use-chunking-and-when-not
// when plupload chunk_size setting is't null ,it cause bug in ie8/9 which runs flash runtimes (not support html5) .
op
.
chunk_size
=
0
;
}
else
if
(
isSpecialSafari
)
{
// win7 safari / iOS7 safari have bug when in chunk upload mode
// reset chunk_size to 0
// disable chunk in special version safari
op
.
chunk_size
=
0
;
}
else
{
BLOCK_BITS
=
20
;
MAX_CHUNK_SIZE
=
4
<<
BLOCK_BITS
;
// 4M
chunk_size
=
plupload
.
parseSize
(
op
.
chunk_size
);
if
(
chunk_size
>
MAX_CHUNK_SIZE
)
{
op
.
chunk_size
=
MAX_CHUNK_SIZE
;
}
// qiniu service max_chunk_size is 4m
// reset chunk_size to max_chunk_size(4m) when chunk_size > 4m
}
// if op.chunk_size set 0 will be cause to direct upload
};
const
getHosts
=
function
(
hosts
)
{
const
result
=
[];
for
(
let
i
=
0
;
i
<
hosts
.
length
;
i
++
)
{
const
host
=
hosts
[
i
];
if
(
host
.
indexOf
(
'
-H
'
)
===
0
)
{
result
.
push
(
host
.
split
(
'
'
)[
2
]);
}
else
{
result
.
push
(
host
);
}
}
return
result
;
};
const
getPutPolicy
=
function
(
uptoken
)
{
const
segments
=
uptoken
.
split
(
'
:
'
);
const
ak
=
segments
[
0
];
const
putPolicy
=
that
.
parseJSON
(
that
.
URLSafeBase64Decode
(
segments
[
2
]));
putPolicy
.
ak
=
ak
;
if
(
putPolicy
.
scope
.
indexOf
(
'
:
'
)
>=
0
)
{
putPolicy
.
bucket
=
putPolicy
.
scope
.
split
(
'
:
'
)[
0
];
putPolicy
.
key
=
putPolicy
.
scope
.
split
(
'
:
'
)[
1
];
}
else
{
putPolicy
.
bucket
=
putPolicy
.
scope
;
}
return
putPolicy
;
};
const
getUpHosts
=
function
(
uptoken
)
{
const
putPolicy
=
getPutPolicy
(
uptoken
);
// var uphosts_url = "//uc.qbox.me/v1/query?ak="+ak+"&bucket="+putPolicy.scope;
// IE 9- is not support protocal relative url
const
uphosts_url
=
window
.
location
.
protocol
+
'
//uc.qbox.me/v1/query?ak=
'
+
putPolicy
.
ak
+
'
&bucket=
'
+
putPolicy
.
bucket
;
logger
.
debug
(
'
putPolicy:
'
,
putPolicy
);
logger
.
debug
(
'
get uphosts from:
'
,
uphosts_url
);
const
ie
=
that
.
detectIEVersion
();
let
ajax
;
if
(
ie
&&
ie
<=
9
)
{
ajax
=
new
mOxie
.
XMLHttpRequest
();
mOxie
.
Env
.
swf_url
=
op
.
flash_swf_url
;
}
else
{
ajax
=
that
.
createAjax
();
}
ajax
.
open
(
'
GET
'
,
uphosts_url
,
false
);
const
onreadystatechange
=
function
()
{
logger
.
debug
(
'
ajax.readyState:
'
,
ajax
.
readyState
);
if
(
ajax
.
readyState
===
4
)
{
logger
.
debug
(
'
ajax.status:
'
,
ajax
.
status
);
if
(
ajax
.
status
<
400
)
{
const
res
=
that
.
parseJSON
(
ajax
.
responseText
);
qiniuUpHosts
.
http
=
getHosts
(
res
.
http
.
up
);
qiniuUpHosts
.
https
=
getHosts
(
res
.
https
.
up
);
logger
.
debug
(
'
get new uphosts:
'
,
qiniuUpHosts
);
that
.
resetUploadUrl
();
}
else
{
logger
.
error
(
'
get uphosts error:
'
,
ajax
.
responseText
);
}
}
};
if
(
ie
&&
ie
<=
9
)
{
ajax
.
bind
(
'
readystatechange
'
,
onreadystatechange
);
}
else
{
ajax
.
onreadystatechange
=
onreadystatechange
;
}
ajax
.
send
();
// ajax.send();
// if (ajax.status < 400) {
// var res = that.parseJSON(ajax.responseText);
// qiniuUpHosts.http = getHosts(res.http.up);
// qiniuUpHosts.https = getHosts(res.https.up);
// logger.debug("get new uphosts: ", qiniuUpHosts);
// that.resetUploadUrl();
// } else {
// logger.error("get uphosts error: ", ajax.responseText);
// }
};
const
getUptoken
=
function
(
file
)
{
if
(
!
that
.
token
||
(
op
.
uptoken_url
&&
that
.
tokenInfo
.
isExpired
()))
{
return
getNewUpToken
(
file
);
}
else
{
return
that
.
token
;
}
};
// getNewUptoken maybe called at Init Event or BeforeUpload Event
// case Init Event, the file param of getUptken will be set a null value
// if op.uptoken has value, set uptoken with op.uptoken
// else if op.uptoken_url has value, set uptoken from op.uptoken_url
// else if op.uptoken_func has value, set uptoken by result of op.uptoken_func
const
getNewUpToken
=
function
(
file
)
{
if
(
op
.
uptoken
)
{
that
.
token
=
op
.
uptoken
;
}
else
if
(
op
.
uptoken_url
)
{
logger
.
debug
(
'
get uptoken from:
'
,
that
.
uptoken_url
);
// TODO: use mOxie
const
ajax
=
that
.
createAjax
();
ajax
.
open
(
'
GET
'
,
that
.
uptoken_url
,
false
);
ajax
.
setRequestHeader
(
'
If-Modified-Since
'
,
'
0
'
);
// ajax.onreadystatechange = function() {
// if (ajax.readyState === 4 && ajax.status === 200) {
// var res = that.parseJSON(ajax.responseText);
// that.token = res.uptoken;
// }
// };
ajax
.
send
();
if
(
ajax
.
status
===
200
)
{
const
res
=
that
.
parseJSON
(
ajax
.
responseText
);
that
.
token
=
res
.
uptoken
;
const
segments
=
that
.
token
.
split
(
'
:
'
);
const
putPolicy
=
that
.
parseJSON
(
that
.
URLSafeBase64Decode
(
segments
[
2
]));
if
(
!
that
.
tokenMap
)
{
that
.
tokenMap
=
{};
}
const
getTimestamp
=
function
(
time
)
{
return
Math
.
ceil
(
time
.
getTime
()
/
1000
);
};
const
serverTime
=
getTimestamp
(
new
Date
(
ajax
.
getResponseHeader
(
'
date
'
)));
const
clientTime
=
getTimestamp
(
new
Date
());
that
.
tokenInfo
=
{
serverDelay
:
clientTime
-
serverTime
,
deadline
:
putPolicy
.
deadline
,
isExpired
()
{
const
leftTime
=
this
.
deadline
-
getTimestamp
(
new
Date
())
+
this
.
serverDelay
;
return
leftTime
<
600
;
},
};
logger
.
debug
(
'
get new uptoken:
'
,
that
.
token
);
logger
.
debug
(
'
get token info:
'
,
that
.
tokenInfo
);
}
else
{
logger
.
error
(
'
get uptoken error:
'
,
ajax
.
responseText
);
}
}
else
if
(
op
.
uptoken_func
)
{
logger
.
debug
(
'
get uptoken from uptoken_func
'
);
that
.
token
=
op
.
uptoken_func
(
file
);
logger
.
debug
(
'
get new uptoken:
'
,
that
.
token
);
}
else
{
logger
.
error
(
'
one of [uptoken, uptoken_url, uptoken_func] settings in options is required!
'
);
}
if
(
that
.
token
)
{
getUpHosts
(
that
.
token
);
}
return
that
.
token
;
};
// get file key according with the user passed options
const
getFileKey
=
function
(
up
,
file
,
func
)
{
// WARNING
// When you set the key in putPolicy by "scope": "bucket:key"
// You should understand the risk of override a file in the bucket
// So the code below that automatically get key from uptoken has been commented
// var putPolicy = getPutPolicy(that.token)
// if (putPolicy.key) {
// logger.debug("key is defined in putPolicy.scope: ", putPolicy.key)
// return putPolicy.key
// }
let
key
=
''
;
let
unique_names
=
false
;
if
(
!
op
.
save_key
)
{
unique_names
=
up
.
getOption
&&
up
.
getOption
(
'
unique_names
'
);
unique_names
=
unique_names
||
(
up
.
settings
&&
up
.
settings
.
unique_names
);
if
(
unique_names
)
{
const
ext
=
that
.
getFileExtension
(
file
.
name
);
key
=
ext
?
file
.
id
+
'
.
'
+
ext
:
file
.
id
;
}
else
if
(
typeof
func
===
'
function
'
)
{
key
=
func
(
up
,
file
);
}
else
{
key
=
file
.
name
;
}
}
return
key
;
};
/** ******** inner function define end **********/
if
(
op
.
log_level
)
{
logger
.
level
=
op
.
log_level
;
}
if
(
!
op
.
domain
)
{
throw
new
Error
(
'
domain setting in options is required!
'
);
}
if
(
!
op
.
browse_button
)
{
throw
new
Error
(
'
browse_button setting in options is required!
'
);
}
if
(
!
op
.
uptoken
&&
!
op
.
uptoken_url
&&
!
op
.
uptoken_func
)
{
throw
new
Error
(
'
one of [uptoken, uptoken_url, uptoken_func] settings in options is required!
'
);
}
logger
.
debug
(
'
init uploader start
'
);
logger
.
debug
(
'
environment:
'
,
mOxie
.
Env
);
logger
.
debug
(
'
userAgent:
'
,
navigator
.
userAgent
);
const
option
=
{};
// hold the handler from user passed options
const
_Error_Handler
=
op
.
init
&&
op
.
init
.
Error
;
const
_FileUploaded_Handler
=
op
.
init
&&
op
.
init
.
FileUploaded
;
// replace the handler for intercept
op
.
init
.
Error
=
function
()
{};
op
.
init
.
FileUploaded
=
function
()
{};
that
.
uptoken_url
=
op
.
uptoken_url
;
that
.
token
=
''
;
that
.
key_handler
=
typeof
op
.
init
.
Key
===
'
function
'
?
op
.
init
.
Key
:
''
;
this
.
domain
=
op
.
domain
;
// TODO: ctx is global in scope of a uploader instance
// this maybe cause error
let
ctx
=
''
;
const
speedCalInfo
=
{
isResumeUpload
:
false
,
resumeFilesize
:
0
,
startTime
:
''
,
currentTime
:
''
,
};
reset_chunk_size
();
logger
.
debug
(
'
invoke reset_chunk_size()
'
);
logger
.
debug
(
'
op.chunk_size:
'
,
op
.
chunk_size
);
const
defaultSetting
=
{
url
:
qiniuUploadUrl
,
multipart_params
:
{
token
:
''
,
},
};
const
ie
=
that
.
detectIEVersion
();
// case IE 9-
// add accept in multipart params
if
(
ie
&&
ie
<=
9
)
{
defaultSetting
.
multipart_params
.
accept
=
'
text/plain; charset=utf-8
'
;
logger
.
debug
(
'
add accept text/plain in multipart params
'
);
}
// compose options with user passed options and default setting
plupload
.
extend
(
option
,
op
,
defaultSetting
);
logger
.
debug
(
'
option:
'
,
option
);
// create a new uploader with composed options
const
uploader
=
new
plupload
.
Uploader
(
option
);
logger
.
debug
(
'
new plupload.Uploader(option)
'
);
// bind getNewUpToken to 'Init' event
uploader
.
bind
(
'
Init
'
,
function
(
up
,
params
)
{
logger
.
debug
(
'
Init event activated
'
);
// if op.get_new_uptoken is not true
// invoke getNewUptoken when uploader init
// else
// getNewUptoken everytime before a new file upload
if
(
!
op
.
get_new_uptoken
)
{
getNewUpToken
(
null
);
}
// getNewUpToken(null);
});
logger
.
debug
(
'
bind Init event
'
);
// bind 'FilesAdded' event
// when file be added and auto_start has set value
// uploader will auto start upload the file
uploader
.
bind
(
'
FilesAdded
'
,
function
(
up
,
files
)
{
logger
.
debug
(
'
FilesAdded event activated
'
);
let
auto_start
=
up
.
getOption
&&
up
.
getOption
(
'
auto_start
'
);
auto_start
=
auto_start
||
(
up
.
settings
&&
up
.
settings
.
auto_start
);
logger
.
debug
(
'
auto_start:
'
,
auto_start
);
logger
.
debug
(
'
files:
'
,
files
);
// detect is iOS
const
is_ios
=
function
()
{
if
(
mOxie
.
Env
.
OS
.
toLowerCase
()
===
'
ios
'
)
{
return
true
;
}
else
{
return
false
;
}
};
// if current env os is iOS change file name to [time].[ext]
if
(
is_ios
())
{
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
const
file
=
files
[
i
];
const
ext
=
that
.
getFileExtension
(
file
.
name
);
file
.
name
=
file
.
id
+
'
.
'
+
ext
;
}
}
if
(
auto_start
)
{
setTimeout
(
function
()
{
up
.
start
();
logger
.
debug
(
'
invoke up.start()
'
);
},
0
);
// up.start();
// plupload.each(files, function(i, file) {
// up.start();
// logger.debug("invoke up.start()")
// logger.debug("file: ", file);
// });
}
up
.
refresh
();
// Reposition Flash/Silverlight
});
logger
.
debug
(
'
bind FilesAdded event
'
);
// bind 'BeforeUpload' event
// intercept the process of upload
// - prepare uptoken
// - according the chunk size to make differnt upload strategy
// - resume upload with the last breakpoint of file
uploader
.
bind
(
'
BeforeUpload
'
,
function
(
up
,
file
)
{
logger
.
debug
(
'
BeforeUpload event activated
'
);
// add a key named speed for file object
file
.
speed
=
file
.
speed
||
0
;
ctx
=
''
;
if
(
op
.
get_new_uptoken
)
{
getNewUpToken
(
file
);
}
const
directUpload
=
function
(
up
,
file
,
func
)
{
speedCalInfo
.
startTime
=
new
Date
().
getTime
();
let
multipart_params_obj
;
if
(
op
.
save_key
)
{
multipart_params_obj
=
{
token
:
that
.
token
,
};
}
else
{
multipart_params_obj
=
{
key
:
getFileKey
(
up
,
file
,
func
),
token
:
that
.
token
,
};
}
const
ie
=
that
.
detectIEVersion
();
// case IE 9-
// add accept in multipart params
if
(
ie
&&
ie
<=
9
)
{
multipart_params_obj
.
accept
=
'
text/plain; charset=utf-8
'
;
logger
.
debug
(
'
add accept text/plain in multipart params
'
);
}
logger
.
debug
(
'
directUpload multipart_params_obj:
'
,
multipart_params_obj
);
const
x_vars
=
op
.
x_vars
;
if
(
x_vars
!==
undefined
&&
typeof
x_vars
===
'
object
'
)
{
for
(
const
x_key
in
x_vars
)
{
if
(
x_vars
.
hasOwnProperty
(
x_key
))
{
if
(
typeof
x_vars
[
x_key
]
===
'
function
'
)
{
multipart_params_obj
[
'
x:
'
+
x_key
]
=
x_vars
[
x_key
](
up
,
file
);
}
else
if
(
typeof
x_vars
[
x_key
]
!==
'
object
'
)
{
multipart_params_obj
[
'
x:
'
+
x_key
]
=
x_vars
[
x_key
];
}
}
}
}
up
.
setOption
({
url
:
qiniuUploadUrl
,
multipart
:
true
,
chunk_size
:
is_android_weixin_or_qq
()
?
op
.
max_file_size
:
undefined
,
multipart_params
:
multipart_params_obj
,
});
};
// detect is weixin or qq inner browser
const
is_android_weixin_or_qq
=
function
()
{
const
ua
=
navigator
.
userAgent
.
toLowerCase
();
if
((
ua
.
match
(
/MicroMessenger/i
)
||
mOxie
.
Env
.
browser
===
'
QQBrowser
'
||
ua
.
match
(
/V1_AND_SQ/i
))
&&
mOxie
.
Env
.
OS
.
toLowerCase
()
===
'
android
'
)
{
return
true
;
}
else
{
return
false
;
}
};
let
chunk_size
=
up
.
getOption
&&
up
.
getOption
(
'
chunk_size
'
);
chunk_size
=
chunk_size
||
(
up
.
settings
&&
up
.
settings
.
chunk_size
);
logger
.
debug
(
'
uploader.runtime:
'
,
uploader
.
runtime
);
logger
.
debug
(
'
chunk_size:
'
,
chunk_size
);
// TODO: flash support chunk upload
if
((
uploader
.
runtime
===
'
html5
'
||
uploader
.
runtime
===
'
flash
'
)
&&
chunk_size
)
{
if
(
file
.
size
<
chunk_size
||
is_android_weixin_or_qq
())
{
logger
.
debug
(
'
directUpload because file.size < chunk_size || is_android_weixin_or_qq()
'
);
// direct upload if file size is less then the chunk size
directUpload
(
up
,
file
,
that
.
key_handler
);
}
else
{
// TODO: need a polifill to make it work in IE 9-
// ISSUE: if file.name is existed in localStorage
// but not the same file maybe cause error
let
localFileInfo
=
localStorage
.
getItem
(
file
.
name
);
let
blockSize
=
chunk_size
;
if
(
localFileInfo
)
{
// TODO: although only the html5 runtime will enter this statement
// but need uniform way to make convertion between string and json
localFileInfo
=
that
.
parseJSON
(
localFileInfo
);
const
now
=
new
Date
().
getTime
();
const
before
=
localFileInfo
.
time
||
0
;
const
aDay
=
24
*
60
*
60
*
1000
;
// milliseconds of one day
// if the last upload time is within one day
// will upload continuously follow the last breakpoint
// else
// will reupload entire file
if
(
now
-
before
<
aDay
)
{
if
(
localFileInfo
.
percent
!==
100
)
{
if
(
file
.
size
===
localFileInfo
.
total
)
{
// TODO: if file.name and file.size is the same
// but not the same file will cause error
file
.
percent
=
localFileInfo
.
percent
;
file
.
loaded
=
localFileInfo
.
offset
;
ctx
=
localFileInfo
.
ctx
;
// set speed info
speedCalInfo
.
isResumeUpload
=
true
;
speedCalInfo
.
resumeFilesize
=
localFileInfo
.
offset
;
// set block size
if
(
localFileInfo
.
offset
+
blockSize
>
file
.
size
)
{
blockSize
=
file
.
size
-
localFileInfo
.
offset
;
}
}
else
{
// remove file info when file.size is conflict with file info
localStorage
.
removeItem
(
file
.
name
);
}
}
else
{
// remove file info when upload percent is 100%
// avoid 499 bug
localStorage
.
removeItem
(
file
.
name
);
}
}
else
{
// remove file info when last upload time is over one day
localStorage
.
removeItem
(
file
.
name
);
}
}
speedCalInfo
.
startTime
=
new
Date
().
getTime
();
const
multipart_params_obj
=
{};
const
ie
=
that
.
detectIEVersion
();
// case IE 9-
// add accept in multipart params
if
(
ie
&&
ie
<=
9
)
{
multipart_params_obj
.
accept
=
'
text/plain; charset=utf-8
'
;
logger
.
debug
(
'
add accept text/plain in multipart params
'
);
}
// TODO: to support bput
// http://developer.qiniu.com/docs/v6/api/reference/up/bput.html
up
.
setOption
({
url
:
qiniuUploadUrl
+
'
/mkblk/
'
+
blockSize
,
multipart
:
false
,
chunk_size
,
required_features
:
'
chunks
'
,
headers
:
{
Authorization
:
'
UpToken
'
+
getUptoken
(
file
),
},
multipart_params
:
multipart_params_obj
,
});
}
}
else
{
logger
.
debug
(
'
directUpload because uploader.runtime !==
\'
html5
\'
|| uploader.runtime !==
\'
flash
\'
|| !chunk_size
'
);
// direct upload if runtime is not html5
directUpload
(
up
,
file
,
that
.
key_handler
);
}
});
logger
.
debug
(
'
bind BeforeUpload event
'
);
// bind 'UploadProgress' event
// calculate upload speed
uploader
.
bind
(
'
UploadProgress
'
,
function
(
up
,
file
)
{
logger
.
trace
(
'
UploadProgress event activated
'
);
speedCalInfo
.
currentTime
=
new
Date
().
getTime
();
const
timeUsed
=
speedCalInfo
.
currentTime
-
speedCalInfo
.
startTime
;
// ms
let
fileUploaded
=
file
.
loaded
||
0
;
if
(
speedCalInfo
.
isResumeUpload
)
{
fileUploaded
=
file
.
loaded
-
speedCalInfo
.
resumeFilesize
;
}
file
.
speed
=
((
fileUploaded
/
timeUsed
)
*
1000
).
toFixed
(
0
)
||
0
;
// unit: byte/s
});
logger
.
debug
(
'
bind UploadProgress event
'
);
// bind 'ChunkUploaded' event
// store the chunk upload info and set next chunk upload url
uploader
.
bind
(
'
ChunkUploaded
'
,
function
(
up
,
file
,
info
)
{
logger
.
debug
(
'
ChunkUploaded event activated
'
);
logger
.
debug
(
'
file:
'
,
file
);
logger
.
debug
(
'
info:
'
,
info
);
const
res
=
that
.
parseJSON
(
info
.
response
);
logger
.
debug
(
'
res:
'
,
res
);
// ctx should look like '[chunk01_ctx],[chunk02_ctx],[chunk03_ctx],...'
ctx
=
ctx
?
ctx
+
'
,
'
+
res
.
ctx
:
res
.
ctx
;
const
leftSize
=
info
.
total
-
info
.
offset
;
let
chunk_size
=
up
.
getOption
&&
up
.
getOption
(
'
chunk_size
'
);
chunk_size
=
chunk_size
||
(
up
.
settings
&&
up
.
settings
.
chunk_size
);
if
(
leftSize
<
chunk_size
)
{
up
.
setOption
({
url
:
qiniuUploadUrl
+
'
/mkblk/
'
+
leftSize
,
});
logger
.
debug
(
'
up.setOption url:
'
,
qiniuUploadUrl
+
'
/mkblk/
'
+
leftSize
);
}
up
.
setOption
({
headers
:
{
Authorization
:
'
UpToken
'
+
getUptoken
(
file
),
},
});
localStorage
.
setItem
(
file
.
name
,
that
.
stringifyJSON
({
ctx
,
percent
:
file
.
percent
,
total
:
info
.
total
,
offset
:
info
.
offset
,
time
:
new
Date
().
getTime
(),
})
);
});
logger
.
debug
(
'
bind ChunkUploaded event
'
);
let
retries
=
qiniuUploadUrls
.
length
;
// if error is unkown switch upload url and retry
const
unknow_error_retry
=
function
(
file
)
{
if
(
retries
--
>
0
)
{
setTimeout
(
function
()
{
that
.
resetUploadUrl
();
file
.
status
=
plupload
.
QUEUED
;
uploader
.
stop
();
uploader
.
start
();
},
0
);
return
true
;
}
else
{
retries
=
qiniuUploadUrls
.
length
;
return
false
;
}
};
// bind 'Error' event
// check the err.code and return the errTip
uploader
.
bind
(
'
Error
'
,
(
function
(
_Error_Handler
)
{
return
function
(
up
,
err
)
{
logger
.
error
(
'
Error event activated
'
);
logger
.
error
(
'
err:
'
,
err
);
let
errTip
=
''
;
const
file
=
err
.
file
;
if
(
file
)
{
switch
(
err
.
code
)
{
case
plupload
.
FAILED
:
errTip
=
'
上传失败。请稍后再试。
'
;
break
;
case
plupload
.
FILE_SIZE_ERROR
:
let
max_file_size
=
up
.
getOption
&&
up
.
getOption
(
'
max_file_size
'
);
max_file_size
=
max_file_size
||
(
up
.
settings
&&
up
.
settings
.
max_file_size
);
errTip
=
'
浏览器最大可上传
'
+
max_file_size
+
'
。更大文件请使用命令行工具。
'
;
break
;
case
plupload
.
FILE_EXTENSION_ERROR
:
errTip
=
'
文件验证失败。请稍后重试。
'
;
break
;
case
plupload
.
HTTP_ERROR
:
if
(
err
.
response
===
''
)
{
// Fix parseJSON error ,when http error is like net::ERR_ADDRESS_UNREACHABLE
errTip
=
err
.
message
||
'
未知网络错误。
'
;
if
(
!
unknow_error_retry
(
file
))
{
return
;
}
break
;
}
let
errorObj
=
that
.
parseJSON
(
err
.
response
);
let
errorText
=
errorObj
.
error
;
switch
(
err
.
status
)
{
case
400
:
errTip
=
'
请求报文格式错误。
'
;
break
;
case
401
:
errTip
=
'
客户端认证授权失败。请重试或提交反馈。
'
;
break
;
case
405
:
errTip
=
'
客户端请求错误。请重试或提交反馈。
'
;
break
;
case
579
:
errTip
=
'
资源上传成功,但回调失败。
'
;
break
;
case
599
:
errTip
=
'
网络连接异常。请重试或提交反馈。
'
;
if
(
!
unknow_error_retry
(
file
))
{
return
;
}
break
;
case
614
:
errTip
=
'
文件已存在。
'
;
try
{
errorObj
=
that
.
parseJSON
(
errorObj
.
error
);
errorText
=
errorObj
.
error
||
'
file exists
'
;
}
catch
(
e
)
{
errorText
=
errorObj
.
error
||
'
file exists
'
;
}
break
;
case
631
:
errTip
=
'
指定空间不存在。
'
;
break
;
case
701
:
errTip
=
'
上传数据块校验出错。请重试或提交反馈。
'
;
break
;
default
:
errTip
=
'
未知错误。
'
;
if
(
!
unknow_error_retry
(
file
))
{
return
;
}
break
;
}
errTip
=
errTip
+
'
(
'
+
err
.
status
+
'
:
'
+
errorText
+
'
)
'
;
break
;
case
plupload
.
SECURITY_ERROR
:
errTip
=
'
安全配置错误。请联系网站管理员。
'
;
break
;
case
plupload
.
GENERIC_ERROR
:
errTip
=
'
上传失败。请稍后再试。
'
;
break
;
case
plupload
.
IO_ERROR
:
errTip
=
'
上传失败。请稍后再试。
'
;
break
;
case
plupload
.
INIT_ERROR
:
errTip
=
'
网站配置错误。请联系网站管理员。
'
;
uploader
.
destroy
();
break
;
default
:
errTip
=
err
.
message
+
err
.
details
;
if
(
!
unknow_error_retry
(
file
))
{
return
;
}
break
;
}
if
(
_Error_Handler
)
{
_Error_Handler
(
up
,
err
,
errTip
);
}
}
up
.
refresh
();
// Reposition Flash/Silverlight
};
})(
_Error_Handler
)
);
logger
.
debug
(
'
bind Error event
'
);
// bind 'FileUploaded' event
// intercept the complete of upload
// - get downtoken from downtoken_url if bucket is private
// - invoke mkfile api to compose chunks if upload strategy is chunk upload
uploader
.
bind
(
'
FileUploaded
'
,
(
function
(
_FileUploaded_Handler
)
{
return
function
(
up
,
file
,
info
)
{
logger
.
debug
(
'
FileUploaded event activated
'
);
logger
.
debug
(
'
file:
'
,
file
);
logger
.
debug
(
'
info:
'
,
info
);
const
last_step
=
function
(
up
,
file
,
info
)
{
if
(
op
.
downtoken_url
)
{
// if op.dowontoken_url is not empty
// need get downtoken before invoke the _FileUploaded_Handler
const
ajax_downtoken
=
that
.
createAjax
();
ajax_downtoken
.
open
(
'
POST
'
,
op
.
downtoken_url
,
true
);
ajax_downtoken
.
setRequestHeader
(
'
Content-type
'
,
'
application/x-www-form-urlencoded
'
);
ajax_downtoken
.
onreadystatechange
=
function
()
{
if
(
ajax_downtoken
.
readyState
===
4
)
{
if
(
ajax_downtoken
.
status
===
200
)
{
let
res_downtoken
;
try
{
res_downtoken
=
that
.
parseJSON
(
ajax_downtoken
.
responseText
);
}
catch
(
e
)
{
throw
new
Error
(
'
invalid json format
'
);
}
const
info_extended
=
{};
plupload
.
extend
(
info_extended
,
that
.
parseJSON
(
info
),
res_downtoken
);
if
(
_FileUploaded_Handler
)
{
_FileUploaded_Handler
(
up
,
file
,
that
.
stringifyJSON
(
info_extended
));
}
}
else
{
uploader
.
trigger
(
'
Error
'
,
{
status
:
ajax_downtoken
.
status
,
response
:
ajax_downtoken
.
responseText
,
file
,
code
:
plupload
.
HTTP_ERROR
,
});
}
}
};
ajax_downtoken
.
send
(
'
key=
'
+
that
.
parseJSON
(
info
).
key
+
'
&domain=
'
+
op
.
domain
);
}
else
if
(
_FileUploaded_Handler
)
{
_FileUploaded_Handler
(
up
,
file
,
info
);
}
};
const
res
=
that
.
parseJSON
(
info
.
response
);
ctx
=
ctx
||
res
.
ctx
;
// if ctx is not empty
// that means the upload strategy is chunk upload
// befroe the invoke the last_step
// we need request the mkfile to compose all uploaded chunks
// else
// invalke the last_step
logger
.
debug
(
'
ctx:
'
,
ctx
);
if
(
ctx
)
{
let
key
=
''
;
logger
.
debug
(
'
save_key:
'
,
op
.
save_key
);
if
(
!
op
.
save_key
)
{
key
=
getFileKey
(
up
,
file
,
that
.
key_handler
);
key
=
key
?
'
/key/
'
+
that
.
URLSafeBase64Encode
(
key
)
:
''
;
}
const
fname
=
'
/fname/
'
+
that
.
URLSafeBase64Encode
(
file
.
name
);
logger
.
debug
(
'
op.x_vars:
'
,
op
.
x_vars
);
const
x_vars
=
op
.
x_vars
;
let
x_val
=
''
;
let
x_vars_url
=
''
;
if
(
x_vars
!==
undefined
&&
typeof
x_vars
===
'
object
'
)
{
for
(
const
x_key
in
x_vars
)
{
if
(
x_vars
.
hasOwnProperty
(
x_key
))
{
if
(
typeof
x_vars
[
x_key
]
===
'
function
'
)
{
x_val
=
that
.
URLSafeBase64Encode
(
x_vars
[
x_key
](
up
,
file
));
}
else
if
(
typeof
x_vars
[
x_key
]
!==
'
object
'
)
{
x_val
=
that
.
URLSafeBase64Encode
(
x_vars
[
x_key
]);
}
x_vars_url
+=
'
/x:
'
+
x_key
+
'
/
'
+
x_val
;
}
}
}
const
url
=
qiniuUploadUrl
+
'
/mkfile/
'
+
file
.
size
+
key
+
fname
+
x_vars_url
;
const
ie
=
that
.
detectIEVersion
();
let
ajax
;
if
(
ie
&&
ie
<=
9
)
{
ajax
=
new
mOxie
.
XMLHttpRequest
();
mOxie
.
Env
.
swf_url
=
op
.
flash_swf_url
;
}
else
{
ajax
=
that
.
createAjax
();
}
ajax
.
open
(
'
POST
'
,
url
,
true
);
ajax
.
setRequestHeader
(
'
Content-Type
'
,
'
text/plain;charset=UTF-8
'
);
ajax
.
setRequestHeader
(
'
Authorization
'
,
'
UpToken
'
+
that
.
token
);
const
onreadystatechange
=
function
()
{
logger
.
debug
(
'
ajax.readyState:
'
,
ajax
.
readyState
);
if
(
ajax
.
readyState
===
4
)
{
localStorage
.
removeItem
(
file
.
name
);
let
info
;
if
(
ajax
.
status
===
200
)
{
info
=
ajax
.
responseText
;
logger
.
debug
(
'
mkfile is success:
'
,
info
);
last_step
(
up
,
file
,
info
);
}
else
{
info
=
{
status
:
ajax
.
status
,
response
:
ajax
.
responseText
,
file
,
code
:
-
200
,
responseHeaders
:
ajax
.
getAllResponseHeaders
(),
};
logger
.
debug
(
'
mkfile is error:
'
,
info
);
uploader
.
trigger
(
'
Error
'
,
info
);
}
}
};
if
(
ie
&&
ie
<=
9
)
{
ajax
.
bind
(
'
readystatechange
'
,
onreadystatechange
);
}
else
{
ajax
.
onreadystatechange
=
onreadystatechange
;
}
ajax
.
send
(
ctx
);
logger
.
debug
(
'
mkfile:
'
,
url
);
}
else
{
last_step
(
up
,
file
,
info
.
response
);
}
};
})(
_FileUploaded_Handler
)
);
logger
.
debug
(
'
bind FileUploaded event
'
);
// init uploader
uploader
.
init
();
logger
.
debug
(
'
invoke uploader.init()
'
);
logger
.
debug
(
'
init uploader end
'
);
return
uploader
;
};
/**
* get url by key
* @param {String} key of file
* @return {String} url of file
*/
this
.
getUrl
=
function
(
key
)
{
if
(
!
key
)
{
return
false
;
}
key
=
encodeURI
(
key
);
let
domain
=
this
.
domain
;
if
(
domain
.
slice
(
domain
.
length
-
1
)
!==
'
/
'
)
{
domain
=
domain
+
'
/
'
;
}
return
domain
+
key
;
};
/**
* invoke the imageView2 api of Qiniu
* @param {Object} api params
* @param {String} key of file
* @return {String} url of processed image
*/
this
.
imageView2
=
function
(
op
,
key
)
{
if
(
!
/^
\d
$/
.
test
(
op
.
mode
))
{
return
false
;
}
const
mode
=
op
.
mode
;
const
w
=
op
.
w
||
''
;
const
h
=
op
.
h
||
''
;
const
q
=
op
.
q
||
''
;
const
format
=
op
.
format
||
''
;
if
(
!
w
&&
!
h
)
{
return
false
;
}
let
imageUrl
=
'
imageView2/
'
+
mode
;
imageUrl
+=
w
?
'
/w/
'
+
w
:
''
;
imageUrl
+=
h
?
'
/h/
'
+
h
:
''
;
imageUrl
+=
q
?
'
/q/
'
+
q
:
''
;
imageUrl
+=
format
?
'
/format/
'
+
format
:
''
;
if
(
key
)
{
imageUrl
=
this
.
getUrl
(
key
)
+
'
?
'
+
imageUrl
;
}
return
imageUrl
;
};
/**
* invoke the imageMogr2 api of Qiniu
* @param {Object} api params
* @param {String} key of file
* @return {String} url of processed image
*/
this
.
imageMogr2
=
function
(
op
,
key
)
{
const
auto_orient
=
op
[
'
auto-orient
'
]
||
''
;
const
thumbnail
=
op
.
thumbnail
||
''
;
const
strip
=
op
.
strip
||
''
;
const
gravity
=
op
.
gravity
||
''
;
const
crop
=
op
.
crop
||
''
;
const
quality
=
op
.
quality
||
''
;
const
rotate
=
op
.
rotate
||
''
;
const
format
=
op
.
format
||
''
;
const
blur
=
op
.
blur
||
''
;
// Todo check option
let
imageUrl
=
'
imageMogr2
'
;
imageUrl
+=
auto_orient
?
'
/auto-orient
'
:
''
;
imageUrl
+=
thumbnail
?
'
/thumbnail/
'
+
thumbnail
:
''
;
imageUrl
+=
strip
?
'
/strip
'
:
''
;
imageUrl
+=
gravity
?
'
/gravity/
'
+
gravity
:
''
;
imageUrl
+=
quality
?
'
/quality/
'
+
quality
:
''
;
imageUrl
+=
crop
?
'
/crop/
'
+
crop
:
''
;
imageUrl
+=
rotate
?
'
/rotate/
'
+
rotate
:
''
;
imageUrl
+=
format
?
'
/format/
'
+
format
:
''
;
imageUrl
+=
blur
?
'
/blur/
'
+
blur
:
''
;
if
(
key
)
{
imageUrl
=
this
.
getUrl
(
key
)
+
'
?
'
+
imageUrl
;
}
return
imageUrl
;
};
/**
* invoke the watermark api of Qiniu
* @param {Object} api params
* @param {String} key of file
* @return {String} url of processed image
*/
this
.
watermark
=
function
(
op
,
key
)
{
const
mode
=
op
.
mode
;
if
(
!
mode
)
{
return
false
;
}
let
imageUrl
=
'
watermark/
'
+
mode
;
if
(
mode
===
1
)
{
const
image
=
op
.
image
||
''
;
if
(
!
image
)
{
return
false
;
}
imageUrl
+=
image
?
'
/image/
'
+
this
.
URLSafeBase64Encode
(
image
)
:
''
;
}
else
if
(
mode
===
2
)
{
const
text
=
op
.
text
?
op
.
text
:
''
;
const
font
=
op
.
font
?
op
.
font
:
''
;
const
fontsize
=
op
.
fontsize
?
op
.
fontsize
:
''
;
const
fill
=
op
.
fill
?
op
.
fill
:
''
;
if
(
!
text
)
{
return
false
;
}
imageUrl
+=
text
?
'
/text/
'
+
this
.
URLSafeBase64Encode
(
text
)
:
''
;
imageUrl
+=
font
?
'
/font/
'
+
this
.
URLSafeBase64Encode
(
font
)
:
''
;
imageUrl
+=
fontsize
?
'
/fontsize/
'
+
fontsize
:
''
;
imageUrl
+=
fill
?
'
/fill/
'
+
this
.
URLSafeBase64Encode
(
fill
)
:
''
;
}
else
{
// Todo mode3
return
false
;
}
const
dissolve
=
op
.
dissolve
||
''
;
const
gravity
=
op
.
gravity
||
''
;
const
dx
=
op
.
dx
||
''
;
const
dy
=
op
.
dy
||
''
;
imageUrl
+=
dissolve
?
'
/dissolve/
'
+
dissolve
:
''
;
imageUrl
+=
gravity
?
'
/gravity/
'
+
gravity
:
''
;
imageUrl
+=
dx
?
'
/dx/
'
+
dx
:
''
;
imageUrl
+=
dy
?
'
/dy/
'
+
dy
:
''
;
if
(
key
)
{
imageUrl
=
this
.
getUrl
(
key
)
+
'
?
'
+
imageUrl
;
}
return
imageUrl
;
};
/**
* invoke the imageInfo api of Qiniu
* @param {String} key of file
* @return {Object} image info
*/
this
.
imageInfo
=
function
(
key
)
{
if
(
!
key
)
{
return
false
;
}
const
url
=
this
.
getUrl
(
key
)
+
'
?imageInfo
'
;
const
xhr
=
this
.
createAjax
();
let
info
;
const
that
=
this
;
xhr
.
open
(
'
GET
'
,
url
,
false
);
xhr
.
onreadystatechange
=
function
()
{
if
(
xhr
.
readyState
===
4
&&
xhr
.
status
===
200
)
{
info
=
that
.
parseJSON
(
xhr
.
responseText
);
}
};
xhr
.
send
();
return
info
;
};
/**
* invoke the exif api of Qiniu
* @param {String} key of file
* @return {Object} image exif
*/
this
.
exif
=
function
(
key
)
{
if
(
!
key
)
{
return
false
;
}
const
url
=
this
.
getUrl
(
key
)
+
'
?exif
'
;
const
xhr
=
this
.
createAjax
();
let
info
;
const
that
=
this
;
xhr
.
open
(
'
GET
'
,
url
,
false
);
xhr
.
onreadystatechange
=
function
()
{
if
(
xhr
.
readyState
===
4
&&
xhr
.
status
===
200
)
{
info
=
that
.
parseJSON
(
xhr
.
responseText
);
}
};
xhr
.
send
();
return
info
;
};
/**
* invoke the exif or imageInfo api of Qiniu
* according with type param
* @param {String} ['exif'|'imageInfo']type of info
* @param {String} key of file
* @return {Object} image exif or info
*/
this
.
get
=
function
(
type
,
key
)
{
if
(
!
key
||
!
type
)
{
return
false
;
}
if
(
type
===
'
exif
'
)
{
return
this
.
exif
(
key
);
}
else
if
(
type
===
'
imageInfo
'
)
{
return
this
.
imageInfo
(
key
);
}
return
false
;
};
/**
* invoke api of Qiniu like a pipeline
* @param {Array of Object} params of a series api call
* each object in array is options of api which name is set as 'fop' property
* each api's output will be next api's input
* @param {String} key of file
* @return {String|Boolean} url of processed image
*/
this
.
pipeline
=
function
(
arr
,
key
)
{
const
isArray
=
Object
.
prototype
.
toString
.
call
(
arr
)
===
'
[object Array]
'
;
let
option
;
let
errOp
;
let
imageUrl
=
''
;
if
(
isArray
)
{
for
(
let
i
=
0
,
len
=
arr
.
length
;
i
<
len
;
i
++
)
{
option
=
arr
[
i
];
if
(
!
option
.
fop
)
{
return
false
;
}
switch
(
option
.
fop
)
{
case
'
watermark
'
:
imageUrl
+=
this
.
watermark
(
option
)
+
'
|
'
;
break
;
case
'
imageView2
'
:
imageUrl
+=
this
.
imageView2
(
option
)
+
'
|
'
;
break
;
case
'
imageMogr2
'
:
imageUrl
+=
this
.
imageMogr2
(
option
)
+
'
|
'
;
break
;
default
:
errOp
=
true
;
break
;
}
if
(
errOp
)
{
return
false
;
}
}
if
(
key
)
{
imageUrl
=
this
.
getUrl
(
key
)
+
'
?
'
+
imageUrl
;
const
length
=
imageUrl
.
length
;
if
(
imageUrl
.
slice
(
length
-
1
)
===
'
|
'
)
{
imageUrl
=
imageUrl
.
slice
(
0
,
length
-
1
);
}
}
return
imageUrl
;
}
return
false
;
};
}
const
Qiniu
=
new
QiniuJsSDK
();
global
.
Qiniu
=
Qiniu
;
global
.
QiniuJsSDK
=
QiniuJsSDK
;
})(
window
);
app/web/service/sa.service.ts
0 → 100644
View file @
c7027cf3
import
Vue
from
'
vue
'
;
import
sa
from
'
sa-sdk-javascript
'
;
import
config
from
'
@/config
'
;
import
Storage
from
'
@/service/localStorage.service
'
;
export
function
initSa
(
router
)
{
console
.
log
(
'
initSa
'
,
EASY_ENV_IS_BROWSER
,
config
);
sa
.
init
({
server_url
:
config
.
shenceUrl
,
heatmap
:
{
// 是否开启点击图,默认 default 表示开启,自动采集 $WebClick 事件,可以设置 'not_collect' 表示关闭
clickmap
:
'
default
'
,
// 是否开启触达注意力图,默认 default 表示开启,自动采集 $WebStay 事件,可以设置 'not_collect' 表示关闭
scroll_notice_map
:
'
default
'
,
},
// 判断外层是否有 App 的 SDK ,如果有的话,会往 App 的 SDK 发数据。如果没有,就正常发送数据。
use_app_track
:
true
,
show_log
:
config
.
test
,
app_js_bridge
:
true
,
});
// 添加公共属性
sa
.
registerPage
({
platformType
:
'
H5
'
,
uuid
:
''
,
qg_device_id
:
''
,
channel_code
:
''
,
splitStream
:
''
,
});
router
.
afterEach
(()
=>
{
Vue
.
nextTick
(()
=>
{
sa
.
quick
(
'
autoTrackSinglePage
'
);
});
});
}
export
function
registeredEvents
(
eventName
,
eventData
)
{
sa
.
track
(
eventName
,
eventData
);
}
// 用户登录神策埋点
export
function
loginSa
(
uuid
=
Storage
.
get
(
'
uuid
'
))
{
if
(
!
uuid
)
{
return
;
}
Storage
.
set
(
'
uuid
'
,
uuid
);
sa
.
login
(
uuid
);
}
app/web/service/utils.service.ts
View file @
c7027cf3
// tslint:disable
export
const
chunk
=
function
(
array
,
size
)
{
export
const
chunk
=
function
(
array
,
size
)
{
const
result
=
[];
const
result
=
[];
let
[
start
,
end
]
=
[
null
,
null
];
let
[
start
,
end
]
=
[
null
,
null
];
...
@@ -118,3 +119,19 @@ export const transformStyle = function(styleObj = {}) {
...
@@ -118,3 +119,19 @@ export const transformStyle = function(styleObj = {}) {
}
}
return
style
;
return
style
;
};
};
const
ua
=
!
EASY_ENV_IS_BROWSER
?
{
match
()
{}
}
:
window
.
navigator
.
userAgent
.
toLowerCase
();
// 判断微信环境
export
const
isWechat
=
ua
.
match
(
/MicroMessenger/i
)
==
"
micromessenger
"
;
// 判断羊小咩(信用钱包)环境
export
const
isApp
=
ua
.
match
(
/xyqb/i
)
==
"
xyqb
"
;
// 判断真享生活
export
const
isVcc
=
ua
.
match
(
/VCC/i
)
==
"
vcc
"
;
// 判断IOS环境
export
const
isIOS
=
/iphone|ipad|ipod/
.
test
(
ua
);
// 判读Android环境
export
const
isAndroid
=
/android/
.
test
(
ua
);
package.json
View file @
c7027cf3
...
@@ -19,8 +19,8 @@
...
@@ -19,8 +19,8 @@
},
},
"dependencies"
:
{
"dependencies"
:
{
"
@better-scroll/core
"
:
"
^2.0.5
"
,
"
@better-scroll/core
"
:
"
^2.0.5
"
,
"
@qg/cherry-ui
"
:
"
^2.18.
66
"
,
"
@qg/cherry-ui
"
:
"
^2.18.
75
"
,
"
@qg/citrus-ui
"
:
"
0.0.1
-alpha.2
"
,
"
@qg/citrus-ui
"
:
"
0.0.1
4
"
,
"
axios
"
:
"
^0.21.1
"
,
"
axios
"
:
"
^0.21.1
"
,
"
babel-plugin-transform-vue-jsx
"
:
"
^4.0.1
"
,
"
babel-plugin-transform-vue-jsx
"
:
"
^4.0.1
"
,
"
egg
"
:
"
^2.3.0
"
,
"
egg
"
:
"
^2.3.0
"
,
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
"
egg-webpack
"
:
"
^4.4.7
"
,
"
egg-webpack
"
:
"
^4.4.7
"
,
"
egg-webpack-vue
"
:
"
^2.0.0
"
,
"
egg-webpack-vue
"
:
"
^2.0.0
"
,
"
js-cookie
"
:
"
^2.2.1
"
,
"
js-cookie
"
:
"
^2.2.1
"
,
"
npm
"
:
"
^6.14.10
"
,
"
qs
"
:
"
^6.9.4
"
,
"
qs
"
:
"
^6.9.4
"
,
"
raven-js
"
:
"
^3.27.2
"
,
"
raven-js
"
:
"
^3.27.2
"
,
"
sa-sdk-javascript
"
:
"
^1.15.27
"
,
"
sa-sdk-javascript
"
:
"
^1.15.27
"
,
...
@@ -42,8 +43,7 @@
...
@@ -42,8 +43,7 @@
"
vue-router
"
:
"
^3.0.1
"
,
"
vue-router
"
:
"
^3.0.1
"
,
"
vuex
"
:
"
^3.0.1
"
,
"
vuex
"
:
"
^3.0.1
"
,
"
vuex-class
"
:
"
^0.3.1
"
,
"
vuex-class
"
:
"
^0.3.1
"
,
"
vuex-router-sync
"
:
"
^5.0.0
"
,
"
vuex-router-sync
"
:
"
^5.0.0
"
"
npm
"
:
"
^6.14.10
"
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"
typescript
"
:
"
^3.9.2
"
,
"
typescript
"
:
"
^3.9.2
"
,
...
...
webpack.config.js
View file @
c7027cf3
...
@@ -181,6 +181,9 @@ module.exports = {
...
@@ -181,6 +181,9 @@ module.exports = {
}
}
}
}
},
},
externals
:
{
'
sa-sdk-javascript
'
:
'
sensorsDataAnalytic201505
'
},
// mode: 'development',
// mode: 'development',
devtool
:
'
source-map
'
,
devtool
:
'
source-map
'
,
customize
(
webpackConfig
){
customize
(
webpackConfig
){
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment