Commit 7e8df88a authored by 秦海涛's avatar 秦海涛

init

parent ad5fc65b
node_modules
.tea
.DS_Store
.vscode
\ No newline at end of file
import request from './utils/request'; import request from "./utils/request";
const API = { const API = {
// 上传数据生成xslx文件 uploadDataCreateFile // 上传数据生成xslx文件 uploadDataCreateFile
uploadDataCreateFile: params => request('exportAwardsList', 'POST', params), uploadDataCreateFile: (params) => request("exportAwardsList", "POST", params),
// 保存活动配置 saveActivityInfo // 保存活动配置 saveActivityInfo
saveActivityInfo: params => request('saveActivityInfo', 'POST', params), saveActivityInfo: (params) => request("saveActivityInfo", "POST", params),
// 删除活动 delActivity // 删除活动 delActivity
delActivity: params => request('delActivity', 'POST', params), delActivity: (params) => request("delActivity", "POST", params),
// 授权信息保存 sellerSave // 授权信息保存 sellerSave
sellerSave: params => request('sellerSave', 'POST', params), sellerSave: (params) => request("sellerSave", "POST", params),
// 生成活动规则 generateRule
generateRule: params => request('generateRule', 'POST', params),
// 获取中奖名单 findWinnerInfoList // 获取中奖名单 findWinnerInfoList
findWinnerInfoList: params => request('findWinnerInfoList', 'POST', params), findWinnerInfoList: (params) => request("findWinnerInfoList", "POST", params),
// 获取活动列表云函数 getActivityList // 获取活动列表云函数 getActivityList
getActivityList: params => request('getActivityList', 'POST', params), getActivityList: (params) => request("getActivityList", "POST", params),
// 获取活动配置 getActivityDetail // 获取活动配置 getActivityDetail
getActivityDetail: params => request('getActivityDetail', 'POST', params), getActivityDetail: (params) => request("getActivityDetail", "POST", params),
// 获取淘宝店家商品 findItemListByStatus // 获取淘宝店家商品 findItemListByStatus
findItemListByStatus: params => request('findItemListByStatus', 'POST', params, { findItemListByStatus: (params) =>
isShowLoading: true request("findItemListByStatus", "POST", params, {
}), isShowLoading: true,
}),
// 通过id去查找商品 findItemListByIds // 通过id去查找商品 findItemListByIds
findItemListByIds: params => request('findItemListByIds', 'POST', params, { findItemListByIds: (params) =>
isShowLoading: true request("findItemListByIds", "POST", params, {
}), isShowLoading: true,
}),
// 通过权益ename查询商品 queryBenefitByEname // 通过权益ename查询商品 queryBenefitByEname
queryBenefitByEname: params => request('queryBenefitByEname', 'POST', params), queryBenefitByEname: (params) =>
request("queryBenefitByEname", "POST", params),
// 复制创建新活动
createCopyActivity: (params) => request("copyNewActivity", "POST", params),
}; };
export default API; export default API;
\ No newline at end of file
{ {
"pages": [ "pages": [
"pages/index/index" "pages/index/index",
"pages/cmp/index/index"
], ],
"window": { "window": {
"defaultTitle": "xxxxx店铺商家后台" "defaultTitle": "店铺漂流记商家后台"
}, },
"plugins": { "plugins": {
"myPlugin": { "myPlugin": {
......
export const passUrlList = [
"1688.cn",
"taobao.cn",
"taobao.com",
"taobao.net",
"tb.cn",
"tmall.com",
"zhifu.com",
"zhifubao.com",
"juhuasuan.com",
"tmall.hk",
"tmall.com.hk",
"dingtalk.com",
"yushanfang.com",
"guoguo-app.com",
"umeng.com",
];
\ No newline at end of file
export const getMillSeconsByDays = (days = 1) => days * 24 * 3600 * 1000;
\ No newline at end of file
.db-dialog-content { .db-dialog-content {
width: 515px;
background-color: #fff; background-color: #fff;
position: fixed;
left: 50%;
top: 100px;
} }
.db-dialog-title { .db-dialog-title {
display: flex; display: flex;
...@@ -12,6 +14,10 @@ ...@@ -12,6 +14,10 @@
height: 60px; height: 60px;
padding: 0 24px; padding: 0 24px;
} }
.db-dialog-title_no {
height: 30px;
justify-content: flex-end;
}
.db-dialog-content_inner { .db-dialog-content_inner {
/* width: 100%; */ /* width: 100%; */
......
<overlay <overlay
visible="{{ visible }}" visible="{{ visible }}"
hasMask="{{true}}" hasMask="{{hasMask}}"
triggerType="click" triggerType="click"
wrapperClassName="overlay" target=".aaa"
disableScroll
target=".edit-breadcrumb"
data-index="1" data-index="1"
canCloseByMask="{{true}}" canCloseByMask="{{true}}"
> >
<view class="db-dialog-content" style="{{ { width: (width + 'px').replace('pxpx', 'px') } }}"> <view class="db-dialog-content" style="{{ { width: (width + 'px').replace('pxpx', 'px'), marginLeft: '-' + (width / 2 + 'px').replace('pxpx', 'px') } }}">
<view class="db-dialog-title">{{title}}<icon size="xs" type="close" onTap="closeDialog" style="color: #999999;" /></view> <view class="db-dialog-title {{!title ? 'db-dialog-title_no': ''}}">{{title}}<icon size="xs" type="close" onTap="onCloseDialog" style="color: #999999;" /></view>
<view class="db-dialog-content_inner"> <view class="db-dialog-content_inner">
<slot/> <slot/>
</view> </view>
......
...@@ -2,15 +2,17 @@ Component({ ...@@ -2,15 +2,17 @@ Component({
mixins: [], mixins: [],
data: {}, data: {},
props: { props: {
width: 515,
title: '', title: '',
visible: false, visible: false,
onClose: () => {} onClose: () => {},
hasMask: true
}, },
didMount() {}, didMount() {},
didUpdate() {}, didUpdate() {},
didUnmount() {}, didUnmount() {},
methods: { methods: {
closeDialog() { onCloseDialog() {
this.props.onClose() this.props.onClose()
} }
}, },
......
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"side-bar": "/components/base/side-bar/side-bar" "side-bar": "/components/basic/side-bar/side-bar"
} }
} }
\ No newline at end of file
.tb-qa-tips {
width: 12px;
height: 12px;
display: inline-block;
background: url(//yun.duiba.com.cn/activity/mini-taobao/question.png) center no-repeat;
background-size: 100% 100%;
}
\ No newline at end of file
<balloon closable="{{false}}" visible="{{balloonVisible}}" align="{{tipsAlign}}" onClose="setBalloonVisibleFalse">
<view
data-x="balloonVisible"
slot="trigger"
onTap="setBalloonVisible"
class="tb-qa-tips" >
</view>
<text>{{tips}}</text>
</balloon>
Component({
data: {
balloonVisible: false
},
props: {
tipsAlign: 'r',
tips: ''
},
didMount() {},
methods: {
setBalloonVisible() {
this.setData({
balloonVisible: true
})
},
setBalloonVisibleFalse() {
this.setData({
balloonVisible: false
})
}
},
});
.confirm-dialog-content { .confirm-dialog-content {
width: 515px!important; width: 515px!important;
min-height: 225px; min-height: 225px;
position:fixed;
left: 50%;
margin-left: -257px;
top: 200px;
background-color: #fff; background-color: #fff;
} }
.confirm-dialog-title { .confirm-dialog-title {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
triggerType="click" triggerType="click"
wrapperClassName="overlay" wrapperClassName="overlay"
disableScroll disableScroll
target=".edit-breadcrumb" target=".aaa"
data-index="1" data-index="1"
canCloseByMask="{{true}}" canCloseByMask="{{true}}"
> >
......
{
"component": true
}
\ No newline at end of file
.copy-link-wrap{
color:#333;
}
.copy-link-title{
margin-top:10px;
}
.link-view{
display:flex;
}
.link-view .copy-link-url{
width:70%;
height:25px;
overflow:auto;
}
.copy-link-url{
background-color:#eee;
padding:5px 20px;
flex-grow:1;
width:70%;
overflow:auto;
margin-right:10px;
}
.link-btn{
flex-grow:0;
flex-shrink:0;
}
.copy-link-title-export{
margin-bottom:10px;
}
<dialog-wrap
title="如何导出名单"
visible="{{visible}}"
onClose="onCloseDialog"
>
<view class="copy-link-wrap">
<view >导出方式:</view>
<view class="copy-link-title">1.下载文件:复制下方链接-打开电脑浏览器一 输入链接下载Excel;</view>
<view>2.更改文件属性:将下载的文件重命名,在文件名后输入xlsx即可;</view>
<view class="copy-link-title copy-link-title-export">导出链接:</view>
<view class="link-view">
<text class="copy-link-url">{{url}}</text><button type="primary" class="link-btn" onTap="copyLink" >复制链接</button>
</view>
</view>
</dialog-wrap>
\ No newline at end of file
Component({
mixins: [],
data: {},
props: {
onClose: () => {},
url: "",
visible: false,
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onCloseDialog() {
this.props && this.props.onClose();
},
copyLink() {
const { url } = this.props;
my.setClipboard({
text: url.replace(/amp;/g, ""),
success(res) {
my.showToast({
type: "success",
content: "下载链接复制成功,请在浏览器中打开下载",
});
},
});
},
},
});
{
"component": true,
"usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap"
}
}
\ No newline at end of file
.modal-content-imageUpload-wrap{
.probablity-prize-content {
background: #FFFFFF;
max-height: 507px;
display: flex;
flex-direction: column;
}
.probablity-prize-content-imageUpload-wrap{
display:flex; display:flex;
padding-top:10px; padding-top:10px;
box-sizing:border-box; box-sizing:border-box;
} }
.modal-content-imageUpload-btn view{ .probablity-prize-content-imageUpload-btn view{
margin-bottom:5px; margin-bottom:5px;
color:#666666 color:#666666
} }
.edit-content-formitem-choosePrize-tips-success{ .probablity-prize-content-formitem-choosePrize-tips-success{
color:#71B204 !important; color:#71B204 !important;
padding-top:20px; padding-top:20px;
font-size:14px; font-size:14px;
} }
.edit-content-formitem-choosePrize-tips-fail{ .probablity-prize-content-formitem-choosePrize-tips-fail{
color:#F23C3C !important; color:#F23C3C !important;
padding-top:20px; padding-top:20px;
font-size:14px; font-size:14px;
} }
.edit-content-formitem-choosePrize-wrap{ .probablity-prize-content-formitem-choosePrize-wrap{
display:flex; display:flex;
} }
.edit-content-input.edit-probablity-input { .probablity-prize-content-input.edit-probablity-input {
width: 300px!important; width: 310px!important;
margin-right: 10px; margin-right: 10px;
} }
.edit-content-formitem-goequity{ .probablity-prize-content-input.dialog-rank-input {
width: 310px!important;
}
.probablity-prize-content-formitem-goequity{
width:80px; width:80px;
height:30px; height:30px;
border-radius:5px; border-radius:5px;
...@@ -38,17 +49,27 @@ ...@@ -38,17 +49,27 @@
text-align:center; text-align:center;
line-height:30px; line-height:30px;
} }
.modal-content-imageUpload-btn{ .probablity-prize-content-imageUpload-btn{
display:flex; display:flex;
flex-direction:column; flex-direction:column;
justify-content:space-around; justify-content:space-around;
} }
.modal-content-imageUpload-btn text{ .probablity-prize-content-imageUpload-btn text{
font-size:12px; font-size:12px;
margin-bottom:5px; margin-bottom:5px;
color:#666666; color:#666666;
} }
.edit-content-formItem-nocoupon{ /* .probablity-prize-content-formItem {
display: block;
} */
.probablity-prize-content-formItem-nocoupon{
color:#000 !important; color:#000 !important;
margin-left:5px; margin-left:5px;
}
.probablity-prize-content-btn {
display: flex;
justify-content: flex-end;
}
.probablity-prize-content-btn_confirm {
margin-right: 10px;
} }
\ No newline at end of file
<dialog-wrap
title="选择奖品"
visible="{{visible}}"
hasMask="{{showDialogMask}}"
onClose="onCloseDialog"
width="738"
>
<view class="probablity-prize-content">
<view class="probablity-prize-content-form">
<form inline="true">
<form-item style="width:100%" size="large" class="probablity-prize-content-formItem" label="奖品类型" required>
<view class="probablity-prize-content-formitem-choosePrize-wrap">
<select onChange="onPrizeTypeChange" defaultValue="{{isEdit ? prizeDialogData.record.type : prizeInitData.type}}">
<option value="1">优惠券</option>
<option value="3">实物</option>
<option value="2">积分</option>
</select>
</view>
</form-item>
<form-item a:if="{{prizeInitData.type == EQUITY_TYPE}}" validateState="{{choosePrizeTips.status}}" style="width:100%" size="large" help="{{choosePrizeTips.content}}" class="probablity-prize-content-formItem probablity-prize-content-formItem-choosePrize" label="选择奖品" required>
<view class="probablity-prize-content-formitem-choosePrize-wrap">
<input a:if="{{prizeInitData.name}}" disabled="true" class="probablity-prize-content-input" style="margin-right:10px" onChange="changeInput" maxLength="10" value="{{prizeInitData.name}}" hasLimitHint="true" name="活动名称" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.name : prizeInitData.name}}" placeholder="请选择奖品"/>
<view class="probablity-prize-content-formitem-goequity" onTap="navigateToPlugin" type="primary">{{prizeInitData.ename ? '重新选择' : '选择奖品'}}</view>
</view>
</form-item>
<form-item
style="width:100%"
a:if="{{prizeInitData.type == OBJECT_TYPE || prizeInitData.type == CREDITS_TYPE}}"
size="large"
class="probablity-prize-content-formItem"
label="奖品名称"
validateState="{{prizeNameTips.status}}" help="{{prizeNameTips.content}}"
required>
<input class="probablity-prize-content-input" data-name="name" onChange="onChangePrizeValue" maxLength="10" value="{{prizeInitData.name}}" hasLimitHint="true" name="奖品名称" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.name : prizeInitData.name}}" placeholder="请输入奖品名称"/>
</form-item>
<form-item size="large" required class="probablity-prize-content-formItem" label="奖品图片" validateState="{{imageTips.status}}" help="{{imageTips.content}}">
<view class="probablity-prize-content-imageUpload-wrap">
<image style="width:90px;height:90px;border:1px solid #ccc;margin-right:10px" src="{{prizeInitData.image}}"></image>
<view class="probablity-prize-content-imageUpload-btn">
<view>奖品图片</view>
<text>尺寸为{{imageLimit[0]}}px * {{imageLimit[1]}}px,格式为jpg/png</text>
<view></view>
<button onTap="uploadImage" type="primary">上传图片</button>
</view>
</view>
</form-item>
<form-item
a:if="{{(prizeInitData.type == OBJECT_TYPE || prizeInitData.type == EQUITY_TYPE) && type === 'probablity'}}"
style="width:100%"
size="large"
class="probablity-prize-content-formItem"
label="库存类型"
required>
<radio-group value="{{prizeInitData.limitStock}}" onChange="onLimitStockChange">
<radio value="{{0}}">不限库存</radio>
<radio value="{{1}}">限制库存</radio>
</radio-group>
</form-item>
<form-item
style="width:100%"
a:if="{{(prizeInitData.type == OBJECT_TYPE || prizeInitData.type == EQUITY_TYPE) && prizeInitData.limitStock && type === 'probablity'}}"
size="large"
class="probablity-prize-content-formItem"
label="奖品库存"
validateState="{{prizeNumberTips.status}}" help="{{prizeNumberTips.content}}"
required>
<input
type="number"
maxLength="5"
class="probablity-prize-content-input"
data-name="stock"
onChange="onChangePrizeValue"
addonTextAfter="已发放库存{{(prizeDialogEdit ? prizeDialogData.record.useStock : prizeInitData.useStock) || 0}}件"
type="number"
value="{{prizeInitData.stock}}"
name="奖品库存"
defaultValue="{{prizeDialogEdit ? prizeDialogData.record.stock : prizeInitData.stock}}"
placeholder="请输入奖品库存"/>
</form-item>
<form-item
a:if="{{prizeInitData.type == CREDITS_TYPE}}"
size="large"
class="probablity-prize-content-formItem"
label="积分价值"
style="width:100%"
validateState="{{creditsValueTips.status}}" help="{{creditsValueTips.content}}"
required>
<input type="number" class="probablity-prize-content-input" data-name="credits" onChange="onChangePrizeValue" type="number" value="{{prizeInitData.credits}}" hasLimitHint="true" name="积分价值" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.credits : prizeInitData.credits}}" placeholder="请输入积分价值"/>
</form-item>
<form-item
a:if="{{type==='rank'}}"
size="large"
class="probablity-prize-content-formItem"
label="领奖名次"
style="width:100%"
validateState="{{rankValueTips.status}}" help="{{rankValueTips.content}}"
required>
<input
type="text"
class="probablity-prize-content-input dialog-rank-input"
data-name="rank"
onChange="onChangePrizeValue"
type="number"
value="{{prizeInitData.rank}}"
hasLimitHint="true"
name="领奖名次"
defaultValue="{{prizeDialogEdit ? prizeDialogData.record.rank : prizeInitData.rank}}"
placeholder='领奖名次, 第5名输入"5", 第5-10名输入"5-10"'/>
</form-item>
<form-item
a:if="{{type==='probablity'}}"
style="width:100%"
size="large"
class="probablity-prize-content-formItem"
label="中奖概率"
validateState="{{probablityTips.status}}"
help="{{probablityTips.content}}"
required>
<input
class="probablity-prize-content-input edit-probablity-input"
type="number"
onChange="onChangePrizeValue"
data-name="probablity"
value="{{prizeInitData.probablity}}"
name="中奖概率"
defaultValue="{{prizeInitData.probablity}}"
placeholder="当前概率不能超过100"/>%
</form-item>
</form>
</view>
<view class="probablity-prize-content-btn">
<button class="probablity-prize-content-btn_confirm" onTap="updatePrize" type="primary">确定</button>
<button onTap="onCloseDialog">取消</button>
</view>
</view>
</dialog-wrap>
\ No newline at end of file
This diff is collapsed.
...@@ -5,5 +5,8 @@ ...@@ -5,5 +5,8 @@
"version": "0.0.12", "version": "0.0.12",
"provider": "3000000002026202" "provider": "3000000002026202"
} }
},
"usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap"
} }
} }
\ No newline at end of file
.rank-dialog-wrap {
}
.other-winner-list {
display: flex;
justify-content: flex-end;
margin: 0 0 20px 0;
}
.now-winner-list {
display: flex;
justify-content: flex-end;
margin: 20px 0;
}
.rank-pagination {
display: flex;
justify-content: flex-end;
margin: 10px 0 0 0;
}
\ No newline at end of file
<dialog-wrap
title="中奖信息"
visible="{{false}}"
onClose="onCloseDialog"
width="800"
>
<view class="rank-dialog-wrap">
<view class="other-winner-list">
<button type="text">导出其它中奖名单</button>
</view>
<tab shape="wrapped">
<tab-item
a:for="{{tabs}}"
title="{{item.tab}}"
key="{{item.key}}"
>
<view class="now-winner-list">
<button type="primary">导出本期中奖名单</button>
</view>
<table dataSource="{{dataSource}}">
<table-column a:for="{{columns}}" title="{{item.title}}" dataIndex="{{item.prop}}"/>
</table>
<view class="rank-pagination">
<text class="rank-pagination-text">共{{pageInfo.total}}条</text>
<pagination shape="arrow-only" hideOnlyOnePage="true" defaultCurrent="1" current="{{pageInfo.pageNo}}" pageSize="{{pageInfo.pageSize}}" onChange="changePagination" pageShowCount="100" total="{{pageInfo.total}}" />
</view>
</tab-item>
</tab>
</view>
</dialog-wrap>
\ No newline at end of file
Component({
mixins: [],
data: {
tabs: [{
tab: '0608-0712',
key: 111
},{
tab: '03308-0712',
key: 43
},{
tab: '064548-0712',
key: 435
},{
tab: '0608-0712',
key: 436545
},{
tab: '0608-0712',
key: 65
},{
tab: '0608-0712',
key: 11561
},{
tab: '0608-0712',
key: 13311
},{
tab: '0608-0712',
key: 145611
},{
tab: '0608-0712',
key: 1178761
}],
dataSource: [],
columns: [
{ title: '排名', prop: 'rank' },
{ title: '用户昵称', prop: 'userNick' },
{ title: '奖品类型', prop: 'type' },
{ title: '奖品名称', prop: 'name' },
{ title: '收货人', prop: 'receiveName' },
{ title: '联系方式', prop: 'phone' },
{ title: '收货地址', prop: 'address' }
],
pageInfo: {
pageNo: 1,
pageSize: 100,
total: 0
}
},
props: {},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {},
});
{
"component": true,
"usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap"
}
}
\ No newline at end of file
.task-day-limit {
margin: 0 0 0 60px;
color: #333;
/* font-size: 13px; */
display: flex;
align-items: center;
}
.task-content-btn {
display: flex;
justify-content: flex-end;
}
.task-content-btn_confirm {
margin-right: 10px;
}
\ No newline at end of file
<dialog-wrap
visible="{{visible}}"
onClose="onCloseDialog"
width="460"
>
<view class="task-dialog-wrap">
<form style="width: 100%" data-name="form" inline="{{true}}">
<form-item label="任务标题">
<input
style="width: 250px"
onChange="onChange"
data-name="title"
defaultValue="{{title}}"
maxLength="{{10}}"
maxlength="{{10}}"
hasLimitHint="{{true}}"
name="title"
placeholder="请输入任务标题"/>
</form-item>
<form-item label="任务类型" style="width:100%;">
<radio-group size="small" value="{{taskRateType}}" onChange="onTaskRateTypeChange">
<radio size="small" value="{{1}}">永久一次</radio>
<radio size="small" value="{{2}}" >每天限次</radio>
<radio size="small" value="{{3}}" >不限次</radio>
</radio-group>
</form-item>
<form-item a:if="{{taskRateType === 2}}">
<view class="task-day-limit">
<view>每天最多完成</view>
<view style="margin: 0 6px;"><select value="{{times}}" onChange="onTimesChange" dataSource="{{dataSource}}"/>
</view>次任务</view>
</form-item>
<form-item label="跳转链接" a:if="{{!noLink}}">
<input style="width: 250px" onChange="onChange" data-name="link" defaultValue="{{link}}" name="link" placeholder="请输入跳转链接"/>
</form-item>
<form-item label="任务奖励">
<input onChange="onChange" data-name="value" defaultValue="{{value}}" name="value" addonTextAfter="{{unit}}"/>
</form-item>
</form>
<view class="task-content-btn">
<button class="task-content-btn_confirm" onTap="onSaveTask" type="primary">保存</button>
<button onTap="onCloseDialog">取消</button>
</view>
</view>
</dialog-wrap>
\ No newline at end of file
const { passUrlList } = require('../../../cmpUtils/const');
Component({
mixins: [],
data: {
dataSource:[
{ label: 1, value: 1 },
{ label: 2, value: 2 },
{ label: 3, value: 3 },
{ label: 4, value: 4 },
{ label: 5, value:5 },
{ label: 6, value:6 },
{ label: 7, value:7 },
{ label: 8, value:8 },
{ label: 9, value:9 },
{ label: 10, value:10 }
],
taskRateType: 1,
times: 1,
title: '',
link: '',
value: ''
},
props: {
visible: false,
noLink: false,
type: '',
unit: '',
onClose: () => {},
onUpdate: () => {}
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onCloseDialog() {
this.props.onClose();
},
onTimesChange(e) {
const { value } = e.detail;
this.setData({
times: value
})
},
onTaskRateTypeChange(e) {
const { value } = e.detail;
this.setData({
taskRateType: value
})
},
onChange(e) {
const { value } = e.detail;
const { name } = e.target.dataset;
this.setData({
[name]: value
})
},
validateLink(link) {
if(!link) return false;
return true;
},
onSaveTask() {
const { title, link, value, taskRateType, times } = this.data;
if(!title) {
my.showToast({
type: 'fail',
content: '请输入任务标题'
})
return;
}
if(!this.props.noLink && !this.validateLink(link)) {
my.showToast({
type: 'fail',
content: '请输入正确的链接地址'
})
return;
}
if(!value) {
my.showToast({
type: 'fail',
content: '请输入正确的任务奖励'
})
return;
}
this.props.onUpdate && this.props.onUpdate({ title, link, value, taskRateType, times, type: this.props.type })
this.onCloseDialog();
}
},
});
{
"component": true,
"usingComponents": {
"dialog-wrap": "../../basic/dialiog-wrap/dialiog-wrap"
}
}
\ No newline at end of file
.tb-cfg-input {
display: flex;
align-items: center;
font-size: 13px;
color: #333;
}
.tb-cfg-input_prev {
margin-right: 8px;
}
.tb-cfg-input_append {
margin-left: 8px;
}
<view class="tb-cfg-input">
<view class="tb-cfg-input_prev">{{textBefore}}</view>
<input style="width: 60px;" value="{{value}}" onChange="onChange" placeholder="{{placeholder}}" maxlength="{{maxlength}}"/>
<view class="tb-cfg-input_append">{{textAfter}}</view>
</view>
\ No newline at end of file
Component({
data: {
maxlength: ''
},
props: {
textBefore: '',
textAfter: '',
validateRange: [],
value: '',
placeholder: '',
onChange: () => {}
},
didMount() {
this.formatMaxlength();
},
didUpdate() {},
methods: {
onChange(e) {
this.props.onChange && this.props.onChange(e);
},
// 根据校验限制输入长度
formatMaxlength() {
const { validateRange } = this.props;
if(!validateRange.length) return;
let maxLimit = validateRange[1];
if(maxLimit) {
this.setData({
maxlength: (maxLimit+'').length
})
}
}
},
});
{
"component": true
}
\ No newline at end of file
.tb-imageUpload-wrap{
display:flex;
padding-top:10px;
box-sizing:border-box;
}
.tb-imageUpload-btn{
display:flex;
flex-direction:column;
justify-content:space-around;
}
.tb-imageUpload-btn text{
font-size:12px;
margin-bottom:5px;
color:#666666;
}
.tb-imageUpload-btn view{
margin-bottom:5px;
color:#666666
}
\ No newline at end of file
<view class="tb-imageUpload-wrap">
<image style="width:90px;height:90px;border:1px solid #ccc;margin-right:10px" src="{{prizeInitData.image}}"></image>
<view class="tb-imageUpload-btn">
<view>图片</view>
<text>尺寸为{{imageLimit[0]}}px * {{imageLimit[1]}}px,格式为jpg/png</text>
<view></view>
<button onTap="uploadImage" type="primary">上传图片</button>
</view>
</view>
\ No newline at end of file
import { chooseImage, getImageInfo, validateRangeNumber } from "/utils";
Component({
mixins: [],
data: {},
props: {
imageLimit: [200, 200],
onSuccess: () => {},
onError: () => {}
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
async uploadImage() {
const { onSuccess, onError } = this.props;
try {
const res = await chooseImage();
if (!res.apFilePaths.length) return;
const { height, width, type, path } = await getImageInfo({
src: res.apFilePaths[0],
});
let imgBool = ~path.indexOf(".png") || ~path.indexOf(".jpg");
if (height !== 300 || width !== 300 || !imgBool) {
onError && onError({height, width, type, path })
}
const { url } = await cloud.file.uploadFile({
filePath: res.apFilePaths[0],
fileType: "image",
fileName: path.split("/").pop(),
});
onSuccess && onSuccess(url)
} catch (error) {
console.error(error);
}
},
},
});
{
"component": true
}
\ No newline at end of file
.tb-input-container {
display: inline-block;
position: relative;
}
.tb-question-tips {
display: inline-block;
position: relative;
top: -8px;
left: 6px;
}
\ No newline at end of file
<view class="tb-input-container">
<input
value="{{value}}"
size="{{size}}"
onChange="onChange"
onKeyDown="onKeyDown"
disabled="{{disabled}}"
maxLength="{{maxLength}}"
maxlength="{{maxLength}}"
hasLimitHint="{{hasLimitHint}}"
cutString="{{cutString}}"
readOnly="{{readOnly}}"
trim="{{trim}}"
data-name="{{dataName}}"
placeholder="{{placeholder}}"
onFocus="onFocus"
onBlur="onBlur"
name="{{name}}"
state="{{state}}"
hasClear="{{hasClear}}"
hasBorder="{{hasBorder}}"
onPressEnter="onPressEnter"
hint="{{hint}}"
addonTextBefore="{{addonTextBefore}}"
addonTextAfter="{{addonTextAfter}}"
autoFocus="{{autoFocus}}"
htmlType="{{htmlType}}"
style="width: {{width}}"
/>
<view class="tb-question-tips">
<question-tips a:if="{{tips}}" tips="{{tips}}"/>
</view>
</view>
\ No newline at end of file
Component({
mixins: [],
data: {
balloonVisible: false
},
props: {
value: '',
size: 'medium',
disabled: false,
maxLength: null,
hasLimitHint: false,
cutString: false,
readOnly: false,
tips: false,
trim: false,
placeholder: '',
name: '',
state: '',
hasClear: '',
hasBorder: true,
hint: '',
addonTextBefore: '',
addonTextAfter: '',
autoFocus: '',
htmlType: '',
width: '',
tipsAlign: 't',
dataName: '',
onChange: () => {},
onKeyDown: () => {},
onFocus: () => {},
onBlur: () => {},
onPressEnter: () => {},
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onChange(e) {
this.props.onChange && this.props.onChange(e);
},
onKeyDown(e) {
this.props.onKeyDown && this.props.onKeyDown(e);
},
onFocus(e) {
this.props.onFocus && this.props.onFocus(e);
},
onBlur(e) {
this.props.onBlur && this.props.onBlur(e);
},
onPressEnter(e) {
this.props.onPressEnter && this.props.onPressEnter(e);
},
setBalloonVisible() {
this.setData({
balloonVisible: true
})
},
setBalloonVisibleFalse() {
this.setData({
balloonVisible: false
})
}
},
});
{
"component": true,
"usingComponents": {
"question-tips": "/components/basic/question-tips/question-tips"
}
}
\ No newline at end of file
.tb-label {
font-size: 16px;
margin-bottom: 20px;
font-weight: 600;
padding-left: 26px;
}
<view class="tb-label">
{{title}}
</view>
\ No newline at end of file
Component({
props: {
title: ''
}
});
{
"component": true
}
\ No newline at end of file
.tb-picker-question-tips {
display: inline-block;
position: relative;
top: -8px;
left: 6px;
}
.error-tips {
color: red;
font-size: 12px;
}
\ No newline at end of file
<view class="className">
<range-picker
style="width: 320px"
onVisibleChange="dialogChange"
hasClear="true"
value="{{innerTimeRange}}"
data-time="{{innerTimeRange}}"
onChange="pickerChange"
disabled="{{disabled}}"
show-time="{{ format: 'HH:mm' }}"
state="{{state}}"
help="{{errorTips}}"
/>
<view class="tb-picker-question-tips">
<question-tips a:if="{{tips}}" tips="{{tips}}"/>
</view>
</view>
\ No newline at end of file
import dayjs from 'dayjs';
import { getMillSeconsByDays } from '../../../cmpUtils/time';
Component({
mixins: [],
data: {
innerTimeRange: [],
state: '',
errorTips: ''
},
props: {
timeRange: [],
// 用于活动开始后,不可更改开始时间的备份
originalStartTime: '',
disabled: false,
onChange: () => {},
disableStartTime: false
},
didMount() {
this.initTime();
},
didUpdate(prevProps) {
this.changeTime(prevProps, this.props)
},
didUnmount() {},
methods: {
// 初始化时间, 默认开始时间为当前时间后的10分钟 结束时间为7天之后
initTime() {
const { timeRange } = this.props;
const nowTime = new Date().getTime();
const sevenDays = getMillSeconsByDays(7);
const tenMinutes = 600000;
let defaultStartTime = timeRange[0];
let defaultEndTime = timeRange[1];
// 当前时间 + 10分钟
let startNow = dayjs(nowTime + tenMinutes).format("YYYY-MM-DD HH:mm:ss");
// 开始时间 + 7天
let endNow = dayjs(nowTime + tenMinutes + sevenDays).format("YYYY-MM-DD HH:mm:ss");
// 配置了初始时间,则使用初始时间
if(defaultStartTime) {
startNow = defaultStartTime;
}
defaultEndTime && (endNow = defaultEndTime);
this.setData({
innerTimeRange: [ startNow, endNow ]
})
this.confrimChangeTime([new Date(startNow).getTime(), new Date(endNow).getTime()])
},
// defaultStartTime, defaultEndTime props变化
changeTime(prevProps, currentProps) {
let prevStartTime = prevProps.timeRange[0];
let currentStartTime = currentProps.timeRange[0];
let prevEndTime = prevProps.timeRange[1];
let currentEndTime = currentProps.timeRange[1];
const isTimeChange = currentStartTime !== prevStartTime
|| currentEndTime !== prevEndTime;
if(isTimeChange) {
this.setData({
innerTimeRange: [
dayjs(currentStartTime).format("YYYY-MM-DD HH:mm:ss"),
dayjs(currentEndTime).format("YYYY-MM-DD HH:mm:ss")
]
})
}
},
pickerChange(e) {
const [startTime, endTime] = e.detail.value;
const innerTimeRange = [ startTime || '', endTime || '' ];
if(!startTime && !endTime) {
this.confrimChangeTime(['', ''])
}
this.setData({
innerTimeRange
})
},
// 确认时间
checkoutTime(startTime, endTime) {
const { disableStartTime, originalStartTime } = this.props;
const isStart = originalStartTime < Date.now();
// 编辑活动时,如果活动已经开始, 开始时间不能编辑
if (disableStartTime && isStart) {
this.confrimChangeTime([dayjs(originalStartTime).format("YYYY-MM-DD HH:mm:ss"), endTime])
startTime = originalStartTime
}
let timeHasSame = new Date(endTime).getTime() === new Date(startTime).getTime()
let timeIsCantChoose = new Date().getTime() > new Date(startTime).getTime()
if (timeHasSame || timeIsCantChoose) {
let errTips = '';
if (timeIsCantChoose && !disableStartTime) {
errTips = `活动开始时间不能小于当前时间`
console.log('error', '活动开始时间不能小于当前时间')
}
if (timeHasSame) {
errTips = `开始时间不能等于结束时间`
console.log('error', '开始时间不能等于结束时间')
}
this.confrimChangeTime([startTime, endTime], errTips)
} else {
this.setData({
state: '',
errorTips: ''
})
this.confrimChangeTime([startTime, endTime])
}
},
// 时间选择框状态变化
dialogChange(e) {
const [startTime, endTime] = e.target.dataset.time
const {
value
} = e.detail
if (!value) {
this.checkoutTime(startTime, endTime)
}
},
confrimChangeTime([startTime, endTime], error) {
this.props.onChange && this.props.onChange([ new Date(startTime).getTime() || '', new Date(endTime).getTime() || ''], error);
}
}
});
{
"component": true,
"usingComponents": {
"question-tips": "/components/basic/question-tips/question-tips"
}
}
\ No newline at end of file
.tb-rule-title {
font-size: 12px;
color: #333;
}
\ No newline at end of file
<view class="tb-rule-container">
<view class="tb-rule-title">用于展示在活动页的规则说明</view>
<textarea
style="width:400px;margin: 10px 0 0 0"
value="{{rule}}"
onChange="onChange"
maxLength="2000"
hasLimitHint="{{true}}"
>
</textarea>
</view>
\ No newline at end of file
Component({
data: {},
props: {
onChange: () => {}
},
didMount() {},
didUpdate() {},
methods: {
onChange(e) {
this.props.onChange && this.props.onChange(e);
},
},
});
{
"component": true
}
\ No newline at end of file
.tb-list-container {
padding: 0 24px;
background-color: #fff;
}
.tb-list-container .next-table-header .next-table-cell {
background-color: #fff;
}
.tb-list-container .next-table-row {
height: 80px;
}
.tb-list-container .next-table-header .next-table-cell-wrapper {
height: 60px;
line-height: 38px;
}
.tb-list-pagination {
margin-top: 20px;
align-items: center;
justify-content: flex-end;
display: flex;
}
.tb-list-edit {
margin-right: 8px;
}
.font-14 {
font-size: 14px;
}
.font-13 {
font-size: 13px;
}
.font-12 {
font-size: 12px;
}
.mb-4 {
margin-bottom: 4px;
}
\ No newline at end of file
<view class="tb-list-container">
<table dataSource="{{dataSource}}" hasBorder="{{false}}" loading="{{isLoadingList}}">
<table-column title="活动名称" >
<view class="font-14" slot-scope="x">
<text>{{x.record.title}}</text>
</view>
</table-column>
<table-column title="活动时间" >
<view class="font-13" slot-scope="x">
<view class="mb-4">起: {{x.record.startTime}}</view>
<view>止: {{x.record.endTime}}</view>
</view>
</table-column>
<table-column title="操作" dataIndex="id" alignHeader="left">
<view slot-scope="x">
<button a:if="{{buttons.includes('edit')}}" class="tb-list-edit" onTap="handleClickEdit" type="primary" text="true" data-x="{{x}}" >编辑活动</button>
<button a:if="{{buttons.includes('export')}}" class="tb-list-edit" type="primary" text="true" data-x="{{x}}" data-type="object" onTap="exportWinnerList">导出实物中奖名单</button>
<button a:if="{{buttons.includes('delete')}}" class="tb-list-edit" type="primary" text="true" data-x="{{x}}" onTap="handleTapDelete">删除</button>
<button a:if="{{buttons.includes('copyLink')}}" class="tb-list-edit" type="primary" text="true" data-x="{{x}}" onTap="onCopyLink">复制活动链接</button>
<button a:if="{{buttons.includes('copyNewActivity')}}" class="tb-list-edit" type="primary" text="true" data-x="{{x}}" onTap="onCreateNewActivity">复制新活动</button>
</view>
</table-column>
</table>
</view>
<view class="tb-list-pagination">
<text class="tb-list-pagination-text">共{{pageInfo.total}}条</text>
<pagination shape="arrow-only" hideOnlyOnePage="true" defaultCurrent="1" current="{{pageInfo.pageNo}}" pageSize="{{pageInfo.pageSize}}" onChange="changePagination" pageShowCount="5" total="{{pageInfo.total}}" />
</view>
<copy-link-dialog visible="{{exportDialogVisible}}" url="{{exportUrl}}" onClose="onCloseExportDialog"/>
<confirm-dialog
visible="{{confirmDialog.visible}}"
content="{{confirmDialog.content}}"
onClose="onCloseConfirmDialog"
onConfirm="onConfirmDelete"
/>
<rank-dialog />
\ No newline at end of file
import dayjs from "dayjs";
import {
getActivityList,
delActivity,
findWinnerInfoList,
uploadDataCreateFile,
createCopyActivity,
} from "/api";
import { appId } from "/config";
import { setClipboard } from "/utils";
Component({
data: {
isLoadingList: false,
exportDialogVisible: false,
exportUrl: '',
dataSource: [],
confirmDialog: {
visible: false,
content: "删除活动后该活动用户参与信息将全部删除,确认删除吗?",
},
pageInfo: {
pageNo: 1,
pgaeSize: 10,
total: 0
},
deleteId: "",
selectedItem: "",
},
props: {
buttons: ['edit', 'export', 'delete', 'copyLink']
},
didMount() {
this.getList();
},
methods: {
/**
*获取活动列表
*
* @param {number} [currentPage=1] 页数
* @param {number} [size=10] 页码尺寸
* @returns {void}
*/
async getList(currentPage = 1, size = 10) {
this.setData({ isLoadingList: true });
try {
const { success, data, message } = await getActivityList({
pageNo: currentPage,
pageSize: size,
});
this.setData({ isLoadingList: false });
if (!success) {
my.showToast({
type: "fail",
content: message,
});
return;
}
const { list, pageNo, pageSize, total } = data;
const timeNow = new Date().getTime();
let formatList = list.map((i) => {
return {
...i,
startTime: dayjs(+i.startTime).format("YYYY-MM-DD HH:mm:ss"),
endTime: dayjs(+i.endTime).format("YYYY-MM-DD HH:mm:ss"),
};
});
this.setData({
dataSource: formatList,
pageInfo: {
pageNo,
pageSize,
total,
},
});
} catch (error) {
this.setData({
isLoadingList: false,
});
}
},
// 复制链接
async onCopyLink(evt) {
const { activityId } = evt.target.dataset.x.record;
let text = `https://m.duanqu.com/?_ariver_appid=${appId}?query=activityId%3D${activityId}`
try {
await setClipboard({
text
});
my.showToast({
type: "success",
content: "复制活动链接成功",
});
} catch (error) {
console.log(error);
}
},
onCloseExportDialog() {
this.setData({
exportDialogVisible: false
})
},
//复制新活动
async onCreateNewActivity(evt) {
const { activityId } = evt.target.dataset.x.record;
let res = await createCopyActivity({ activityId });
if (res.success) {
this.getList();
} else {
my.showToast({
content: res.message,
type: "fail",
});
}
},
// 点击列表删除
handleTapDelete(evt) {
const { activityId } = evt.target.dataset.x.record;
console.log(1)
this.setData({
confirmDialog: Object.assign({}, this.data.confirmDialog, {
visible: true,
}),
deleteId: activityId,
});
},
onCloseConfirmDialog() {
this.setData({
confirmDialog: Object.assign({}, this.data.confirmDialog, {
visible: false,
}),
});
},
onConfirmDelete() {
const activityId = this.data.deleteId;
this.setData({
confirmDialog: Object.assign({}, this.data.confirmDialog, {
visible: false,
}),
});
activityId && this.deleteActivityFromId(activityId);
},
// 删除活动
async deleteActivityFromId(activityId) {
try {
const { success, message } = await delActivity({
activityId
});
if (success) {
this.getList();
} else {
my.showToast({
type: "fail",
content: message,
});
}
} catch (error) {
console.log(error);
}
},
// 导出中奖名单
async exportWinnerList(evt) {
const { activityId } = evt.target.dataset.x.record;
const { type } = evt.target.dataset;
let isObject = type === "object";
my.showLoading({ content: "生成文件中..." });
try {
const { success, data, message } = await uploadDataCreateFile({
activityId,
isObject,
});
my.hideLoading();
if (success) {
await setClipboard({ text: data.url.replace(/amp;/g, "") });
this.setData({
exportDialogVisible: true,
exportUrl: data.url.replace(/amp;/g, "")
})
} else {
my.showToast({
type: "fail",
content: message,
});
}
} catch (error) {
my.hideLoading();
console.log(error, "exportList-error");
}
},
// 编辑
handleClickEdit(evt) {
let { activityId } = evt.target.dataset.x.record;
this.$page.$router.push(`/activity/edit/${activityId}`);
},
changePagination(evt) {
const { value } = evt.detail;
this.getList(value);
},
},
});
{
"component": true,
"usingComponents": {
"copy-link-dialog": "/components/dialog/copy-link-dialog/copy-link-dialog",
"confirm-dialog": "/components/dialog/confirm-dialog/confirm-dialog",
"rank-dialog": "/components/dialog/rank-dialog/rank-dialog"
}
}
\ No newline at end of file
<view>
<overlay
visible="{{showPrize}}"
onRequestClose="onClose"
disableScroll
hasMask="{{showDialogMask}}"
wrapperClassName="overlay"
wrapperStyle="{{{'top':dialogTop + 'px'}}}"
target=".edit-breadcrumb"
canCloseByMask="true"
data-index="0"
>
<view class="modal-content">
<view class="modal-content-title">选择奖品<icon size="small" type="close" onTap="closePrize" style="color: #999999;" /></view>
<view class="modal-content-form">
<form class="edit-content-form" inline="true">
<form-item style="width:100%" size="large" class="edit-content-formItem edit-content-formItem-choosePrize" label="奖品类型" required>
<view class="edit-content-formitem-choosePrize-wrap">
<select onChange="onPrizeTypeChange" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.type : prizeInitData.type}}">
<option value="2">优惠券</option>
<option value="4">实物</option>
<option value="3">积分</option>
</select>
</view>
</form-item>
<form-item
a:if="{{prizeInitData.type == OBJECT_TYPE || prizeInitData.type == CREDITS_TYPE}}"
size="large"
class="edit-content-formItem"
label="奖品名称"
validateState="{{prizeNameTips.status}}" help="{{prizeNameTips.content}}"
required>
<input class="edit-content-input" data-name="name" onChange="onChangePrizeValue" maxLength="10" value="{{prizeInitData.name}}" hasLimitHint="true" name="奖品名称" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.name : prizeInitData.name}}" placeholder="请输入奖品名称"/>
</form-item>
<form-item
a:if="{{prizeInitData.type == OBJECT_TYPE}}"
size="large"
class="edit-content-formItem"
label="奖品库存"
validateState="{{prizeNumberTips.status}}" help="{{prizeNumberTips.content}}"
required>
<input type="number" class="edit-content-input" data-name="restStock" onChange="onChangePrizeValue" type="number" value="{{prizeInitData.restStock}}" hasLimitHint="true" name="奖品库存" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.restStock : prizeInitData.restStock}}" placeholder="请输入奖品库存"/>
</form-item>
<form-item
a:if="{{prizeInitData.type == CREDITS_TYPE}}"
size="large"
class="edit-content-formItem"
label="积分价值"
validateState="{{creditsValueTips.status}}" help="{{creditsValueTips.content}}"
required>
<input type="number" class="edit-content-input" data-name="credits" onChange="onChangePrizeValue" type="number" value="{{prizeInitData.credits}}" hasLimitHint="true" name="积分价值" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.credits : prizeInitData.credits}}" placeholder="请输入积分价值"/>
</form-item>
<form-item a:if="{{prizeInitData.type == EQUITY_TYPE}}" validateState="{{choosePrizeTips.status}}" style="width:100%" size="large" help="{{choosePrizeTips.content}}" class="edit-content-formItem edit-content-formItem-choosePrize" label="选择奖品" required>
<view class="edit-content-formitem-choosePrize-wrap">
<input a:if="{{prizeInitData.name}}" disabled="true" class="edit-content-input" style="margin-right:10px" onChange="changeInput" maxLength="10" value="{{prizeInitData.name}}" hasLimitHint="true" name="活动名称" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.name : prizeInitData.name}}" placeholder="请选择奖品"/>
<view class="edit-content-formitem-goequity" onTap="navigateToPlugin" type="primary">{{prizeInitData.ename ? '重新选择' : '选择奖品'}}</view>
</view>
</form-item>
<form-item size="large" required class="edit-content-formItem" label="奖品图片" validateState="{{imageTips.status}}" help="{{imageTips.content}}">
<view class="modal-content-imageUpload-wrap">
<image style="width:90px;height:90px;border:1px solid #ccc;margin-right:10px" src="{{prizeInitData.image}}"></image>
<view class="modal-content-imageUpload-btn">
<view>奖品图片</view>
<text>尺寸为300px * 300px,格式为jpg/png</text>
<view></view>
<button onTap="uploadImage" type="primary">上传图片</button>
</view>
</view>
</form-item>
<form-item size="large" class="edit-content-formItem" label="中奖概率" validateState="{{probablityTips.status}}" help="{{probablityTips.content}}" required>
<input
class="edit-content-input edit-probablity-input" type="number" onChange="onChangePrizeValue" data-name="probablity" value="{{prizeInitData.probablity}}" name="中奖概率" defaultValue="{{prizeInitData.probablity}}" placeholder="当前概率不能超过100"/>%
</form-item>
<!-- <form-item size="large" class="edit-content-formItem" label="奖品库存" required>
<input disabled="true" class="edit-content-input" onChange="changeInput" maxLength="10" value="{{prizeInitData.name}}" hasLimitHint="true" name="活动名称" defaultValue="{{prizeDialogEdit ? prizeDialogData.record.name : prizeInitData.name}}" placeholder="请输入奖品库存"/>
</form-item> -->
</form>
</view>
<view class="modal-content-btn">
<button onTap="updatePrize" type="primary">确定</button>
<button onTap="closePrize">取消</button>
</view>
</view>
</overlay>
</view>
\ No newline at end of file
const {
cloud
} = getApp()
const {
function: fc
} = cloud
const plugin = requirePlugin('myPlugin')
import {
bizCode
} from '../../config';
import {
queryBenefitByEname
} from '../../api';
import { chooseImage, getImageInfo, validateRangeNumber } from '/utils';
const EQUITY_TYPE = 2;
const CREDITS_TYPE = 3;
const OBJECT_TYPE = 4;
const THANKS_TYPE = 5;
Component({
mixins: [],
data: {
EQUITY_TYPE,
CREDITS_TYPE,
OBJECT_TYPE,
THANKS_TYPE,
showDialogMask: true,
dialogTop: '',
rankTips: {
status: 'success',
content: ''
},
imageTips: {
status: 'success',
content: ''
},
probablityTips: {
status: 'success',
content: ''
},
prizeNameTips: {
status: 'success',
content: ''
},
prizeNumberTips: {
status: 'success',
content: ''
},
creditsValueTips: {
status: 'success',
content: ''
},
prizeInitData: {
ename: '',
id: '',
restStock: '',
activityOutId: '',
type: 2,
image: '',
credits: '',
probablity: '',
name: ''
}
},
props: {
prizeDialogData: {
index: '',
record: {}
},
activityOutId: '',
prizeDialogEdit: false,
showPrize: false,
hasEditPrize: false,
datasource: [],
onCloseDialog: function () {},
onUpdateLevel: function () {},
onUpdateHasChange: function () {},
},
didMount() {
this.initPosition()
let that = this
const bridge = {
bizCode, //此处输入想配置的商家应用appID
//这个方法用于获取插件中用户选择的奖池enname
async getCheckBenefitID({ ename, poolID }) {
that.setData({
prizeInitData: {
...that.data.prizeInitData,
ename
}
})
my.showToast({
type: 'success',
content: '已选择权益奖品'
})
const { success, data, message } = await queryBenefitByEname({ ename })
if (success) {
const { benefitName, rightTypeId, startTime, endTime, restStock } = data[0];
that.setData({
prizeInitData: {
...that.data.prizeInitData,
name: benefitName,
type: rightTypeId,
startTime,
endTime,
restStock
}
})
that.$page.data.backPageTimeOut = setTimeout(() => {
my.navigateBack({
delta: 1
})
}, 6000)
} else {
my.showToast({
type: 'fail',
content: message
})
}
}
}
this.resetPrizeInit()
plugin.setBridge(bridge)
},
methods: {
initPosition() {
const {
scrollTop
} = this.$page.data
this.setData({
dialogTop: scrollTop * 2
})
},
onPrizeTypeChange(e) {
let value = e.detail.value;
this.setData({
prizeInitData: {
...this.data.prizeInitData,
type: value
}
})
},
navigateToPlugin() {
clearTimeout(this.$page.data.backPageTimeOut)
my.navigateTo({
url: 'plugin://myPlugin/orightindex-page'
})
},
resetPrizeInit() {
if (this.props.prizeDialogEdit) {
const {
rank,
...rest
} = this.props.prizeDialogData.record
this.setData({
prizeInitData: {
...rest
}
})
}
},
async uploadImage() {
try {
this.setData({
showDialogMask: false
})
const res = await chooseImage();
if (!res.apFilePaths.length) return
const {
height,
width,
type,
path
} = await getImageInfo({
src: res.apFilePaths[0]
});
let imgBool = ~path.indexOf('.png') || ~path.indexOf('.jpg')
if (height !== 300 || width !== 300 || !imgBool) {
this.showItemTips('imageTips', 'error', '请按要求上传图片');
} else {
this.showItemTips('imageTips', 'success', '');
}
const {
url
} = await cloud.file.uploadFile({
filePath: res.apFilePaths[0],
fileType: 'image',
fileName: path.split('/').pop()
})
this.setData({
prizeInitData: {
...this.data.prizeInitData,
image: url
}
})
} catch (error) {
this.setData({
showDialogMask: true
})
console.error(error)
}
},
onChangePrizeValue(e) {
const key = e.target.dataset.name;
const value = e.detail.value;
this.setData({
prizeInitData: {
...this.data.prizeInitData,
[key]: value
}
})
},
changeInput(e) {
this.setData({
prizeInitData: {
...this.data.prizeInitData,
name: e.detail.value
}
})
},
updatePrize() {
const {
name,
ename,
image,
type,
startTime,
probablity,
restStock,
credits,
endTime
} = this.data.prizeInitData
const {
imageTips
} = this.data;
let probablityRexp = /^\d+(\.\d{1,2})?$/;
if (!probablityRexp.test(probablity) || probablity > 100) {
this.showItemTips('probablityTips', 'error', '奖品概率必须在0-100%之间且最多支持两位小数');
} else {
this.showItemTips('probablityTips', 'success', '');
}
const {
LUKCY_POCKET_TYPE,
COUPON_TYPE,
CREDITS_TYPE,
OBJECT_TYPE,
THANKS_TYPE,
} = this.data;
if (type === LUKCY_POCKET_TYPE && !ename) {
my.showToast({
type: 'fail',
content: '优惠券配置错误, 请重新配置'
});
return;
}
if((type == OBJECT_TYPE || type == CREDITS_TYPE) &&!name) {
this.showItemTips('prizeNameTips', 'error', '请输入奖品名称')
} else {
this.showItemTips('prizeNameTips', 'success', '')
}
if ((type == OBJECT_TYPE) && !validateRangeNumber(restStock, [0, 9999])) {
this.showItemTips('prizeNumberTips', 'error', '奖品库存为0-9999之间的整数');
} else {
this.showItemTips('prizeNumberTips', 'success', '');
}
if (type == CREDITS_TYPE && !validateRangeNumber(credits, [0, 999])) {
this.showItemTips('creditsValueTips', 'error', '请输入积分价值为0-999的整数');
} else {
this.showItemTips('creditsValueTips', 'success', '');
}
const { probablityTips, prizeNumberTips, creditsValueTips } = this.data;
const isImagePass = image && imageTips.status !== 'error';
const isEquietyPass = (type == EQUITY_TYPE) && name && isImagePass && ename && probablityTips.status !== 'error';
const isObjectPass = type == OBJECT_TYPE && name && restStock && isImagePass && probablityTips.status !== 'error' && prizeNumberTips.status !== 'error';
const isCreditsPass = type == CREDITS_TYPE && name && credits && isImagePass && probablityTips.status !== 'error' && creditsValueTips.status !== 'error';
if (
isEquietyPass || isObjectPass || isCreditsPass
) {
this.props.onUpdateLevel({
image,
name,
ename,
type,
probablity,
restStock,
credits
},
this.props.prizeDialogData.index
)
if (this.props.activityOutId) {
this.props.onUpdateHasChange(true, this.props.prizeDialogData.index);
}
this.closePrize();
} else {
my.showToast({
type: 'fail',
content: '请完整填写奖品信息'
})
}
},
showItemTips(type, status, content) {
this.setData({
[type]: {
status,
content
}
})
},
closePrize() {
this.setData({
showDialogMask: true
})
this.props.onCloseDialog('prize')
}
}
})
\ No newline at end of file
.tb-rate-table-container {
width: 800px;
}
.tb-rate-table-add {
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
height: 50px;
background: #fff;
color: #3386F1;
}
.tb-rate-table-add_icon {
width: 12px;
height: 12px;
border: 1px solid #3386F1;
border-radius: 50%;
color: #3386F1;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.tb-rate-table-operate {
color: #3386F1;
font-size: 12px;
margin: 0 4px 0 0;
}
.tb-rate-table-prize-image {
display: flex;
align-items: center;
}
.edit-content-formItem-addTableList {
height: 54px;
/* width: 600px; */
line-height: 54px;
color: #3386F1;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
}
.tb-rate-table-add_disabled {
height: 54px;
line-height: 54px;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
color: #D7DBE0;
}
.tb-rate-table-add_disabled .tb-rate-table-add_icon {
color: #D7DBE0;
border: 1px solid #D7DBE0;
}
/* 表格样式覆盖 */
.tb-rate-table .next-table-header .next-table-cell-wrapper {
height: 50px;
line-height: 28px;
}
/* 表格样式覆盖 */
\ No newline at end of file
<view class="tb-rate-table-container" style="border: 1px solid #ddd;border-bottom:none;margin: 10px 0 0 0;">
<table dataSource="{{prizeInfoList}}"hasBorder="{{false}}" class="tb-rate-table">
<!-- <table-column title="排序" dataIndex="_sort">
<view slot-scope="x">
<view>
<text a:if="{{x.index !== 0}}" data-idx="{{x.index}}" onTap="up">⬆️</text>
<text a:if="{{x.index + 1 !== prizeInfoList.length}}" data-idx="{{x.index}}" onTap="down">⬇️</text>
</view>
</view>
</table-column> -->
<table-column title="序号" dataIndex="_index">
<view slot-scope="x">{{x.index + 1}}</view>
</table-column>
<table-column title="奖品信息" dataIndex="image">
<view class="tb-rate-table-prize-image" slot-scope="x">
<view a:if="{{x.value}}">
<image style="width:42px;height:42px;margin: 0 6px 0 0" src="{{x.value}}"></image>
</view>
<view>{{x.record.name}} </view>
</view>
</table-column>
<table-column title="奖品数量(件)" dataIndex="stock">
<view slot-scope="x">{{x.value || '-'}}</view>
</table-column>
<table-column title="中奖概率(%)" dataIndex="probablity">
<view slot-scope="x">{{x.value}}</view>
</table-column>
<table-column title="操作">
<text class="tb-rate-table-operate" onTap="onEditPrize" data-x="{{x}}" data-name="edit" slot-scope="x">编辑</text>
<text slot-scope="x" class="tb-rate-table-operate edit-content-formItem-delete" onTap="handleDeleteClick" data-x="{{x}}" slot-scope="x">删除</text>
</table-column>
</table>
<view class="tb-rate-table-add {{prizeInfoList.length >= limit && 'tb-rate-table-add_disabled'}}" onTap="addPrize">
<view class="tb-rate-table-add_icon"><icon size="xxs" type="add"/></view>
添加奖品 ({{prizeInfoList.length}}/{{limit}})
</view>
</view>
<prize-dialog
a:if="{{dialogVisible}}"
visible="{{dialogVisible}}"
isEdit="{{isEdit}}"
prizeDialogData="{{prizeDialogData}}"
onClose="onCloseDialog"
onUpdate="onPrizeUpdate"
onAdd="onPrizeAdd"/>
\ No newline at end of file
Component({
mixins: [],
data: {
prizeInfoList: [{
_id: "2321321",
image: "https://img.alicdn.com/imgextra/i2/742982950/O1CN01zuwaKU1Xf905ZgMno_!!742982950-2-miniprogram.png",
name: "一等奖大礼包",
stock: 34,
probablity: 22,
restStock: 10,
type: 2,
limitStock: 0
}],
dialogVisible: false,
isEdit: false,
prizeDialogData: {}
},
props: {
limit: 20
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
// 删除奖品
handleDeleteClick(e) {
const { index } = e.target.dataset.x;
this.setData({ prizeInfoList: this.data.prizeInfoList.filter(((i, k) => k !== index)) })
},
addPrize() {
const { prizeInfoList } = this.data;
const { limit } = this.props;
if (prizeInfoList.length >= limit) {
my.showToast({ type: 'fail', content: `最多创建${limit}个奖励配置` });
return;
}
this.setData({
dialogVisible: true,
isEdit: false,
prizeDialogData: {}
})
},
onEditPrize(e) {
const { name, x } = e.target.dataset;
console.log(x)
this.setData({
prizeDialogData: x,
isEdit: true,
dialogVisible: true
})
},
onCloseDialog() {
this.setData({ dialogVisible: false })
},
onPrizeUpdate(data, index) {
const updatedData = this.data.prizeInfoList.map((v, i) => {
if(index === i) return {...v, ...data}
return v;
})
this.setData({
prizeInfoList: updatedData
})
},
onPrizeAdd(data) {
const { prizeInfoList } = this.data;
this.setData({
prizeInfoList: [...prizeInfoList, data]
})
}
},
});
{
"component": true,
"usingComponents": {
"prize-dialog": "/components/dialog/prize-dialog/prize-dialog"
}
}
\ No newline at end of file
.rank-form-item {
width: 100%;
}
\ No newline at end of file
<view>
<view>排行榜配置<view>
<form style="margin: 20px 0 0 0" data-name="form" onChange="onChange" inline="true">
<form-item class="rank-form-item" label="周期设置" >
<radio-group dataSource="{{periodConfig}}" onChange="onChangeHeihei" />
</form-item>
<form-item class="rank-form-item" label="最近期时间" >
<tb-range-picker
onChange="onTimeChange"
disableStartTime="{{false}}"
/>
</form-item>
<form-item class="rank-form-item" label="持续期次" >
<radio-group dataSource="{{lastedPeriodConfig}}" onChange="onChangeHeihei" />
</form-item>
<form-item class="rank-form-item" label="剩余期次" >
<input addonTextBefore="包含最近期共" addonTextAfter="期" />
</form-item>
<form-item class="rank-form-item" label="开奖时间" >
<input style="width: 160px" addonTextBefore="榜单截止后第" addonTextAfter="天" />
</form-item>
</view>
\ No newline at end of file
Component({
mixins: [],
data: {
periodConfig: [
{
label: '自然周',
value: 'natural',
},
{
label: '自定义',
value: 'custom',
}
],
lastedPeriodConfig: [
{
label: '自动循环',
value: 'autoLoop',
},
{
label: '自定义',
value: 'custom',
}
]
},
props: {},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onChange(e) {
console.log(e)
}
},
});
{
"component": true,
"usingComponents": {
"tb-range-picker": "/components/form/tb-range-picker/tb-range-picker"
}
}
\ No newline at end of file
.tb-rank-table-container {
width: 600px;
}
.tb-rank-table-add {
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
height: 50px;
background: #fff;
color: #3386F1;
}
.tb-rank-table-add_icon {
width: 12px;
height: 12px;
border: 1px solid #3386F1;
border-radius: 50%;
color: #3386F1;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
}
.tb-rank-table-operate {
color: #3386F1;
font-size: 12px;
margin: 0 4px 0 0;
}
.tb-rank-table-prize-image {
display: flex;
align-items: center;
}
.edit-content-formItem-addTableList {
height: 54px;
/* width: 600px; */
line-height: 54px;
color: #3386F1;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
}
.tb-rank-table-add_disabled {
height: 54px;
line-height: 54px;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
color: #D7DBE0;
}
.tb-rank-table-add_disabled .tb-rank-table-add_icon {
color: #D7DBE0;
border: 1px solid #D7DBE0;
}
/* 表格样式覆盖 */
.tb-rank-table .next-table-header .next-table-cell-wrapper {
height: 50px;
line-height: 28px;
}
/* 表格样式覆盖 */
\ No newline at end of file
<view class="tb-rank-table-container" style="border: 1px solid #ddd;border-bottom:none;margin: 10px 0 0 0;">
<table dataSource="{{prizeInfoList}}"hasBorder="{{false}}" class="tb-rate-table">
<table-column title="名次" dataIndex="rank">
<view slot-scope="x">{{
x.value.split("-").length === 2 ?
(x.value.split("-")[0] !== x.value.split("-")[1]? '第 ' +x.value.split("-")[0]+'-'+x.value.split("-")[1] +' 名':'第 ' + x.value.split("-")[1] +' 名')
:
`第 ${x.value} 名`
}}</view>
</table-column>
<table-column title="奖品信息" dataIndex="image">
<view class="tb-rank-table-prize-image" slot-scope="x">
<view a:if="{{x.record.image}}">
<image style="width:42px;height:42px;margin: 0 6px 0 0" src="{{x.record.image}}"></image>
</view>
<view>{{x.record.name}} </view>
</view>
</table-column>
<table-column title="操作">
<text class="tb-rank-table-operate" onTap="onEditPrize" data-x="{{x}}" data-name="edit" slot-scope="x">编辑</text>
<text slot-scope="x" class="tb-rank-table-operate edit-content-formItem-delete" onTap="handleDeleteClick" data-x="{{x}}" slot-scope="x">删除</text>
</table-column>
</table>
<view class="tb-rank-table-add {{prizeInfoList.length >= limit && 'tb-rank-table-add_disabled'}}" onTap="addPrize">
<view class="tb-rank-table-add_icon"><icon size="xxs" type="add"/></view>
添加奖品 ({{prizeInfoList.length}}/{{limit}})
</view>
</view>
<prize-dialog
a:if="{{dialogVisible}}"
visible="{{dialogVisible}}"
isEdit="{{isEdit}}"
prizeDialogData="{{prizeDialogData}}"
onClose="onCloseDialog"
type="rank"
onUpdate="onPrizeUpdate"
onAdd="onPrizeAdd"/>
\ No newline at end of file
Component({
mixins: [],
data: {
prizeInfoList: [
// {
// _id: "2321321",
// image: "https://img.alicdn.com/imgextra/i2/742982950/O1CN01zuwaKU1Xf905ZgMno_!!742982950-2-miniprogram.png",
// name: "一等奖大礼包",
// type: 2,
// limitStock: 0,
// rank: '1',
// },
// {
// _id: "2321321",
// image: "https://img.alicdn.com/imgextra/i2/742982950/O1CN01zuwaKU1Xf905ZgMno_!!742982950-2-miniprogram.png",
// name: "二等奖大礼包",
// type: 2,
// limitStock: 0,
// rank: '2-2',
// },
// {
// _id: "2321321",
// image: "https://img.alicdn.com/imgextra/i2/742982950/O1CN01zuwaKU1Xf905ZgMno_!!742982950-2-miniprogram.png",
// name: "三等奖大礼包",
// type: 2,
// limitStock: 0,
// rank: '3-3',
// },
// {
// _id: "2321321",
// image: "https://img.alicdn.com/imgextra/i2/742982950/O1CN01zuwaKU1Xf905ZgMno_!!742982950-2-miniprogram.png",
// name: "大礼包",
// type: 2,
// limitStock: 0,
// rank: '4-100',
// }
],
dialogVisible: false,
isEdit: false,
prizeDialogData: {}
},
props: {
limit: 20
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
// 格式化排名信息
formatRank(rank) {
return rank
},
// 删除奖品
handleDeleteClick(e) {
const { index } = e.target.dataset.x;
this.setData({ prizeInfoList: this.data.prizeInfoList.filter(((i, k) => k !== index)) })
},
addPrize() {
const { prizeInfoList } = this.data;
const { limit } = this.props;
if (prizeInfoList.length >= limit) {
my.showToast({ type: 'fail', content: `最多创建${limit}个奖励配置` });
return;
}
this.setData({
dialogVisible: true,
isEdit: false,
prizeDialogData: {}
})
},
onEditPrize(e) {
const { name, x } = e.target.dataset;
console.log(x)
this.setData({
prizeDialogData: x,
isEdit: true,
dialogVisible: true
})
},
onCloseDialog() {
this.setData({ dialogVisible: false })
},
onPrizeUpdate(data, index) {
const updatedData = this.data.prizeInfoList.map((v, i) => {
if(index === i) return {...v, ...data}
return v;
})
this.setData({
prizeInfoList: updatedData
})
},
onPrizeAdd(data) {
const { prizeInfoList } = this.data;
this.setData({
prizeInfoList: [...prizeInfoList, data]
})
}
},
});
{
"component": true,
"usingComponents": {
"prize-dialog": "/components/dialog/prize-dialog/prize-dialog"
}
}
\ No newline at end of file
<view class="url-task">
<button type="primary" text="{{true}}" onTap="onOpenDialog" >{{taskData.title || '编辑任务'}}</button>
<task-dialog visible="{{visible}}" onClose="onClose" onUpdate="onUpdate" unit="炸弹" noLink="{{noLink}}"/>
</view>
Component({
mixins: [],
data: {
visible: false,
taskData: {
title: ''
},
},
props: {
noLink: false
},
didMount() {},
didUpdate() {},
didUnmount() {},
methods: {
onClose() {
this.setData({
visible: false
})
},
onOpenDialog() {
this.setData({
visible: true
})
},
onUpdate(taskData) {
this.setData({
taskData
})
}
},
});
{
"component": true,
"usingComponents": {
"task-dialog": "/components/dialog/task-dialog/task-dialog"
}
}
\ No newline at end of file
export default { export default {
// ams:ams接口,cloud: 云函数 // ams:ams接口,cloud: 云函数
requestType: 'cloud', requestType: "ams",
// app环境 // app环境
env: 'test', env: "online", // online 线上 test 测试
// 线上活动地址 // 默认云函数名称
activityURL: 'https://m.duanqu.com/?_ariver_appid=3000000002099934&nbsv=1.0.3&nbsource=debug&nbsn=TRIAL', cloudFnName: 'backstage',
// 配置的商家应用appID, 权益插件用 // 小程序appId
bizCode: '3000000003498711' appId: "3000000002099934",
}
\ No newline at end of file // 配置应用appID, 权益插件用
bizCode: "3000000003498711",
};
{
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@tbmp/mp-cloud-sdk": {
"version": "1.1.4",
"resolved": "https://registry.npm.taobao.org/@tbmp/mp-cloud-sdk/download/@tbmp/mp-cloud-sdk-1.1.4.tgz",
"integrity": "sha1-DMuRzXfRfFLNbwyxWENoz9/Rqd0="
},
"async-validator": {
"version": "3.3.0",
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-3.3.0.tgz",
"integrity": "sha1-HZIZO75g1tbIskZpLHAF6e0UqO4="
},
"dayjs": {
"version": "1.8.28",
"resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.8.28.tgz",
"integrity": "sha1-N6piAd9IPQiWRctsj2zvbwxNvAc="
},
"miniapp-router": {
"version": "0.1.7",
"resolved": "https://registry.npm.taobao.org/miniapp-router/download/miniapp-router-0.1.7.tgz",
"integrity": "sha1-6SmJV0y7DPEXk9YlCNBBP+FluUg="
},
"moment": {
"version": "2.24.0",
"resolved": "http://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz",
"integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s="
}
}
}
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tbmp/mp-cloud-sdk": "1.1.4", "@tbmp/mp-cloud-sdk": "1.1.4",
"async-validator": "^3.3.0",
"dayjs": "^1.8.28",
"miniapp-router": "^0.1.6", "miniapp-router": "^0.1.6",
"moment": "^2.24.0" "moment": "^2.24.0"
} }
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
color: rgba(153, 153, 153, 1); color: rgba(153, 153, 153, 1);
}
.edit-title_my {
color:rgba(51,134,241,1);
} }
.edit-breadcrumb { .edit-breadcrumb {
...@@ -18,294 +20,18 @@ ...@@ -18,294 +20,18 @@
font-weight: 900; font-weight: 900;
} }
.edit-tip-icon {
width: 14px;
height: 14px;
margin-left: -10px;
}
.edit-content { .edit-content {
padding: 20px; padding: 20px;
} }
.edit-content-form-item {
.edit-content-title { width: 100%;
font-size: 16px;
margin-bottom: 20px;
font-weight: 600;
padding-left: 26px;
}
.edit-content-input {
width: 400px !important;
}
.edit-content-formItem {
font-size: 14px;
font-weight: 400;
position: relative;
}
.edit-content-formItem-add {
width: 42px;
height: 42px;
border: 1px dashed #C9CED4;
display: flex;
justify-content: center;
align-items: center;
}
.edit-content-formItem label {
color: #fff;
}
.edit-content-formItem-qunliao {
margin-top: 15px;
font-size: 14px;
}
.edit-content-formItem-qunliao text {
color: #333333;
}
.edit-content-formItem-qunliao .formItem-qunliao-num {
color: #3386F1;
}
.edit-content-formItem-qunliao .formItem-qunliao-btn {
color: #3386F1;
margin-left: 10px;
}
.edit-content-formItem-addTableList {
height: 54px;
/* width: 600px; */
line-height: 54px;
color: #3386F1;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
}
.edit-content-formItem-addTableList-notAvailable {
height: 54px;
width: 450px;
line-height: 54px;
border-left: 1px solid #D7DBE0;
border-bottom: 1px solid #D7DBE0;
border-right: 1px solid #D7DBE0;
color: #D7DBE0;
}
.edit-content-specialUrl {
color: #000 !important;
margin-right: 10px;
}
.edit-content-formItem-addTableList Icon {
margin: 0 10px;
}
.edit-content-formItem-image {
display: flex;
align-items: center;
}
.edit-content-formItem-image image {
margin-right: 5px;
}
.xunbao-tips {
width:14px;
height:14px;
display: inline-block;
position: relative;
top: 2px;
left: 4px;
background: url(//yun.duiba.com.cn/activity/mini-taobao/question.png) center no-repeat;
background-size: 100% 100%;
}
.xunbao-required {
color: #F23C3C;
font-size: 12px;
padding-right: 4px;
}
.edit-content-formItem-edit {
color: #3386F1;
}
.edit-content-formItem-delete {
margin-left: 10px;
}
.edit-content-formItem-checkbox {
margin-left: 15px;
}
.checkbox-content {
margin-left: 80px;
background-color: #F7F8FA;
padding: 20px;
}
.checkbox-content view {
margin-bottom: 10px;
}
.checkbox-content view text {
color: #3386F1;
}
.checkbox-content view .has-choose-baby {
color: #000;
margin-right: 10px;
}
.checkbox-tips {
margin: 10px 100px;
color: red;
font-size: 12px;
}
.edit-content-formItem-nodata {
height: 40px;
line-height: 40px;
display: flex;
}
.edit-content-formItem-nodata text {
color: #3386F1;
margin-left: 5px;
font-size: 14px;
}
.has-choose-baby {
margin: 0 12px 0 0;
}
.has-choose-baby text {
color: #3386F1;
} }
.rule-config-textarea {
margin-left: 100px;
}
.rule-config-textarea Textarea {
width: 400px;
height: 100px;
}
.edit-activity-config-input {
width: 40px;
margin: 4px 0 0 0;
}
.submit-btn { .submit-btn {
margin: 20px 0 0 80px; margin: 20px 0 0 80px;
} }
.submit-btn Button { .submit-btn Button {
margin-left: 20px; margin-left: 20px;
} }
\ No newline at end of file
.edit-activity-config {
display: flex;
align-items: center;
}
.modal-content {
background: #FFFFFF;
width: 738px;
max-height: 600px;
border: 1px solid #D7DBE0;
display: flex;
flex-direction: column;
box-shadow: 0px 6px 8px 0px #aaa;
}
.modal-content-title {
flex-grow: 0;
flex-shrink: 0;
font-size: 16px;
font-weight: 600;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #D7DBE0;
}
.modal-content-btn {
flex-grow: 0;
flex-shrink: 0;
padding: 20px;
display: flex;
justify-content: flex-end;
border-top: 1px solid #D7DBE0;
}
.modal-content-btn Button {
margin-right: 15px;
}
.modal-content-form {
padding: 20px 20px 0px;
}
.modal-content-imageUpload {
width: 100%;
padding-left: 80px;
display: flex;
align-items: center;
margin-bottom: 20px;
}
.modal-content-imageUpload image {
margin-right: 10px;
}
.edit-content-formItem-choosePrize text {
color: #3386F1;
margin: 0 5px;
}
.edit-content-formItem-choosePrize-btn {
margin-left: 15px !important;
}
.overlay {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
right: 0;
bottom: 0;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
}
.task-error-tip {
font-size: 12px;
color: #F23C3C;
margin-left: 24px;
}
.add-prize-wrap {
/* display: inline-block; */
display: inline-flex;
/* display: flex; */
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
border-radius: 50%;
margin:0 8px 0 16px;
}
/* 表格样式覆盖 */
.edit-custom-table .next-table-header .next-table-cell-wrapper {
height: 50px;
line-height: 28px;
}
/* 表格样式覆盖 */
\ No newline at end of file
<view class="edit-container"> <view class="edit-container">
<view class="edit-breadcrumb"> <view class="edit-breadcrumb">
<text class="edit-title" onTap="backToActivityList">我的活动</text><text class="edit-title edit-title-separate">/</text><text class="edit-title">{{activityId ? '编辑' : '新建'}} 「 xxxx 」 活动</text> <text class="edit-title edit-title_my" onTap="backList">我的活动</text>
<text class="edit-title edit-title-separate">/</text>
<text class="edit-title">{{activityId ? '编辑' : '新建'}} 「 店铺漂流记 」 活动</text>
</view> </view>
<view class="edit-content"> <view class="edit-content">
<form class="edit-content-form" inline="true" labelTextAlign="right" size="large" labelCol="{{labelCol}}"> <form class="edit-content-form" inline="true" labelTextAlign="right" labelCol="{{labelCol}}">
<view class="edit-content-title">基础配置</view> <tb-label title="基础配置"/>
<form-item labelTextAlign="right" style="width:100%" validateState="{{timeRangeTipInfo.status}}" help="{{timeRangeTipInfo.content}}" class="edit-content-formItem" label="活动时间" asterisk="{{false}}"> <form-item
<range-picker style="width: 400px" onVisibleChange="dialogChange" hasClear="true" value="{{timeRange}}" data-time="{{timeRange}}" onChange="pickerChange" show-time="{{ format: 'HH:mm' }}" class="block" /> class="edit-content-form-item"
label="活动时间"
validateState="{{formState.timeRange.status}}"
help="{{formState.timeRange.message}}"
asterisk="{{false}}">
<tb-range-picker
timeRange="{{timeRange}}"
originalStartTime="{{originalStartTime}}"
onChange="onTimeChange"
disableStartTime="{{isStart}}"
tips="demo"
/>
</form-item> </form-item>
<form-item
validateState="{{formState.title.status}}"
help="{{formState.title.message}}"
class="edit-content-form-item"
label="活动名称"
asterisk="{{false}}">
<tb-input
placeholder="请输入活动名称"
maxLength="12"
value="{{title}}"
dataName="title"
hasLimitHint="{{true}}"
onChange="onChange"
/>
</form-item>
<form-item
validateState="{{formState.subtitle.status}}"
help="{{formState.subtitle.message}}"
class="edit-content-form-item"
label="活动副标题"
asterisk="{{false}}">
<tb-input
placeholder="请输入活动副标题"
maxLength="16"
value="{{subtitle}}"
dataName="subtitle"
hasLimitHint="{{true}}"
onChange="onChange"
/>
</form-item>
<tb-label title="奖品配置"/>
<form-item
class="edit-content-form-item"
label="奖品配置"
asterisk="{{false}}">
<rank-table/>
</form-item>
<tb-label title="任务配置"/>
<form-item
class="edit-content-form-item"
label="关注店铺"
asterisk="{{false}}">
<tb-config-input
textBefore="用户关注店铺后,获得"
textAfter="次参与机会,每个用户永久一次"
validateRange="{{[1, 99]}}"
value="{{limitValue}}"
onChange="onConfigInputChange",
placeholder="1-99"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="成为会员"
asterisk="{{false}}">
<tb-config-input
textBefore="用户成为会员后,获得"
textAfter="次参与机会,每个用户永久一次"
validateRange="{{[1, 99]}}"
value="{{limitValue}}"
onChange="onConfigInputChange",
placeholder="1-999"
/>
</form-item>
<form-item
class="edit-content-form-item"
label="邀请好友"
asterisk="{{false}}">
<task-config noLink="{{true}}" type="inviteFriends"/>
</form-item>
<form-item
class="edit-content-form-item"
label="浏览指定页面"
asterisk="{{false}}">
<task-config type="jumpLink"/>
</form-item>
<form-item
validateState="{{formState.logoImage.status}}"
help="{{formState.logoImage.message}}"
class="edit-content-form-item"
label="logo图片"
asterisk="{{false}}">
<tb-image-upload/>
</form-item>
<tb-label title="邀请配置"/>
<form-item
validateState="{{formState.commandTitle.status}}"
help="{{formState.commandTitle.message}}"
class="edit-content-form-item"
label="邀请淘口令名称"
asterisk="{{false}}">
<tb-input
placeholder="请输入邀请者淘口令名称"
maxLength="12"
value="{{commandTitle}}"
dataName="commandTitle"
hasLimitHint="{{true}}"
onChange="onChange"
/>
</form-item>
<form-item
validateState="{{formState.beenInvitedText.status}}"
help="{{formState.beenInvitedText.message}}"
class="edit-content-form-item"
label="被邀请者文案"
asterisk="{{false}}">
<tb-input
placeholder="请输入被邀请者文案"
maxLength="12"
value="{{beenInvitedText}}"
dataName="beenInvitedText"
hasLimitHint="{{true}}"
onChange="onChange"
/>
</form-item>
<form-item
validateState="{{formState.commandImg.status}}"
help="{{formState.commandImg.message}}"
class="edit-content-form-item"
label="淘口令图片"
asterisk="{{false}}">
<tb-image-upload/>
</form-item>
<view class="submit-btn">
<button onTap="onSubmit" type="primary">确定</button>
<button>取消</button>
</view>
</form> </form>
<view class="submit-btn" a:if="{{!isEnd}}">
<button onTap="submitActive" type="primary">确定</button>
<button onTap="backToActivityList">取消</button>
</view>
</view>
</view> </view>
\ No newline at end of file
This diff is collapsed.
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"prize-dialog": "/components/prize-dialog/prize-dialog" "tb-label": "/components/form/tb-label/tb-label",
"tb-input": "/components/form/tb-input/tb-input",
"tb-config-input": "/components/form/tb-config-input/tb-config-input",
"tb-range-picker": "/components/form/tb-range-picker/tb-range-picker",
"tb-rule": "/components/form/tb-rule/tb-rule",
"probability-prize-table": "/components/prize/probability-prize-table/probability-prize-table",
"list-table": "/components/list/list-table/list-table",
"rank-config": "/components/rank/rank-config/rank-config",
"rank-table": "/components/rank/rank-table/rank-table",
"task-config": "/components/task/task-config/task-config",
"tb-image-upload": "/components/form/tb-image-upload/tb-image-upload"
} }
} }
\ No newline at end of file
export const descriptor = {
title: {
required: true,
validator: (rule, value) => !!value && value.length <= 12,
message: "请输入正确的活动名称"
},
subtitle: {
required: true,
validator: (rule, value) => !!value && value.length <= 16,
message: "请输入正确的活动副标题"
},
timeRange: {
required: true
}
};
export const formatValidator = descriptor => {
const validators = {}
Object.keys(descriptor).forEach(key => {
validators[key] = {
status: 'success',
message: ''
}
});
return validators
}
\ No newline at end of file
...@@ -2,36 +2,4 @@ ...@@ -2,36 +2,4 @@
<text class="db-title">活动管理</text> <text class="db-title">活动管理</text>
<button type="primary" onTap="tapname">创建活动</button> <button type="primary" onTap="tapname">创建活动</button>
</view> </view>
<view class="list-container"> <list-table/>
<table dataSource="{{dataSource}}" hasBorder="{{false}}" loading="{{isLoadingList}}">
<table-column title="活动名称" >
<view class="font-14" slot-scope="x">
<text>{{x.record.title}}</text>
</view>
</table-column>
<table-column title="活动时间" >
<view class="font-13" slot-scope="x">
<view class="mb-4">起: {{x.record.startTime}}</view>
<view>止: {{x.record.endTime}}</view>
</view>
</table-column>
<table-column title="操作" dataIndex="id" alignHeader="left">
<button class="edit" onTap="handleClickEdit" type="primary" text="true" data-x="{{x}}" slot-scope="x">编辑活动</button>
<button class="edit" type="primary" text="true" data-x="{{x}}" slot-scope="x" onTap="exportWinnerList">导出中奖名单</button>
<button class="edit" type="primary" text="true" data-x="{{x}}" slot-scope="x" onTap="handleTapDelete">删除</button>
<button class="edit" type="primary" text="true" data-x="{{x}}" slot-scope="x" onTap="onCopyLink">复制链接</button>
</table-column>
</table>
</view>
<view class="pagination">
<text class="pagination-text">共{{pageInfo.total}}条</text>
<pagination shape="arrow-only" hideOnlyOnePage="true" defaultCurrent="1" current="{{pageInfo.pageNo}}" pageSize="{{pageInfo.pageSize}}" onChange="changePagination" pageShowCount="5" total="{{pageInfo.total}}" />
</view>
<confirm-dialog
visible="{{confirmDialog.visible}}"
content="{{confirmDialog.content}}"
onClose="onCloseConfirmDialog"
onConfirm="onConfirmDelete"
/>
import moment from 'moment';
import {
getActivityList,
delActivity,
findWinnerInfoList,
sellerSave,
uploadDataCreateFile
} from '/api';
import { activityURL } from '../../../config';
import { activityType } from '../const';
import { setClipboard } from '/utils'
const { cloud } = getApp(); const { cloud } = getApp();
const { function: fc } = cloud; const { function: fc } = cloud;
Component({ Component({
mixins: [],
data: {
confirmDialog: {
visible: false,
content: '删除活动后该活动用户参与信息将全部删除,确认删除吗?'
},
winnerListDialogVisible: false,
winnerList: [],
deleteId: '',
selectedItem: '',
dataSource: [],
pageInfo: {
pageNo: 1,
pageSize: 10,
total: 0
},
isLoadingList: false,
showWinning: false
},
props: {}, props: {},
didMount() {
this.getList();
},
methods: { methods: {
/**
*获取活动列表
*
* @param {number} [currentPage=1] 页数
* @param {number} [size=10] 页码尺寸
* @returns {void}
*/
async getList(currentPage = 1, size = 10) {
this.setData({ isLoadingList: true });
try {
const { success, data, message } = await getActivityList({
pageNo: currentPage,
pageSize: size,
activityType
})
this.setData({ isLoadingList: false })
if (!success) {
my.showToast({
type: 'fail',
content: message
})
return;
}
const { list, pageNo, pageSize, total } = data;
this.setData({
dataSource: list,
pageInfo: {
pageNo,
pageSize,
total
}
})
} catch (error) {
this.setData({
isLoadingList: false
})
}
},
// 导出中奖名单
async exportWinnerList(evt) {
const { activityId } = evt.target.dataset.x.record;
my.showLoading({ content: '生成文件中...' })
try {
const { success, data, message } = await uploadDataCreateFile({
activityId,
activityType
})
my.hideLoading();
if (success) {
await setClipboard({ text: data.url.replace(/amp;/g, '') })
my.showToast({
type: 'success',
content: '中奖名单链接复制成功,请在浏览器中打开下载'
});
} else {
my.showToast({
type: 'fail',
content: message
})
}
} catch (error) {
my.hideLoading();
console.log(error, 'exportList-error');
}
},
// 复制链接
async onCopyLink(evt) {
const { activityId } = evt.target.dataset.x.record;
try {
await setClipboard({
text: `${activityURL}&activityId=${activityId}`
})
my.showToast({
type: 'success',
content: '复制活动链接成功'
})
} catch (error) {
console.log(error)
}
},
onCloseConfirmDialog() {
this.setData({
confirmDialog: Object.assign({},
this.data.confirmDialog, {
visible: false
})
})
},
// 点击列表删除
handleTapDelete(evt) {
const { activityId } = evt.target.dataset.x.record;
this.setData({
confirmDialog: Object.assign({}, this.data.confirmDialog, {
visible: true
}),
deleteId: activityId
})
},
onConfirmDelete() {
const activityId = this.data.deleteId;
this.setData({
confirmDialog: Object.assign({}, this.data.confirmDialog, {
visible: false
})
})
activityId && this.deleteActivityFromId(activityId)
},
// 删除活动
async deleteActivityFromId(activityId) {
try {
const { success, message } = await delActivity({ activityId, activityType });
if (success) {
this.getList()
} else {
my.showToast({
type: 'fail',
content: message
})
}
} catch (error) {
console.log(err)
}
},
// 编辑
handleClickEdit(evt) {
let { activityId } = evt.target.dataset.x.record;
this.$page.$router.push(`/activity/edit/${activityId}`)
},
changePagination(evt) {
const { value } = evt.detail;
this.getList(value)
},
// 创建活动 // 创建活动
tapname() { tapname() {
this.$page.$router.push('/activity/add') this.$page.$router.push("/activity/add");
} },
}, },
}); });
\ No newline at end of file
{ {
"component": true, "component": true,
"usingComponents": { "usingComponents": {
"confirm-dialog": "/components/confirm-dialog/confirm-dialog" "list-table": "/components/list/list-table/list-table"
} }
} }
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
taobao-mini-sdk @ 025197b3
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment