Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
quantum-blocks
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
Commits
aaa4b0a3
Commit
aaa4b0a3
authored
Feb 25, 2021
by
郝聪敏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feature: 添加优惠券
parent
e79407ce
Changes
36
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
730 additions
and
271 deletions
+730
-271
editor.ts
app/controller/editor.ts
+1
-1
operation.api.ts
app/web/api/operation.api.ts
+146
-0
dev.config.ts
app/web/config/dev.config.ts
+2
-0
app.ts
app/web/framework/app.ts
+1
-0
index.vue
app/web/lib/Advertisement/index.vue
+1
-1
index.vue
app/web/lib/Coupon/index.vue
+38
-26
index.vue
app/web/lib/Goods/index.vue
+49
-20
index.vue
app/web/lib/GoodsTabs/index.vue
+9
-4
index.vue
app/web/lib/GuideCube/index.vue
+78
-39
index.vue
app/web/lib/Marquee/index.vue
+40
-11
config.ts
app/web/lib/config.ts
+15
-4
index.ts
app/web/page/activity/component/FreedomContainer/index.ts
+2
-1
index.vue
app/web/page/activity/component/FreedomContainer/index.vue
+2
-2
index.ts
app/web/page/activity/view/activity/index.ts
+37
-1
index.vue
app/web/page/activity/view/activity/index.vue
+17
-17
index.vue
app/web/page/activity/view/home/index.vue
+1
-3
index.ts
app/web/page/editor/component/BasicPageForm/index.ts
+11
-7
index.vue
...r/component/DynamicForm/component/ColorSelector/index.vue
+2
-2
index.ts
...component/DynamicForm/component/CouponTableModal/index.ts
+7
-3
index.vue
...omponent/DynamicForm/component/CouponTableModal/index.vue
+1
-1
index.ts
.../component/DynamicForm/component/GoodsTableModal/index.ts
+4
-2
index.ts
...ditor/component/DynamicForm/component/TableModal/index.ts
+1
-1
index.vue
...e/editor/component/DynamicForm/component/Upload/index.vue
+16
-6
index.ts
app/web/page/editor/component/DynamicForm/index.ts
+123
-3
index.vue
app/web/page/editor/component/DynamicForm/index.vue
+51
-86
index.ts
app/web/page/editor/component/DynamicPageForm/index.ts
+28
-13
index.vue
app/web/page/editor/component/DynamicPageForm/index.vue
+12
-4
index.ts
app/web/page/editor/component/FreedomContainer/index.ts
+2
-2
index.ts
app/web/page/editor/view/dashboard/index.ts
+7
-2
index.vue
app/web/page/editor/view/dashboard/index.vue
+2
-2
transformStyle.mixin.ts
app/web/page/mixins/transformStyle.mixin.ts
+6
-4
index.ts
app/web/page/store/modules/editor/index.ts
+4
-0
state.ts
app/web/page/store/modules/editor/state.ts
+4
-0
type.ts
app/web/page/store/modules/editor/type.ts
+2
-1
http.service.ts
app/web/service/http.service.ts
+1
-1
qg.service.ts
app/web/service/qg.service.ts
+7
-1
No files found.
app/controller/editor.ts
View file @
aaa4b0a3
...
...
@@ -37,7 +37,7 @@ export default class EditorController extends Controller {
pageDescribe
:
pageDescribe
&&
{
like
:
`%
${
pageDescribe
}
%`
},
isPublish
,
enable
:
1
},
v
=>
!
trim
(
v
)
);
},
v
=>
!
v
);
if
(
type
===
'
list
'
)
{
where
=
{
...
where
,
isPublish
:
1
};
}
else
if
(
type
===
'
my
'
)
{
...
...
app/web/api/operation.api.ts
View file @
aaa4b0a3
...
...
@@ -44,4 +44,150 @@ export default {
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/config/dev.config.ts
View file @
aaa4b0a3
...
...
@@ -2,8 +2,10 @@ const protocol = EASY_ENV_IS_BROWSER ? window.location.protocol : 'http';
export
default
{
apiHost
:
`http://localhost:7001/`
,
// apiHost: `http://192.168.28.199:7001/`,
qiniuHost
:
`https://appsync.lkbang.net/`
,
shenceUrl
:
`
${
protocol
}
//bn.xyqb.com/sa?project=default`
,
opapiHost
:
`https://opapi-vcc2.liangkebang.net`
,
qiniuUpHost
:
`
${
protocol
}
//up-z0.qiniup.com`
,
kdspHost
:
'
https://kdsp-api-vcc2.liangkebang.net
'
,
};
app/web/framework/app.ts
View file @
aaa4b0a3
...
...
@@ -62,6 +62,7 @@ export default class App {
server
()
{
return
context
=>
{
// console.log('server', context.state);
const
vm
=
this
.
create
(
context
.
state
);
const
{
store
,
router
}
=
vm
;
router
.
push
(
context
.
state
.
url
);
...
...
app/web/lib/Advertisement/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"ad"
:class=
"['ad',
{ 'ad_one': column === 1, 'ad_two': column === 2, 'ad_three': column === 3 }]" :id="id
">
<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>
...
...
app/web/lib/Coupon/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"
goods
"
v-if=
"column === 1"
>
<div
class=
"
goods-item_one"
:style=
"style"
:key=
"goods.id"
v-for=
"goods
in couponList"
>
<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>
{{
goods
.
couponAmt
||
0
}}
</span></p>
<p>
{{
`满${goods.couponAmt || 0
}
元减${goods.limitAmt || 0
}
元`
}}
<
/p
>
<p>
¥
<span>
{{
coupon
.
faceValue
||
'
-
'
}}
</span></p>
<p>
{{
coupon
.
limitDesc
}}
</p>
</div>
<div
class=
"Gi_one-middle"
>
<
p
>
{{
goods
.
name
}}
<
/p
>
<
p
>
2020.8
.
4
-
2020.9
.
4
<
/p
>
<p>
{{
coupon
.
name
}}
</p>
<p>
{{
`${coupon.startDate
}
- ${coupon.endDate
}
`
}}
<
/p
>
<
/div
>
<
cr
-
button
class
=
"
Gi_one-right
"
type
=
"
primary
"
>
点击领取
<
/cr-button
>
<
div
class
=
"
goods-item-mask
"
>
<
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
=
"
['
goods', {'goods_two': column === 2, 'goods
_multiple': column === 3
}
]
"
>
<
div
class
=
"
goods-item
"
:
style
=
"
style
"
:
key
=
"
goods.id
"
v
-
for
=
"
goods
in couponList
"
>
<
p
class
=
"
goods-item-title
"
>
{{
goods
.
name
}}
<
/p
>
<
p
class
=
"
goods-item-amount
"
>
¥
<
span
>
{{
goods
.
couponAmt
||
0
}}
<
/span></
p
>
<
p
class
=
"
goods-item-condition
"
>
{{
`满${goods.couponAmt || 0
}
元减${goods.limitAmt || 0
}
元`
}}
<
/p
>
<
cr
-
button
shape
=
"
circle
"
type
=
"
primary
"
>
点击领取
<
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
=
"
goods-item-mask
"
>
<
div
class
=
"
coupon-item-mask
"
v
-
if
=
"
!coupon.pickupAble && coupon.publishCountFinished
"
>
<
p
>
已抢空
<
/p
>
<
/div
>
<
/div
>
...
...
@@ -59,7 +59,7 @@
}
,
style
()
{
return
{
background
:
`url(${this.bgImage
}
) no-repeat 0 0 / cover`
,
background
:
this
.
bgImage
?
`url(${this.bgImage
}
) no-repeat 0 0 / cover`
:
''
,
backgroundColor
:
this
.
bgColor
}
}
...
...
@@ -67,15 +67,25 @@
watch
:
{
couponsList
:
{
handler
:
async
function
(
newVal
)
{
for
(
let
i
=
0
;
i
<
newVal
.
length
;
i
++
)
{
const
res
=
await
operationApi
.
couponList
({
couponId
:
newVal
[
i
]
}
);
const
couponInfoList
=
res
.
couponInfoList
;
if
(
couponInfoList
&&
couponInfoList
.
length
)
this
.
list
.
push
(
couponInfoList
[
0
]);
}
console
.
log
(
'
watch
'
,
this
.
list
);
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
>
...
...
@@ -83,9 +93,11 @@
::
-
webkit
-
scrollbar
{
display
:
none
;
/* Chrome Safari */
}
.
goods
{
.
coupon
{
width
:
100
%
;
padding
:
0
12
px
;
box
-
sizing
:
border
-
box
;
font
-
size
:
0
;
&-
item
{
position
:
relative
;
padding
:
4
px
8
px
;
...
...
@@ -143,7 +155,7 @@
overflow
-
x
:
auto
;
white
-
space
:
nowrap
;
padding
:
0
4
px
;
.
goods
-
item
{
.
coupon
-
item
{
width
:
114
px
;
margin
-
right
:
4
px
;
}
...
...
@@ -153,7 +165,7 @@
display
:
flex
;
flex
-
wrap
:
wrap
;
justify
-
content
:
space
-
between
;
.
goods
-
item
{
.
coupon
-
item
{
margin
-
bottom
:
8
px
;
width
:
170
px
;
&
_empty
{
...
...
app/web/lib/Goods/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"container"
>
<cr-image
width=
"100%"
height=
"2.4rem"
:src=
"specialRecommend"
@
click=
"go()"
v-if=
"showSpecial"
></cr-image>
<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"
v-for=
"goods in goodsList"
:key=
"goods.id"
>
<cr-image
width=
"100%"
height=
"3.15rem"
class=
"goods-item-img"
fit=
"contain"
src=
"https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
"
></cr-image>
<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"
>
商品名称商品名称商品名称商品商品名称商品商品名称商品名称商品名称商品商品名称商品商品名称商品名称商品名称商品商品名称商品
</p>
<p
class=
"goods-item-title"
>
{{
goods
.
skuName
}}
</p>
<div
class=
"goods-item-bottom"
>
<div
class=
"Gi-bottom-left"
>
<p>
¥
320.00
</p>
<p>
¥
999.00
</p>
<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">
<cr-image
width=
"100%"
height=
"3.15rem"
class=
"goods-item-img"
fit=
"contain"
src=
"https://img14.360buyimg.com/n0/jfs/t1/141986/32/5318/98164/5f3236baE713fd239/5f2746db41f3e9c0.jpg
"
></cr-image>
<p
class=
"goods-item-title"
>
商品名称商品名称商品名称商品商品名称商品
</p>
<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>
¥
320.00
</p>
<p>
¥
999.00
</p>
<p>
¥
{{
goods
.
salePrice
||
'
-
'
}}
</p>
<p>
¥
{{
goods
.
marketPrice
||
'
-
'
}}
</p>
</div>
<div
class=
"Gi-bottom-right"
>
<div
class=
"Gi-bottom-right"
@
click=
"addShopCart(goods)"
>
<cr-image
width=
"0.45rem"
height=
"0.45rem"
:src=
"shoppingCart"
></cr-image>
</div>
</div>
...
...
@@ -84,20 +85,33 @@
watch
:
{
goods
:
{
handler
:
async
function
(
newVal
)
{
if
(
newVal
.
type
===
'
goodsGroup
'
&&
newVal
.
ids
.
length
)
{
const
{
records
}
=
await
operationApi
.
skuInfo
({
brandId
:
newVal
.
ids
[
0
]
});
if
(
records
&&
records
.
length
)
this
.
list
=
records
;
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
);
//
console.log('watch', this.list);
},
immediate
:
true
}
},
methods
:
{
go
()
{
if
(
this
.
specialLink
)
{
go
(
type
,
params
)
{
if
(
t
ype
===
'
special
'
&&
t
his
.
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
(
'
添加成功
'
);
}
}
}
...
...
@@ -117,7 +131,8 @@
margin-bottom: 4px;
overflow: hidden;
&-title {
font-size: 13px;
height: 36px;
font-size: 12px;
line-height: 18px;
display: -webkit-box;
overflow: hidden;
...
...
@@ -130,7 +145,14 @@
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;
...
...
@@ -176,7 +198,14 @@
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 {
...
...
app/web/lib/GoodsTabs/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"tabs"
>
<cr-tabs
@
change=
"tabsChange"
animated
:underline-
color=
"underlineColor"
:title-active-color=
"activeColor"
:title-inactive-color=
"inactiveColor"
>
<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>
...
...
@@ -52,20 +52,25 @@
})
return
rs
;
});
console
.
log
(
'
tabs
'
,
this
.
childItem
.
child
,
list
);
//
console.log('tabs', this.childItem.child, list);
return
list
;
}
},
mounted
()
{
setTimeout
(()
=>
{
this
.
$refs
.
GoodsTabs
.
resize
();
})
},
methods
:
{
tabsChange
(
name
)
{
console
.
log
(
'
change
'
,
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
'
)
{
if
(
key
===
'
backgroundImage
'
&&
style
.
backgroundImage
)
{
style
.
background
=
`url(
${
style
.
backgroundImage
}
) no-repeat 0 0 / cover`
;
}
}
...
...
app/web/lib/GuideCube/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"guide-cube"
>
<swiper
v-if=
"showSwiper"
class=
"guide-cube-swiper"
ref=
"mySwiper"
:options=
"swiperOptions"
>
<swiper-slide
:style=
"style"
:class=
"
{'swiper-slide_two': slidesPerColumn === 2, 'swiper-slide_one': slidesPerColumn === 1 }" :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>
</swiper-slide>
</swiper>
<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
{
swiper
,
swiperSlide
}
from
'
vue-awesome-swiper
'
;
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
'
],
components
:
{
swiper
,
swiperSlide
,
},
props
:
{
list
:
{
type
:
Array
,
...
...
@@ -27,13 +30,17 @@
default
:
1
},
loop
:
Boolean
,
autoplay
:
Boolean
autoplay
:
Boolean
,
animation
:
Boolean
},
data
()
{
const
vm
=
this
;
let
isEven
=
true
;
let
lastEvenProgress
=
0
;
let
lastProgress
=
0
;
return
{
showSwiper
:
true
,
style
:
{},
//
style: {},
swiperOptions
:
{
loop
:
this
.
loop
,
slidesPerView
:
4
,
...
...
@@ -43,29 +50,60 @@
observeParents
:
true
,
watchSlidesProgress
:
true
,
autoplay
:
this
.
autoplay
,
on
:
{
progress
:
function
()
{
// console.log('memorys', vm.memorys);
const
slidesLength
=
this
.
slides
.
length
;
for
(
let
i
=
0
;
i
<
this
.
slides
.
length
;
i
++
)
{
const
slide
=
this
.
slides
.
eq
(
i
);
let
scale
=
Math
.
abs
(
this
.
slides
[
i
].
progress
%
1
).
toFixed
(
10
)
*
0.2
;
// 记录初始状态,用来复位
if
(
i
===
0
)
this
.
slides
[
0
].
scale
=
scale
;
if
(
!
this
.
slides
[
0
].
scale
)
{
vm
.
memorys
[
i
]
=
vm
.
memorys
[
i
]
?
0
:
1
;
scale
=
0.2
;
}
// 差别对待不同索引
if
(
vm
.
memorys
[
i
])
{
scale
=
1
-
scale
;
}
else
{
scale
=
0.8
+
scale
;
}
slide
.
transform
(
`scale3d(
${
scale
}
,
${
scale
}
, 1)`
);
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)`
);
}
},
},
}
},
}
}
},
...
...
@@ -77,6 +115,11 @@
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
:
{
...
...
@@ -90,11 +133,6 @@
this
.
refreshSwiper
(
'
loop
'
,
newVal
);
},
},
mounted
()
{
this
.
style
=
{
transition
:
'
all .4s cubic-bezier(.4, 0, .2, 1)
'
}
},
methods
:
{
go
(
url
)
{
window
.
location
.
href
=
url
;
...
...
@@ -110,6 +148,7 @@
</
script
>
<
style
lang=
"less"
scoped
>
.guide-cube {
width: 100%;
padding: 12px;
&-swiper {
width: 100%;
...
...
app/web/lib/Marquee/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"marquee"
>
<swiper
class=
"marquee-swiper"
ref=
"mySwiper"
:options=
"swiperOptions"
>
<swiper-slide
:key=
"index"
v-for=
"(item, index) in list"
>
<span
:style=
"styles"
>
{{
item
.
text
}}
</span>
</swiper-slide>
</swiper>
<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
{
swiper
,
swiperSlide
}
from
'
vue-awesome-swiper
'
;
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
'
],
components
:
{
swiper
,
swiperSlide
,
},
props
:
{
list
:
{
type
:
Array
,
...
...
@@ -29,8 +34,9 @@
},
data
()
{
return
{
showSwiper
:
true
,
swiperOptions
:
{
//
loop: true,
loop
:
true
,
observer
:
true
,
observeParents
:
true
,
direction
:
'
vertical
'
,
...
...
@@ -49,6 +55,24 @@
}
}
},
watch
:
{
list
:
{
deep
:
true
,
handler
()
{
this
.
refreshSwiper
();
}
}
},
methods
:
{
go
(
link
)
{
window
.
location
.
href
=
link
;
},
refreshSwiper
()
{
console
.
log
(
'
refreshSwiper
'
);
this
.
showSwiper
=
false
;
this
.
$nextTick
(()
=>
this
.
showSwiper
=
true
);
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
...
...
@@ -63,6 +87,11 @@
display: flex;
justify-content: center;
align-items: center;
a {
display: flex;
justify-content: center;
align-items: center;
}
span {
font-size: 14px;
line-height: 20px;
...
...
app/web/lib/config.ts
View file @
aaa4b0a3
...
...
@@ -481,10 +481,10 @@ export const businessComponents = [
}
],
value
:
{
couponsList
:
[
153
,
152
,
151
,
150
,
149
],
couponsList
:
[],
couponsNumber
:
3
,
column
:
3
,
bgColor
:
'
#fff
'
,
bgColor
:
''
,
bgImage
:
''
,
},
commonStyle
:
{}
...
...
@@ -560,6 +560,11 @@ export const businessComponents = [
name
:
'
自动播放
'
,
type
:
'
checkbox
'
},
{
key
:
'
animation
'
,
name
:
'
切换动画
'
,
type
:
'
checkbox
'
},
{
key
:
'
list
'
,
name
:
'
添加导购
'
,
...
...
@@ -618,11 +623,12 @@ export const businessComponents = [
}],
slidesPerColumn
:
1
,
loop
:
false
,
autoplay
:
false
autoplay
:
false
,
animation
:
false
}
},
{
eleName
:
'
Marquee
'
,
eleName
:
'
Custom
Marquee
'
,
title
:
'
跑马灯
'
,
config
:
[
{
...
...
@@ -640,6 +646,11 @@ export const businessComponents = [
name
:
'
文案
'
,
type
:
'
text
'
},
{
key
:
'
link
'
,
name
:
'
链接
'
,
type
:
'
text
'
},
]
}
],
...
...
app/web/page/activity/component/FreedomContainer/index.ts
View file @
aaa4b0a3
...
...
@@ -2,9 +2,10 @@ import { cloneDeep } from 'lodash';
import
{
Component
,
Prop
,
Vue
,
Mixins
}
from
'
vue-property-decorator
'
;
import
{
Action
,
Mutation
,
State
,
Getter
}
from
'
vuex-class
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
CustomMarquee
from
'
@/lib/Marquee/index.vue
'
;
import
{
resizeDiv
}
from
'
@/service/utils.service
'
;
@
Component
({
name
:
'
FreedomContainer
'
})
@
Component
({
components
:
{
CustomMarquee
},
name
:
'
FreedomContainer
'
})
export
default
class
FreedomContainer
extends
Mixins
(
TransformStyleMixin
)
{
@
Getter
(
'
pageData
'
)
pageData
;
@
State
(
state
=>
state
.
editor
.
curChildIndex
)
curChildIndex
;
...
...
app/web/page/activity/component/FreedomContainer/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"freedom"
>
<div
class=
"freedom-body"
:style=
"
{background: `url(${backgroundImage}) no-repeat 0 0 / cover`}"
>
<component
:class=
"['freedom-body-item',
{ 'Fb-item_selected': curChildIndex === index }]" v-for="(item, index) in childItem.child" :style="transformStyle(item.commonStyle)" :is="item.name" :key="index" v-bind="item.props">
</component>
<div
class=
"freedom-body"
>
<component
:class=
"['freedom-body-item',
{ 'Fb-item_selected': curChildIndex === index }]" v-for="(item, index) in childItem.child" :style="transformStyle(item.commonStyle
, 'container'
)" :is="item.name" :key="index" v-bind="item.props">
</component>
</div>
</div>
</
template
>
...
...
app/web/page/activity/view/activity/index.ts
View file @
aaa4b0a3
...
...
@@ -9,9 +9,12 @@ 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
{
getStyle
}
from
'
@/service/utils.service
'
;
@
Component
({
components
:
{
FreedomContainer
,
GridLayout
,
GridItem
,
DownloadGuide
,
GoodsTabs
,
GuideCube
},
name
:
'
Activity
'
})
@
Component
({
components
:
{
FreedomContainer
,
GridLayout
,
GridItem
,
DownloadGuide
,
GoodsTabs
,
GuideCube
,
Advertisement
,
Coupon
},
name
:
'
Activity
'
})
export
default
class
Activity
extends
Mixins
(
TransformStyleMixin
)
{
@
Getter
(
'
pageData
'
)
pageData
;
@
State
(
state
=>
state
.
editor
.
pageInfo
.
pageName
)
pageName
;
...
...
@@ -20,6 +23,8 @@ export default class Activity extends Mixins(TransformStyleMixin) {
@
Provide
(
'
editor
'
);
isLayoutComReady
=
false
;
showBackTop
=
false
;
targetEle
:
HTMLElement
|
null
=
null
;
get
layout
()
{
return
this
.
pageData
&&
this
.
pageData
.
elements
.
map
(
v
=>
v
.
point
)
||
[];
...
...
@@ -42,9 +47,18 @@ export default class Activity extends Mixins(TransformStyleMixin) {
}
}
mounted
()
{
this
.
targetEle
=
document
.
querySelector
(
'
body
'
);
this
.
showBackTop
=
true
;
setTimeout
(()
=>
{
this
.
modfiTabsStyle
();
},
300
);
}
fetchApi
(
options
)
{
const
{
store
,
route
}
=
options
;
const
{
pageId
}
=
route
.
params
;
console
.
log
(
'
fetchApi
'
,
route
);
return
store
.
dispatch
(
'
getPageDate
'
,
{
pageId
});
}
...
...
@@ -53,4 +67,26 @@ export default class Activity extends Mixins(TransformStyleMixin) {
height
:
`
${
h
*
this
.
rowHeight
}
px`
,
}
:
{};
}
modfiTabsStyle
()
{
const
tabsEle
=
document
.
querySelector
(
'
.tabs
'
);
if
(
tabsEle
)
{
const
gridItemEle
=
tabsEle
?.
parentNode
;
if
(
gridItemEle
?.
classList
.
contains
(
'
vue-grid-item
'
))
{
// 处理transform
const
transform
=
getStyle
(
gridItemEle
,
'
transform
'
);
const
transformY
=
transform
.
split
(
'
(
'
)[
1
].
split
(
'
)
'
)[
0
].
split
(
'
,
'
)[
5
];
gridItemEle
.
style
.
transform
=
'
none
'
;
gridItemEle
.
style
.
top
=
`
${
transformY
}
px`
;
// 处理backgroundColor
const
backgroundColor
=
getStyle
(
tabsEle
,
'
backgroundColor
'
);
const
crTabs
=
tabsEle
.
childNodes
[
0
];
crTabs
.
style
.
backgroundColor
=
backgroundColor
;
const
stickyEle
=
crTabs
?.
childNodes
[
0
];
if
(
stickyEle
?.
classList
.
contains
(
'
cr-sticky
'
)
&&
stickyEle
?.
childNodes
)
{
stickyEle
.
childNodes
[
0
]?.
style
.
backgroundColor
=
backgroundColor
;
}
}
}
}
}
\ No newline at end of file
app/web/page/activity/view/activity/index.vue
View file @
aaa4b0a3
...
...
@@ -12,6 +12,7 @@
:is-mirrored=
"false"
:vertical-compact=
"true"
:use-css-transforms=
"true"
@
layout-ready=
"modfiTabsStyle"
>
<grid-item
:style=
"createStyle(item.point)"
v-for=
"(item, index) in pageData.elements"
:x=
"item.point.x"
...
...
@@ -20,13 +21,14 @@
:h=
"item.point.h"
:i=
"item.point.i"
:key=
"item.point.i"
>
<component
:style=
"transformStyle(item.commonStyle)"
class=
"Dcmc-panel-com"
:data-index=
"index"
:containerIndex=
"index"
:childItem=
"item"
:is=
"item.name"
:key=
"index"
v-bind=
"item.props"
></component>
<component
:style=
"transformStyle(item.commonStyle)"
:data-index=
"index"
:containerIndex=
"index"
:childItem=
"item"
:is=
"item.name"
:key=
"index"
v-bind=
"item.props"
></component>
</grid-item>
</grid-layout>
<cr-back-top
v-if=
"showBackTop && pageData.props.showBackTop"
/>
</div>
</
template
>
<
script
lang=
"ts"
src=
"./index.ts"
></
script
>
<
style
lang=
"less"
>
<
style
lang=
"less"
scoped
>
html,
body,
#app {
...
...
@@ -41,23 +43,21 @@
width: 100%;
height: 100%;
min-height: 100%;
overflow-y: scroll;
background-color: rgb(244, 244, 244);
box-shadow: 2px 0px 10px rgba(0, 0, 0, 0.2);
/deep/ .vue-grid-layout {
min-height: 667px;
// transform: translateY(-10px);
background-color: rgb(244, 244, 244);
box-shadow: 2px 0px 10px rgba(0, 0, 0, 0.2);
/deep/ .vue-grid-layout {
min-height: 667px;
// transform: translateY(-10px);
transition-property: none;
.vue-grid-item {
transition-property: none;
.vue-grid-item {
transition-property: none;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
&>*:first-child {
height: 100%;
}
display: flex;
justify-content: center;
align-items: center;
&>*:first-child {
height: 100%;
}
}
}
}
</
style
>
app/web/page/activity/view/home/index.vue
View file @
aaa4b0a3
<
template
>
<Layout>
<transition
name=
"fade"
mode=
"out-in"
>
<router-view></router-view>
</transition>
<router-view></router-view>
</Layout>
</
template
>
<
script
lang=
"ts"
src=
"./index.ts"
></
script
>
app/web/page/editor/component/BasicPageForm/index.ts
View file @
aaa4b0a3
...
...
@@ -47,12 +47,16 @@ export default class DynamicForm extends Vue {
}
async
createCoverImage
()
{
const
imgName
=
btoa
(
`coverImage-
${
uuidv4
().
substr
(
0
,
8
)}
`
);
const
gridEle
=
document
.
querySelector
(
'
.Dcm-container-panel
'
);
const
canvas
=
await
html2canvas
(
gridEle
as
HTMLElement
,
{
useCORS
:
true
});
const
base64
=
canvas
.
toDataURL
();
const
{
data
:
{
uptoken
}
}
=
await
editorApi
.
getUpToken
();
const
{
data
:
{
key
}
}
=
await
editorApi
.
uploadBase64
(
base64
.
split
(
'
,
'
)[
1
],
imgName
,
`UpToken
${
uptoken
}
`
);
this
.
formCustom
.
coverImage
=
config
.
qiniuHost
+
key
;
try
{
const
imgName
=
btoa
(
`coverImage-
${
uuidv4
().
substr
(
0
,
8
)}
`
);
const
gridEle
=
document
.
querySelector
(
'
.Dcm-container-panel
'
);
const
canvas
=
await
html2canvas
(
gridEle
as
HTMLElement
,
{
useCORS
:
true
});
const
base64
=
canvas
.
toDataURL
();
const
{
data
:
{
uptoken
}
}
=
await
editorApi
.
getUpToken
();
const
{
data
:
{
key
}
}
=
await
editorApi
.
uploadBase64
(
base64
.
split
(
'
,
'
)[
1
],
imgName
,
`UpToken
${
uptoken
}
`
);
this
.
formCustom
.
coverImage
=
config
.
qiniuHost
+
key
;
}
catch
(
e
)
{
console
.
log
(
e
);
}
}
}
\ No newline at end of file
app/web/page/editor/component/DynamicForm/component/ColorSelector/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"color-selector"
>
<Input
class=
"color-selector-input"
v-model=
"color"
placeholder=
"请输入"
@
on-change
=
"change"
></Input>
<ColorPicker
v-model=
"color"
@
on-change=
"change"
/>
<Input
class=
"color-selector-input"
v-model=
"color"
placeholder=
"请输入"
@
input
=
"change"
></Input>
<ColorPicker
v-model=
"color"
@
on-change=
"change
($event)
"
/>
</div>
</
template
>
<
script
>
...
...
app/web/page/editor/component/DynamicForm/component/CouponTableModal/index.ts
View file @
aaa4b0a3
...
...
@@ -9,7 +9,7 @@ export default class CouponTableModal extends Vue {
@
Prop
({
default
:
()
=>
([]),
type
:
Array
})
value
;
@
Prop
({
default
:
()
=>
([]),
type
:
Array
})
formControl
;
goods
:
object
=
cloneDeep
(
this
.
value
);
coupon
:
object
=
cloneDeep
(
this
.
value
);
table
:
object
[]
=
[
{
title
:
'
选择优惠券
'
,
...
...
@@ -20,16 +20,20 @@ export default class CouponTableModal extends Vue {
}
];
@
Watch
(
'
goods
'
)
@
Watch
(
'
coupon
'
)
onFormChange
(
newVal
)
{
this
.
$emit
(
'
input
'
,
newVal
);
}
async
query
(
data
)
{
const
res
=
await
operationApi
.
couponList
(
data
);
// receiverType 领取方式 1:主动领取 2:自动发放 3:不限
const
res
=
await
operationApi
.
couponList
({...
data
,
receiverType
:
1
});
const
couponInfoList
=
res
?.
couponInfoList
?.
map
(
item
=>
{
item
.
receiverTime
=
`
${
item
.
receiverStartTime
.
slice
(
0
,
10
)}
--
${
item
.
receiverEndTime
.
slice
(
0
,
10
)}
`
;
item
.
useTime
=
item
.
useTimeStart
?
`
${
item
.
useTimeStart
}
-
${
item
.
useTimeEnd
}
`
:
`自领取
${
item
.
receiverDaysValid
}
天后生效,有效天数
${
item
.
validDays
}
天`
;
if
(
this
.
coupon
.
some
(
v
=>
v
===
item
.
id
))
{
item
.
_checked
=
true
;
}
return
item
;
});
...
...
app/web/page/editor/component/DynamicForm/component/CouponTableModal/index.vue
View file @
aaa4b0a3
<
template
>
<table-modal
:table=
"table"
:formControl=
"formControl"
v-model=
"
goods
"
title=
"优惠券"
></table-modal>
<table-modal
:table=
"table"
:formControl=
"formControl"
v-model=
"
coupon
"
title=
"优惠券"
></table-modal>
</
template
>
<
script
lang=
"ts"
src=
"./index.ts"
></
script
>
<
style
></
style
>
\ No newline at end of file
app/web/page/editor/component/DynamicForm/component/GoodsTableModal/index.ts
View file @
aaa4b0a3
...
...
@@ -18,6 +18,7 @@ export default class GoodsTableModal extends Vue {
{
title
:
'
选择商品
'
,
type
:
'
goods
'
,
key
:
'
skuNo
'
,
multiple
:
true
,
columns
:
goodsColumn
.
call
(
this
),
query
:
this
.
query
...
...
@@ -25,6 +26,7 @@ export default class GoodsTableModal extends Vue {
{
title
:
'
选择商品组
'
,
type
:
'
goodsGroup
'
,
key
:
'
id
'
,
multiple
:
false
,
columns
:
goodsGroupColumn
.
call
(
this
),
query
:
this
.
queryGroup
...
...
@@ -39,7 +41,7 @@ export default class GoodsTableModal extends Vue {
async
query
(
data
)
{
const
{
records
,
total
}
=
await
operationApi
.
skuInfo
({
type
:
'
list
'
,
...
data
});
records
.
forEach
(
record
=>
{
if
(
this
.
goods
.
ids
.
some
(
v
=>
v
===
record
.
id
))
{
if
(
this
.
goods
.
ids
.
some
(
v
=>
v
===
record
.
skuNo
))
{
record
.
_checked
=
true
;
}
});
...
...
@@ -63,7 +65,7 @@ export default class GoodsTableModal extends Vue {
async
queryGroup
(
data
)
{
const
{
records
,
total
}
=
await
operationApi
.
specialPage
(
data
);
records
.
forEach
(
record
=>
{
if
(
this
.
goods
.
ids
.
some
(
v
=>
v
===
record
.
id
))
{
if
(
this
.
goods
.
ids
.
some
(
v
=>
v
===
record
.
skuNo
))
{
record
.
_checked
=
true
;
}
});
...
...
app/web/page/editor/component/DynamicForm/component/TableModal/index.ts
View file @
aaa4b0a3
...
...
@@ -62,7 +62,7 @@ export default class DynamicForm extends Mixins(DynamicFormMixin) {
if
(
this
.
table
.
length
>
1
)
{
this
.
$emit
(
'
input
'
,
{
type
:
this
.
table
[
this
.
activeName
].
type
,
ids
:
this
.
selections
.
map
(
v
=>
v
.
id
)
ids
:
this
.
selections
.
map
(
v
=>
v
[
this
.
table
[
this
.
activeName
].
key
]
)
});
}
else
{
this
.
$emit
(
'
input
'
,
this
.
selections
.
map
(
v
=>
v
.
id
));
...
...
app/web/page/editor/component/DynamicForm/component/Upload/index.vue
View file @
aaa4b0a3
...
...
@@ -7,7 +7,7 @@
</div>
</div>
<div
id=
"upload"
>
<div
id=
"upload_pic
"
>
<div
:id=
"id
"
>
<Icon
type=
"camera"
size=
"20"
></Icon>
</div>
</div>
...
...
@@ -16,20 +16,28 @@
<
script
>
import
'
@/service/qiniu.service
'
;
import
config
from
'
@/config
'
;
import
uuidv4
from
'
uuid/v4
'
;
// const id = uuidv4().substr(0, 8);
export
default
{
props
:
{
value
:
String
,
},
data
()
{
return
{
id
:
uuidv4
().
substr
(
0
,
8
)
}
},
methods
:
{
handleRemove
()
{
this
.
$emit
(
'
input
'
,
''
);
this
.
$emit
(
'
on-change
'
);
this
.
$emit
(
'
change
'
,
'
'
);
},
uploadQiniu
()
{
var
uploader
=
Qiniu
.
uploader
({
runtimes
:
'
html5
'
,
// 上传模式,依次退化
browse_button
:
'
upload_pic
'
,
// 上传选择的点选按钮,**必需**
browse_button
:
this
.
id
,
// 上传选择的点选按钮,**必需**
uptoken_url
:
'
https://opapi.xyqb.com/upload/getToken
'
,
// uptoken_url: `${config.apiHost}/upload/getToken`, //Ajax请求upToken的Url,**强烈建议设置**(服务端提供)
save_key
:
true
,
// 默认 false。若在服务端生成uptoken的上传策略中指定了 `sava_key`,则开启,SDK会忽略对key的处理
...
...
@@ -55,7 +63,7 @@
desc
:
''
,
});
this
.
$emit
(
'
input
'
,
config
.
qiniuHost
+
res
.
hash
);
this
.
$emit
(
'
on-
change
'
,
config
.
qiniuHost
+
res
.
hash
);
this
.
$emit
(
'
change
'
,
config
.
qiniuHost
+
res
.
hash
);
// this.url = config.qiniuHost + res.hash;
}
},
...
...
@@ -63,16 +71,18 @@
});
},
},
mounted
()
{
this
.
uploadQiniu
();
mounted
()
{
this
.
uploadQiniu
();
}
}
</
script
>
<
style
lang=
"less"
scoped=
""
>
.upload {
position: relative;
display: flex;
align-items: center;
width: 100%;
overflow: hidden;
&-img {
display: inline-block;
width: 60px;
...
...
app/web/page/editor/component/DynamicForm/index.ts
View file @
aaa4b0a3
...
...
@@ -22,6 +22,113 @@ export default class DynamicForm extends Mixins(ContextMenuMixin, DynamicFormMix
@
Getter
(
'
pageData
'
)
pageData
;
form
:
object
=
{};
styleSchame
:
object
=
{
curEle
:
[
{
label
:
'
定位
'
,
list
:
[
{
content
:
'
上对齐
'
,
icon
:
'
arrow-up-c
'
,
args
:
'
top
'
},
{
content
:
'
右对齐
'
,
icon
:
'
arrow-right-c
'
,
args
:
'
right
'
},
{
content
:
'
下对齐
'
,
icon
:
'
arrow-down-c
'
,
args
:
'
bottom
'
},
{
content
:
'
左对齐
'
,
icon
:
'
arrow-left-c
'
,
args
:
'
left
'
},
{
content
:
'
垂直居中
'
,
icon
:
'
android-film
'
,
args
:
'
vertical
'
},
{
content
:
'
水平居中
'
,
icon
:
'
android-film
'
,
args
:
'
horizontal
'
},
]
},
{
label
:
'
位置
'
},
{
label
:
'
尺寸
'
,
list
:
[
{
content
:
'
全屏
'
,
icon
:
'
arrow-resize
'
,
args
:
'
full
'
},
{
content
:
'
宽100%
'
,
icon
:
'
arrow-swap
'
,
args
:
'
width
'
},
{
content
:
'
高100%
'
,
icon
:
'
arrow-swap
'
,
args
:
'
height
'
},
]
},
{
label
:
'
宽高
'
},
{
label
:
'
背景图片
'
},
{
label
:
'
背景颜色
'
}
],
curChild
:
[
{
label
:
'
容器尺寸
'
,
list
:
[
{
content
:
'
全屏
'
,
icon
:
'
arrow-resize
'
,
args
:
[
667
,
375
],
},
{
content
:
'
根据背景图片或组件自动调整宽高
'
,
icon
:
'
image
'
,
args
:
[
667
,
375
,
true
],
},
{
content
:
'
宽100%
'
,
icon
:
'
arrow-swap
'
,
args
:
[
null
,
375
]
},
{
content
:
'
高100%
'
,
icon
:
'
arrow-swap
'
,
args
:
[
667
,
null
]
}
]
},
{
label
:
'
容器宽高
'
},
{
label
:
'
背景图片
'
},
{
label
:
'
背景颜色
'
}
]
};
get
curElement
()
{
let
element
=
{};
...
...
@@ -32,7 +139,7 @@ export default class DynamicForm extends Mixins(ContextMenuMixin, DynamicFormMix
element
=
this
.
pageData
.
elements
[
this
.
curEleIndex
];
}
}
console
.
log
(
'
curElement
'
,
element
);
//
console.log('curElement', element);
return
element
;
}
...
...
@@ -43,9 +150,10 @@ export default class DynamicForm extends Mixins(ContextMenuMixin, DynamicFormMix
get
commonStyle
()
{
let
rs
=
{
backgroundColor
:
''
,
backgroundImage
:
''
};
if
(
this
.
curEleIndex
||
this
.
curEleIndex
===
0
)
{
rs
=
cloneDeep
({
...
rs
,
...
this
.
pageData
.
elements
[
this
.
curEleIndex
].
commonStyle
});
if
(
this
.
curChildIndex
||
this
.
curChildIndex
===
0
)
{
rs
=
cloneDeep
({
...
rs
,
...
this
.
pageData
.
elements
[
this
.
curEleIndex
].
child
[
this
.
curChildIndex
].
commonStyle
});
}
else
{
rs
=
cloneDeep
({
...
rs
,
...
this
.
pageData
.
elements
[
this
.
curEleIndex
].
commonStyle
});
}
}
// console.log('commonStyle', rs);
...
...
@@ -78,6 +186,18 @@ export default class DynamicForm extends Mixins(ContextMenuMixin, DynamicFormMix
return
result
;
}
get
isSelected
()
{
return
this
.
curChildIndex
||
this
.
curChildIndex
===
0
||
this
.
curEleIndex
||
this
.
curEleIndex
===
0
;
}
get
childSelected
()
{
return
this
.
curChildIndex
||
this
.
curChildIndex
===
0
;
}
get
parentSelected
()
{
return
(
this
.
curEleIndex
||
this
.
curEleIndex
===
0
)
&&
!
this
.
curChildIndex
&&
this
.
curChildIndex
!==
0
;
}
// 监听curElement变化, 更新form
@
Watch
(
'
curElement
'
,
{
immediate
:
true
,
deep
:
true
})
onElementChange
(
newVal
)
{
...
...
@@ -92,7 +212,7 @@ export default class DynamicForm extends Mixins(ContextMenuMixin, DynamicFormMix
}
});
console
.
log
(
'
curElement
'
,
newVal
,
this
.
form
);
//
console.log('curElement', newVal, this.form);
}
// 监听form变化, 更新pageData
...
...
app/web/page/editor/component/DynamicForm/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"dynamic-form"
>
<div
class=
"dynamic-form"
v-if=
"isSelected"
>
<h2>
{{
curElement
.
title
}}
</h2>
<template>
<Form
class=
"dynamic-form-component"
:label-width=
"80"
:model=
"form"
>
<h3
v-if=
"!hasGroup"
>
组件属性
</h3>
<template
v-for=
"(item, index) in curElement.schame"
>
<div
v-if=
"item.title"
>
<h3>
{{
item
.
title
}}
</h3>
<FormItem
:label=
"child.name"
:key=
"child.key"
v-for=
"child in item.children"
>
<component
:is=
"getComponent(child.type)"
:options=
"child.options"
:formControl=
"child.formControl"
v-model=
"form[child.key]"
/>
</FormItem>
</div>
<!--
<component
v-else-if=
"item.formControl"
:is=
"getComponent(item.type)"
:options=
"item.options"
:formControl=
"item.formControl"
:name=
"item.name"
v-model=
"form[item.key]"
/>
-->
<FormItem
class=
"Df-component-formitem"
v-else
:label=
"item.name"
>
<component
:is=
"getComponent(item.type)"
:options=
"item.options"
:formControl=
"item.formControl"
v-model=
"form[item.key]"
/>
<Form
class=
"dynamic-form-component"
:label-width=
"80"
:model=
"form"
v-if=
"curElement.schame && curElement.schame.length"
>
<h3
v-if=
"!hasGroup"
>
组件属性
</h3>
<template
v-for=
"(item, index) in curElement.schame"
>
<div
v-if=
"item.title"
>
<h3>
{{
item
.
title
}}
</h3>
<FormItem
:label=
"child.name"
:key=
"child.key"
v-for=
"child in item.children"
>
<component
:is=
"getComponent(child.type)"
:options=
"child.options"
:formControl=
"child.formControl"
v-model=
"form[child.key]"
/>
</FormItem>
</
template
>
</Form>
</template>
<
template
>
<!--
<h3>
基础样式
</h3>
-->
<Form
class=
"dynamic-form-basic"
:label-width=
"80"
>
<h3>
基础样式
</h3>
<template
v-if=
"curChildIndex || curChildIndex === 0"
>
<FormItem
label=
"定位"
>
<Tooltip
placement=
"top"
content=
"上对齐"
>
<Button
type=
"ghost"
icon=
"arrow-up-c"
@
click=
"changeAlignType('top')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"右对齐"
>
<Button
type=
"ghost"
icon=
"arrow-right-c"
@
click=
"changeAlignType('right')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"下对齐"
>
<Button
type=
"ghost"
icon=
"arrow-down-c"
@
click=
"changeAlignType('bottom')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"左对齐"
>
<Button
type=
"ghost"
icon=
"arrow-left-c"
@
click=
"changeAlignType('left')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"垂直居中"
>
<Button
type=
"ghost"
icon=
"android-film"
@
click=
"changeAlignType('vertical')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"水平居中"
>
<Button
type=
"ghost"
icon=
"android-film"
@
click=
"changeAlignType('horizontal')"
></Button>
</Tooltip>
</FormItem>
<FormItem
label=
"位置"
>
<InputNumber
class=
"Df-basic-inputnumber"
v-model=
"commonStyle.left"
@
on-change=
"updateStyle($event, 'left')"
></InputNumber>
<InputNumber
v-model=
"commonStyle.top"
@
on-change=
"updateStyle($event, 'top')"
></InputNumber>
</FormItem>
<FormItem
label=
"尺寸"
>
<Tooltip
placement=
"top"
content=
"全屏"
>
<Button
type=
"ghost"
icon=
"arrow-resize"
@
click=
"resizedChildEvent('full')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"宽100%"
>
<Button
type=
"ghost"
icon=
"arrow-swap"
@
click=
"resizedChildEvent('width')"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"高100%"
>
<Button
type=
"ghost"
icon=
"arrow-swap"
@
click=
"resizedChildEvent('height')"
></Button>
</Tooltip>
</FormItem>
<FormItem
label=
"宽高"
>
<InputNumber
class=
"Df-basic-inputnumber"
:max=
"375"
:min=
"0"
v-model=
"commonStyle.width"
@
on-change=
"updateStyle($event, 'width')"
></InputNumber>
<InputNumber
:max=
"667"
:min=
"0"
v-model=
"commonStyle.height"
@
on-change=
"updateStyle($event, 'height')"
></InputNumber>
</div>
<FormItem
class=
"Df-component-formitem"
v-else
:label=
"item.name"
>
<component
:is=
"getComponent(item.type)"
:options=
"item.options"
:formControl=
"item.formControl"
v-model=
"form[item.key]"
/>
</FormItem>
</
template
>
</Form>
<Form
class=
"dynamic-form-basic"
:label-width=
"80"
>
<h3>
基础样式
</h3>
<
template
v-if=
"childSelected"
>
<template
v-for=
"item in styleSchame.curEle"
>
<FormItem
:label=
"item.label"
>
<template
v-if=
"item.label === '宽高'"
>
<InputNumber
class=
"Df-basic-inputnumber"
:max=
"375"
:min=
"0"
v-model=
"commonStyle.width"
@
on-change=
"updateStyle($event, 'width')"
></InputNumber>
<InputNumber
:max=
"667"
:min=
"0"
v-model=
"commonStyle.height"
@
on-change=
"updateStyle($event, 'height')"
></InputNumber>
</
template
>
<
template
v-else-if=
"item.label === '位置'"
>
<InputNumber
class=
"Df-basic-inputnumber"
v-model=
"commonStyle.left"
@
on-change=
"updateStyle($event, 'left')"
></InputNumber>
<InputNumber
v-model=
"commonStyle.top"
@
on-change=
"updateStyle($event, 'top')"
></InputNumber>
</
template
>
<upload
v-else-if=
"item.label === '背景图片'"
v-model=
"commonStyle.backgroundImage"
@
change=
"updateStyle($event, 'backgroundImage')"
></upload>
<ColorSelector
v-else-if=
"item.label === '背景颜色'"
v-model=
"commonStyle.backgroundColor"
@
input=
"updateStyle($event, 'backgroundColor')"
></ColorSelector>
<
template
v-else
>
<Tooltip
placement=
"top"
:content=
"child.content"
v-for=
"child in item.list"
:key=
"child.content"
>
<Button
type=
"ghost"
:icon=
"child.icon"
@
click=
"changeAlignType(...child.args)"
></Button>
</Tooltip>
</
template
>
</FormItem>
</template>
<
template
v-if=
"(curEleIndex || curEleIndex === 0) && !curChildIndex && curChildIndex !== 0"
>
<FormItem
label=
"容器尺寸"
>
<Tooltip
placement=
"top"
content=
"全屏"
>
<Button
type=
"ghost"
icon=
"arrow-resize"
@
click=
"resizedEvent(667, 375)"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"根据背景图片或组件自动调整宽高"
>
<Button
type=
"ghost"
icon=
"image"
@
click=
"resizedEvent(667, 375, true)"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"宽100%"
>
<Button
type=
"ghost"
icon=
"arrow-swap"
@
click=
"resizedEvent(null, 375)"
></Button>
</Tooltip>
<Tooltip
placement=
"top"
content=
"高100%"
>
<Button
type=
"ghost"
icon=
"arrow-swap"
@
click=
"resizedEvent(667, null)"
></Button>
</Tooltip>
</FormItem>
<FormItem
label=
"容器宽高"
>
<InputNumber
class=
"Df-basic-inputnumber"
:max=
"375"
:min=
"0"
v-model=
"point.w"
@
on-change=
"updatePoint($event, 'w')"
></InputNumber>
<InputNumber
:max=
"667"
:min=
"0"
v-model=
"point.h"
@
on-change=
"updatePoint($event, 'h')"
></InputNumber>
</template>
<
template
v-if=
"parentSelected"
>
<template
v-for=
"item in styleSchame.curChild"
>
<FormItem
:label=
"item.label"
>
<template
v-if=
"item.label === '容器宽高'"
>
<InputNumber
class=
"Df-basic-inputnumber"
:max=
"375"
:min=
"0"
v-model=
"point.w"
@
on-change=
"updatePoint($event, 'w')"
></InputNumber>
<InputNumber
:max=
"667"
:min=
"0"
v-model=
"point.h"
@
on-change=
"updatePoint($event, 'h')"
></InputNumber>
</
template
>
<upload
v-else-if=
"item.label === '背景图片'"
v-model=
"commonStyle.backgroundImage"
@
change=
"updateStyle($event, 'backgroundImage')"
></upload>
<ColorSelector
v-else-if=
"item.label === '背景颜色'"
v-model=
"commonStyle.backgroundColor"
@
input=
"updateStyle($event, 'backgroundColor')"
></ColorSelector>
<
template
v-else
>
<Tooltip
placement=
"top"
:content=
"child.content"
v-for=
"child in item.list"
:key=
"child.content"
>
<Button
type=
"ghost"
:icon=
"child.icon"
@
click=
"resizedEvent(...child.args)"
></Button>
</Tooltip>
</
template
>
</FormItem>
</template>
<FormItem
label=
"背景图片"
>
<Upload
v-model=
"commonStyle.backgroundImage"
@
change=
"updateStyle($event, 'backgroundImage')"
></Upload>
</FormItem>
<FormItem
label=
"背景颜色"
>
<ColorSelector
v-model=
"commonStyle.backgroundColor"
@
input=
"updateStyle($event, 'backgroundColor')"
></ColorSelector>
</FormItem>
</Form>
</template>
</template>
</Form>
</div>
</template>
<
script
lang=
"ts"
src=
"./index.ts"
></
script
>
...
...
app/web/page/editor/component/DynamicPageForm/index.ts
View file @
aaa4b0a3
import
{
Component
,
Mixins
,
Prop
,
Watch
}
from
'
vue-property-decorator
'
;
import
{
Getter
,
State
}
from
'
vuex-class
'
;
import
{
reduce
,
ceil
,
subtract
,
divide
}
from
'
lodash
'
;
import
{
reduce
,
ceil
,
subtract
,
divide
,
cloneDeep
,
assign
}
from
'
lodash
'
;
import
ContextMenuMixin
from
'
@editor/mixins/contextMenu.mixin
'
;
import
Upload
from
'
../DynamicForm/component/Upload/index.vue
'
;
import
ColorSelector
from
'
../DynamicForm/component/ColorSelector/index.vue
'
;
...
...
@@ -13,33 +13,48 @@ import { resizeDiv, getStyle } from '@/service/utils.service';
export
default
class
DynamicPageForm
extends
Mixins
(
ContextMenuMixin
)
{
@
Getter
(
'
pageData
'
)
pageData
;
title
:
string
=
'
页面背景
'
;
form
:
object
=
{};
schame
:
object
[]
=
[
title
:
string
=
'
页面
'
;
commonStyleForm
:
object
=
{};
propsForm
:
object
=
{};
commonStyleSchame
:
object
[]
=
[
{
key
:
'
backgroundImage
'
,
name
:
'
背景图片
'
,
type
:
'
Upload
'
type
:
'
Upload
'
,
},
{
key
:
'
backgroundColor
'
,
name
:
'
背景颜色
'
,
type
:
'
ColorSelector
'
},
}
];
propsSchame
:
object
[]
=
[
{
key
:
'
showBackTop
'
,
name
:
'
返回顶部
'
,
type
:
'
checkbox
'
}
];
@
Watch
(
'
pageData
'
,
{
immediate
:
true
,
deep
:
true
})
onElementChange
(
newVal
)
{
const
keys
=
Object
.
keys
(
this
.
schame
);
// this.form = {};
this
.
schame
.
forEach
(
schame
=>
{
this
.
$set
(
this
.
form
,
schame
.
key
,
this
.
pageData
?.
commonStyle
[
schame
.
key
]);
this
.
commonStyleSchame
.
forEach
(
schame
=>
{
this
.
$set
(
this
.
commonStyleForm
,
schame
.
key
,
this
.
pageData
?.
commonStyle
[
schame
.
key
]);
});
this
.
propsSchame
.
forEach
(
schame
=>
{
this
.
$set
(
this
.
propsForm
,
schame
.
key
,
this
.
pageData
?.
props
[
schame
.
key
]);
});
}
@
Watch
(
'
commonStyleForm
'
,
{
immediate
:
true
,
deep
:
true
})
onCommonStyleFormChange
(
newVal
)
{
this
.
$emit
(
'
modProps
'
,
newVal
,
'
page
'
,
'
commonStyle
'
);
}
@
Watch
(
'
f
orm
'
,
{
immediate
:
true
,
deep
:
true
})
onFormChange
(
newVal
)
{
this
.
$emit
(
'
modProps
'
,
this
.
form
,
'
page
'
);
@
Watch
(
'
propsF
orm
'
,
{
immediate
:
true
,
deep
:
true
})
on
Props
FormChange
(
newVal
)
{
this
.
$emit
(
'
modProps
'
,
newVal
,
'
page
'
,
'
props
'
);
}
// resizedChildEvent(type) {
...
...
app/web/page/editor/component/DynamicPageForm/index.vue
View file @
aaa4b0a3
<
template
>
<div
class=
"dynamic-form"
>
<h2>
{{
title
}}
</h2>
<Form
class=
"dynamic-form-component"
:label-width=
"80"
:model=
"
f
orm"
>
<h3>
组件
属性
</h3>
<template
v-for=
"(item, index) in
s
chame"
>
<Form
class=
"dynamic-form-component"
:label-width=
"80"
:model=
"
propsF
orm"
>
<h3>
基础
属性
</h3>
<template
v-for=
"(item, index) in
propsS
chame"
>
<FormItem
class=
"Df-component-formitem"
:label=
"item.name"
>
<component
:is=
"item.type"
:options=
"item.options"
v-model=
"form[item.key]"
/>
<component
:is=
"item.type"
:options=
"item.options"
v-model=
"propsForm[item.key]"
/>
</FormItem>
</
template
>
</Form>
<Form
class=
"dynamic-form-component"
:label-width=
"80"
:model=
"commonStyleForm"
>
<h3>
基础样式
</h3>
<
template
v-for=
"(item, index) in commonStyleSchame"
>
<FormItem
class=
"Df-component-formitem"
:label=
"item.name"
>
<component
:is=
"item.type"
:options=
"item.options"
v-model=
"commonStyleForm[item.key]"
/>
</FormItem>
</
template
>
</Form>
...
...
app/web/page/editor/component/FreedomContainer/index.ts
View file @
aaa4b0a3
import
{
Component
,
Prop
,
Mixins
,
Watch
}
from
'
vue-property-decorator
'
;
// import LoginForm from '@/lib/Form/index.vue';
import
DownloadGuide
from
'
@/lib/DownloadGuide/index.vue
'
;
import
Marquee
from
'
@/lib/Marquee/index.vue
'
;
import
Custom
Marquee
from
'
@/lib/Marquee/index.vue
'
;
import
ContextMenuMixin
from
'
@editor/mixins/contextMenu.mixin
'
;
import
TransformStyleMixin
from
'
@/page/mixins/transformStyle.mixin
'
;
import
{
cloneDeep
,
pick
,
omit
,
throttle
}
from
'
lodash
'
;
import
{
Action
,
Mutation
,
State
,
Getter
}
from
'
vuex-class
'
;
import
{
convertPointStyle
,
getStyle
}
from
'
@/service/utils.service
'
;
@
Component
({
components
:
{
DownloadGuide
,
Marquee
},
name
:
'
FreedomContainer
'
})
@
Component
({
components
:
{
DownloadGuide
,
Custom
Marquee
},
name
:
'
FreedomContainer
'
})
export
default
class
FreedomContainer
extends
Mixins
(
ContextMenuMixin
,
TransformStyleMixin
)
{
@
Action
(
'
setDragable
'
)
setDragable
;
@
State
(
state
=>
state
.
editor
.
curEleIndex
)
curEleIndex
;
...
...
app/web/page/editor/view/dashboard/index.ts
View file @
aaa4b0a3
...
...
@@ -33,6 +33,7 @@ export default class DashBoard extends Mixins(ContextMenuMixin, GoodsTabsMixin,
@
Mutation
(
'
SET_PAGE_INFO
'
)
setPageInfo
;
@
Mutation
(
'
SET_PAGE_DATA
'
)
setPageData
;
@
Mutation
(
'
UPDATE_PAGE_STYLE
'
)
setPageStyle
;
@
Mutation
(
'
UPDATE_PAGE_PROPS
'
)
setPageProps
;
@
Action
(
'
resetPageData
'
)
resetPageData
;
@
Action
(
'
savePageData
'
)
savePageData
;
@
Action
(
'
getPageDate
'
)
getPageDate
;
...
...
@@ -138,9 +139,13 @@ export default class DashBoard extends Mixins(ContextMenuMixin, GoodsTabsMixin,
}
}
modProps
(
props
,
ele
)
{
modProps
(
props
,
ele
,
type
)
{
if
(
ele
===
'
page
'
)
{
this
.
setPageStyle
({
data
:
props
});
if
(
type
===
'
commonStyle
'
)
{
this
.
setPageStyle
({
data
:
props
});
}
else
if
(
type
===
'
props
'
)
{
this
.
setPageProps
({
data
:
props
});
}
}
else
if
(
ele
===
'
component
'
)
{
let
currentEle
=
{};
if
(
this
.
curEleIndex
!==
null
)
{
...
...
app/web/page/editor/view/dashboard/index.vue
View file @
aaa4b0a3
...
...
@@ -81,10 +81,10 @@
</Col>
<Col
span=
"8"
:class=
"[
{'Dcm-sider_none': isCollapsed}, 'Dc-middle-sider']">
<Tabs
class=
"Dc-middle-editing"
type=
"card"
>
<TabPane
label=
"
属性
"
>
<TabPane
label=
"
组件设置
"
>
<dynamic-form
@
modProps=
"modProps"
@
resizedChildEvent=
"resizedChildEvent"
></dynamic-form>
</TabPane>
<
TabPane
label=
"事件"
>
事件
</TabPane
>
<
!--
<TabPane
label=
"事件"
>
事件
</TabPane>
--
>
<TabPane
label=
"页面设置"
>
<dynamic-page-form
@
modProps=
"modProps"
@
resizedChildEvent=
"resizedChildEvent"
></dynamic-page-form>
</TabPane>
...
...
app/web/page/mixins/transformStyle.mixin.ts
View file @
aaa4b0a3
...
...
@@ -14,12 +14,14 @@ export default class TransformStyleMixin extends Vue {
}
else
{
style
[
key
]
=
styleObj
[
key
]?.
includes
(
'
px
'
)
?
`
${(
+
(
styleObj
[
key
].
slice
(
0
,
-
2
))
/
37.5
).
toFixed
(
2
)}
rem`
:
styleObj
[
key
];
}
if
(
key
===
'
backgroundImage
'
)
{
style
.
backgroundImage
=
`url(
${
style
.
backgroundImage
}
)`
;
if
(
key
===
'
backgroundImage
'
&&
style
.
backgroundImage
)
{
// style.backgroundImage = `url(${style.backgroundImage})`;
style
.
background
=
`url(
${
style
.
backgroundImage
}
) no-repeat 0 0 / cover`
;
}
}
const
transformFun
=
element
===
'
container
'
?
pick
:
omit
;
style
=
transformFun
(
style
,
[
'
position
'
,
'
top
'
,
'
left
'
]);
if
(
element
!==
'
container
'
)
{
style
=
omit
(
style
,
[
'
position
'
,
'
top
'
,
'
left
'
]);
}
return
style
;
}
}
\ No newline at end of file
app/web/page/store/modules/editor/index.ts
View file @
aaa4b0a3
...
...
@@ -15,6 +15,7 @@ import {
SET_PAGE_DATA
,
UPDATE_COMMON_STYLE
,
UPDATE_PAGE_STYLE
,
UPDATE_PAGE_PROPS
}
from
'
./type
'
;
import
RootState
from
'
../../state
'
;
...
...
@@ -135,6 +136,9 @@ export default class EditorModule implements Module<EditorState, RootState> {
[
UPDATE_PAGE_STYLE
](
state
,
{
data
})
{
(
state
.
pageInfo
.
page
as
Page
).
commonStyle
=
data
;
},
[
UPDATE_PAGE_PROPS
](
state
,
{
data
})
{
(
state
.
pageInfo
.
page
as
Page
).
props
=
data
;
},
[
ADD_ELEMENTS
](
state
,
{
containerIndex
,
data
})
{
const
page
=
(
state
.
pageInfo
.
page
as
Page
).
elements
;
if
(
containerIndex
||
containerIndex
===
0
)
{
...
...
app/web/page/store/modules/editor/state.ts
View file @
aaa4b0a3
...
...
@@ -35,6 +35,7 @@ export interface PageElement {
export
interface
Page
{
commonStyle
:
CommonStyle
;
props
:
object
;
elements
:
PageElement
[];
}
...
...
@@ -62,6 +63,9 @@ export const defaultState = {
backgroundColor
:
'
#f7f8fa
'
,
backgroundImage
:
''
},
props
:
{
showBackTop
:
false
},
elements
:
[],
}
},
...
...
app/web/page/store/modules/editor/type.ts
View file @
aaa4b0a3
...
...
@@ -10,4 +10,5 @@ export const RESET_PAGE_DATA = 'RESET_PAGE_DATA';
export
const
SET_TEMPLATE_LIST
=
'
SET_TEMPLATE_LIST
'
;
export
const
SET_PAGE_DATA
=
'
SET_PAGE_DATA
'
;
export
const
UPDATE_COMMON_STYLE
=
'
UPDATE_COMMON_STYLE
'
;
export
const
UPDATE_PAGE_STYLE
=
'
UPDATE_PAGE_STYLE
'
;
\ No newline at end of file
export
const
UPDATE_PAGE_STYLE
=
'
UPDATE_PAGE_STYLE
'
;
export
const
UPDATE_PAGE_PROPS
=
'
UPDATE_PAGE_PROPS
'
;
app/web/service/http.service.ts
View file @
aaa4b0a3
...
...
@@ -63,7 +63,7 @@ instance.interceptors.request.use(
config
.
cancelToken
=
new
CancelToken
(
c
=>
(
pending
[(
config
.
url
+
JSON
.
stringify
(
config
.
data
))
as
string
]
=
c
));
// 添加token
const
token
=
localStorage
.
get
(
'
token
'
);
if
(
token
)
{
if
(
token
&&
!
config
.
hideToken
)
{
config
.
headers
[
'
X-Auth-Token
'
]
=
token
;
if
(
config
.
accessToken
)
{
config
.
headers
[
'
Access-Token
'
]
=
token
;
}
}
...
...
app/web/service/qg.service.ts
View file @
aaa4b0a3
...
...
@@ -24,7 +24,9 @@ import {
Tabs
,
Notify
,
Swipe
,
SwipeItem
SwipeItem
,
Toast
,
BackTop
}
from
'
@qg/cherry-ui
'
;
import
{
KaLoginForm
}
from
'
@qg/citrus-ui
'
;
...
...
@@ -49,9 +51,13 @@ Vue.use(Form);
// Vue.use(List);
Vue
.
use
(
Tab
);
Vue
.
use
(
Tabs
);
// Vue.use(Toast);
// Vue.use(Swipe);
// Vue.use(SwipeItem);
// Vue.use(Swipe);
Vue
.
use
(
BackTop
);
Vue
.
use
(
KaLoginForm
);
Vue
.
prototype
.
$notify
=
Notify
;
Vue
.
prototype
.
$toast
=
Toast
;
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