Commit 2a21b58a authored by 秦海涛's avatar 秦海涛

update

parent 79a03b04
......@@ -2,223 +2,18 @@
<view class="edit-breadcrumb">
<text class="edit-title edit-title_my" onTap="backList">我的活动</text>
<text class="edit-title edit-title-separate">/</text>
<text class="edit-title">{{activityId ? '编辑' : '新建'}} 「 店铺漂流记 」 活动</text>
<text class="edit-title">{{activityId ? '编辑' : '新建'}} 「 <%=appName%> 」 活动</text>
</view>
<view class="edit-content">
<form class="edit-content-form" inline="true" labelTextAlign="right" labelCol="{{labelCol}}">
<tb-label title="基础配置"/>
<form-item
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}}"
/>
</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"
tips="活动名称仅在配置后台展示,用于区分活动,不在C端展示"
/>
</form-item>
<form-item
validateState="{{formState.subtitle.status}}"
help="{{formState.subtitle.message}}"
class="edit-content-form-item"
label="活动副标题"
asterisk="{{false}}">
<tb-input
placeholder="漂流寻宝赢取100元现金红包"
maxLength="16"
value="{{subtitle}}"
dataName="subtitle"
hasLimitHint="{{true}}"
onChange="onChange"
tips="活动副标题用于C端游戏首页展示,需与活动奖品相关,用于吸引用户参与"
/>
</form-item>
<tb-label title="奖品配置"/>
<form-item
class="edit-content-form-item"
label="奖品配置"
validateState="{{formState.prizeInfoList.status}}"
help="{{formState.prizeInfoList.message}}"
asterisk="{{false}}">
<rank-table
list="{{prizeInfoList}}"
onChange="onPrizeListChange"
limit="{{11}}"
maxRankLimit="{{100}}"
fixedRank="{{['1', '2', '3']}}"
imageLimit="{{[200, 200]}}"
/>
</form-item>
<tb-label title="任务配置"/>
<form-item
class="edit-content-form-item"
label="成为会员"
validateState="{{formState['taskMap.beMembership'].status}}"
help="{{formState['taskMap.beMembership'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.beMembership.checked}}" data-name="taskMap.beMembership.checked" onChange="onCheckChange"></checkbox>
<tb-config-input
textBefore="获得"
textAfter="体力值"
validateRange="{{[1, 99]}}"
value="{{taskMap.beMembership.value}}"
dataName="taskMap.beMembership.value"
onChange="onTaskInputChange",
placeholder="1-99"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="邀请好友"
validateState="{{formState['taskMap.inviteFriends'].status}}"
help="{{formState['taskMap.inviteFriends'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.inviteFriends.checked}}" data-name="taskMap.inviteFriends.checked" onChange="onCheckChange"></checkbox>
<task-config
unit="体力值"
type="inviteFriends"
taskData="{{taskMap.inviteFriends}}"
dataName="taskMap.inviteFriends"
onUpdate="onTaskChange"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="浏览指定页面"
validateState="{{formState['taskMap.jumpLink'].status}}"
help="{{formState['taskMap.jumpLink'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.jumpLink.checked}}" data-name="taskMap.jumpLink.checked" onChange="onCheckChange"></checkbox>
<task-config
unit="体力值"
type="jumpLink"
hasLink
taskData="{{taskMap.jumpLink}}"
dataName="taskMap.jumpLink"
onUpdate="onTaskChange"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="寻宝屋商品"
validateState="{{formState['taskMap.browseGoods'].status}}"
help="{{formState['taskMap.browseGoods'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.browseGoods.checked}}" disabled="{{true}}"></checkbox>
<items-config itemIds="{{taskMap.browseGoods.itemIds}}" dataName="taskMap.browseGoods.itemIds" onUpdate="onTaskChange"/>
</view>
</form-item>
<form-item
validateState="{{formState.logoImg.status}}"
help="{{formState.logoImg.message}}"
class="edit-content-form-item"
label="logo图片"
asterisk="{{false}}">
<view style="display:flex;">
<tb-image-upload url="{{logoImg}}" dataName="logoImg" onSuccess="onChangeByDataName" imageLimit="{{[200, 90]}}"/>
<question-tips>
<image style="width:200px;height:400px;border:1px solid #ccc;margin-right:10px" src="//yun.duiba.com.cn/20200410/image2020-6-7_18-16-3.png"></image>
</question-tips>
</view>
</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="20"
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="30"
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 url="{{commandImg}}" dataName="commandImg" onSuccess="onChangeByDataName" imageLimit="{{[400, 300]}}"/>
</form-item>
<tb-label title="规则配置"/>
<form-item
validateState="{{formState.rule.status}}"
help="{{formState.rule.message}}"
class="edit-content-form-item"
label="活动规则"
asterisk="{{false}}">
<tb-rule value="{{rule}}" onChange="onRuleChange" generateRuleInfo="{{{title: subtitle, startTime, endTime, prizeInfoList}}}"/>
</form-item>
<% for(var i = 0; i < configList.length; ++i) {%>
<%-configList[i].template%><% } %>
<view class="submit-btn">
<button onTap="onSubmit" type="primary">确定</button>
<button onTap="cancelEdit">取消</button>
<button>取消</button>
</view>
</form>
......
import moment from 'moment'
import schema from 'async-validator';
import { descriptor, formatValidator } from './validate';
import {
descriptor,
formatValidator
} from './validate';
import {
getActivityDetail,
saveActivityInfo,
......@@ -16,57 +19,15 @@ var validator = new schema(descriptor);
Component({
data: {
labelCol: { fixedSpan: 5 },
labelCol: {
fixedSpan: 5
},
id: '',
title: '',
subtitle: '',
startTime: '',
endTime: '',
timeRange: [],
rule: '',
prizeInfoList: [
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "1"
},
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "2"
},
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "3"
}
],
commandTitle: '',
commandImg: '',
logoImg: '',
beenInvitedText: '',
taskList:[
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
taskList: [
// {
// type: "beMembership",//会员
// value: 20,//完成任务获得值
......@@ -126,20 +87,20 @@ Component({
],
taskMap: {
// attentionStore: {
// value: '',
// },
attentionStore: {
value: '',
},
beMembership: {
value:'',
value: '',
checked: false
},
// sign: {
// value: ''
// },
// exchangeCredits: {
// value: '',
// times: '',
// },
sign: {
value: ''
},
exchangeCredits: {
value: '',
times: '',
},
inviteFriends: {
title: '', // 任务标题
taskRateType: 1, // 任务频率类型
......@@ -156,17 +117,17 @@ Component({
itemIds: '',
checked: true
},
// collectGoods: {
// title: "",
// taskRateType: 1,
// times: 3,
// value: '90',
// itemIds: "",
// },
collectGoods: {
title: "",
taskRateType: 1,
times: 3,
value: '90',
itemIds: "",
},
jumpLink: {
title: "",
taskRateType: 3,
link: "",//跳转链接
link: "", //跳转链接
times: 3,
value: '',
checked: false
......@@ -181,7 +142,9 @@ Component({
},
props: {},
didMount() {
const { id } = this.$page.$router.params
const {
id
} = this.$page.$router.params
if (id) {
this.getActivityInfo(id)
}
......@@ -190,13 +153,22 @@ Component({
// 获取id活动信息
async getActivityInfo(activityId) {
try {
const { success, data, message } = await getActivityDetail({ activityId })
const {
success,
data,
message
} = await getActivityDetail({
activityId
})
if (!success) {
this.showFailToast(message);
return;
}
let { prizeInfoList, ...rest } = data;
let {
prizeInfoList,
...rest
} = data;
this.setData({
...rest,
......@@ -204,7 +176,6 @@ Component({
originalStartTime: +rest.startTime,
isStart: +rest.startTime < Date.now(),
isEnd: +rest.endTime < Date.now(),
prizeInfoList: prizeInfoList && prizeInfoList.length > 0 ? prizeInfoList : this.data.prizeInfoList,
taskList: rest.taskList,
taskMap: this.formatTaskListToMap(rest.taskList)
})
......@@ -214,8 +185,12 @@ Component({
}
},
onChange(e) {
const { value } = e.detail;
const { name } = e.target.dataset;
const {
value
} = e.detail;
const {
name
} = e.target.dataset;
this.setData({
[name]: value
})
......@@ -227,12 +202,12 @@ Component({
},
setDataByKey(name, val) {
const keys = name.split('.');
if(keys.length === 1) {
if (keys.length === 1) {
this.setData({
[keys[0]]: val
})
}
if(keys.length === 2) {
if (keys.length === 2) {
let targetKey = this.data[keys[0]];
targetKey[keys[1]] = val;
let newVal = Object.assign({}, targetKey)
......@@ -240,7 +215,7 @@ Component({
[keys[0]]: newVal
})
}
if(keys.length === 3) {
if (keys.length === 3) {
let targetKey = this.data[keys[0]];
targetKey[keys[1]][keys[2]] = val;
let newVal = Object.assign({}, targetKey)
......@@ -250,13 +225,21 @@ Component({
}
},
onTaskInputChange(e) {
const { name } = e.target.dataset;
const { value } = e.detail;
const {
name
} = e.target.dataset;
const {
value
} = e.detail;
this.setDataByKey(name, value);
},
onCheckChange(e) {
const { name } = e.target.dataset;
const { value } = e.detail;
const {
name
} = e.target.dataset;
const {
value
} = e.detail;
this.setDataByKey(name, value);
},
onTaskChange(data, key) {
......@@ -270,7 +253,9 @@ Component({
})
},
onTimeChange(timeRange, error) {
const { formState } = this.data;
const {
formState
} = this.data;
this.setData({
timeRange,
......@@ -298,9 +283,11 @@ Component({
validator.validate(data, (errors, fields) => {
console.log('errors', errors);
console.log('fields', fields);
const { formState } = _this.data;
const {
formState
} = _this.data;
_this.setFormTips(formState, errors, target)
if(errors) {
if (errors) {
resolve(false);
} else {
resolve(true);
......@@ -316,7 +303,7 @@ Component({
Object.keys(formState).forEach(key => {
let error = errors.filter(v => target ? v.field === target && v.field === key : v.field === key).length && errors.filter(v => v.field === key)[0];
// 时间实时校验
if(key === 'timeRange' && formState[key].status === 'error') {
if (key === 'timeRange' && formState[key].status === 'error') {
return
}
newValidator[key] = {
......@@ -335,11 +322,11 @@ Component({
async onSubmit() {
const isValidForm = await this.validateForm(this.data);
// console.log(this.formatActivityParams(this.data))
if(!isValidForm) return;
if (!isValidForm) return;
console.log('成功')
......@@ -372,40 +359,29 @@ Component({
activityId = '',
startTime,
endTime,
rule,
title,
subtitle,
logoImg,
prizeInfoList,
taskList,
taskMap,
commandTitle,
commandImg,
beenInvitedText,
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
} = params;
return {
id,
activityId,
title,
subtitle,
logoImg,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
rule,
prizeInfoList: this.formatPobalityPrizeList(prizeInfoList),
// prizeInfoList: this.formatPrizeList(prizeInfoList),
taskList: this.formatTaskMapToList(taskMap),
commandTitle,
commandImg,
beenInvitedText
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
}
},
// taskMap转化taskList
formatTaskMapToList(taskMap) {
let list = [];
Object.keys(taskMap).forEach(type => {
if(!taskMap[type].checked) return;
if (!taskMap[type].checked) return;
let task = {
...taskMap[type],
type
......@@ -423,13 +399,16 @@ Component({
return taskMap
},
// 补足谢谢参与类型
formatPobalityPrizeList(prizeInfoList = []) {
formatPrizeList(prizeInfoList = []) {
let totalPercent = prizeInfoList.reduce((total, next) => {
return total = addFloat(total, +next.probablity)
return total = addFloat(total, +next.probablity)
}, 0)
// 排名类型不含谢谢参与
if(prizeInfoList[0].rank) return prizeInfoList;
let prizeInfoListCopy = prizeInfoList.concat().map((v, index) => ({ ...v, level: index }));
if (prizeInfoList[0].rank) return prizeInfoList;
let prizeInfoListCopy = prizeInfoList.concat().map((v, index) => ({
...v,
level: index
}));
if (totalPercent < 100) {
let thanksType = {
......@@ -445,85 +424,23 @@ Component({
this.backList()
},
onInputChange(e) {
let { detail: { value },
currentTarget: { dataset }
let {
detail: {
value
},
currentTarget: {
dataset
}
} = e
let { name } = dataset
this.setData({ [name]: value })
},
onChangeByDataName(val, dataName) {
this.setDataByKey(dataName, val)
},
// 选择奖品弹窗
handlerShowPrize(evt) {
const {
prizeInfoList
} = this.data
let {
name
} = evt.target.dataset
if (name === 'edit') {
this.setData({
showPrize: true,
prizeDialogData: evt.target.dataset.x,
prizeDialogEdit: true,
hasEditPrize: true
})
} else {
if (prizeInfoList.length >= 20) {
this.showFailToast('最多创建20个奖励配置')
return false
}
this.setData({
showPrize: true,
prizeDialogData: {},
prizeDialogEdit: false,
hasEditPrize: false
})
}
} = dataset
this.setData({
[name]: value
})
},
//生成规则
generateRule() {
const {
title,
startTime,
endTime,
prizeInfoList
} = this.data;
if (title && startTime && endTime && prizeInfoList.length) {
let bool = true;
prizeInfoList.forEach(i => {
if (!i.image || !i.name) {
bool = false
}
})
if (!bool) {
this.showFailToast('请检查奖品配置是否正确')
return
}
console.log({
title,
startTime: startTime,
endTime: endTime,
prizeInfoList
}, 'time');
generateRule({
title,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
prizeInfoList
}).then(res => {
if (res.success) {
this.setData({
rule: res.data,
hasEditChangePrize: false
})
}
})
} else {
this.showFailToast('请填写完整信息')
}
onChangeByDataName(val, dataName) {
this.setDataByKey(dataName, val)
},
onCloseDialog(data) {
......
import { TASK_RATE_TYPE } from '../const'
import flatten from 'lodash/flatten'
import { rankTableValidator } from "../../../utils/validate";
// 使用 async-validator 校验
// 文档地址: https://github.com/yiminghe/async-validator
export const descriptor = {
title: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value && value.length <= 12
},
message: "请输入正确的活动名称"
},
subtitle: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value && value.length <= 16
},
message: "请输入正确的活动副标题"
},
prizeInfoList: {
required: true,
validator: rankTableValidator
},
timeRange: {required: true
},
logoImg: {
required: true,
message: '请配置图片'
},
commandTitle: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入淘口令名称'
},
beenInvitedText: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入被邀请者文案'
},
commandImg: {
required: true,
message: '请输入淘口令图片'
},
rule: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入活动规则'
},
export const descriptor = {
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].validator ? configList[i].validator + ',' : '' %><% } %>
taskMap: {
type: 'object',
required: true,
required: false,
fields: {
beMembership: {
validator: (rule, val, cb, source) => {
if(!source.beMembership.checked) return true;
return !!val.value
},
message: '请输入成为会员任务的奖励'
},
inviteFriends: {
validator: (rule, val, cb, source) => {
if(!source.inviteFriends.checked) return true;
return !!(val.title && val.value)
},
message: '请输入邀请任务'
},
jumpLink: {
validator: (rule, val, cb, source) => {
if(!source.jumpLink.checked) return true;
return !!(val.title && val.value && val.link);
},
message: '请输入浏览指定页面任务'
},
browseGoods: {
validator: (rule, val) => {
return !!(val.itemIds);
},
message: '请输入寻宝屋商品任务'
}
<% for(var i = 0; i < configList.length; ++i) {%>
<%- taskKeys.includes(configList[i].key) && configList[i].validator ? configList[i].validator + ',' : '' %><% } %>
}
}
};
}
......
<view class="edit-container">
<view class="edit-breadcrumb">
<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 class="edit-content">
<form class="edit-content-form" inline="true" labelTextAlign="right" labelCol="{{labelCol}}">
<tb-label title="基础配置"/>
<form-item
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}}"
/>
</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"
tips="活动名称仅在配置后台展示,用于区分活动,不在C端展示"
/>
</form-item>
<form-item
validateState="{{formState.subtitle.status}}"
help="{{formState.subtitle.message}}"
class="edit-content-form-item"
label="活动副标题"
asterisk="{{false}}">
<tb-input
placeholder="漂流寻宝赢取100元现金红包"
maxLength="16"
value="{{subtitle}}"
dataName="subtitle"
hasLimitHint="{{true}}"
onChange="onChange"
tips="活动副标题用于C端游戏首页展示,需与活动奖品相关,用于吸引用户参与"
/>
</form-item>
<tb-label title="奖品配置"/>
<form-item
class="edit-content-form-item"
label="奖品配置"
validateState="{{formState.prizeInfoList.status}}"
help="{{formState.prizeInfoList.message}}"
asterisk="{{false}}">
<rank-table
list="{{prizeInfoList}}"
onChange="onPrizeListChange"
limit="{{11}}"
maxRankLimit="{{100}}"
fixedRank="{{['1', '2', '3']}}"
imageLimit="{{[200, 200]}}"
/>
</form-item>
<tb-label title="任务配置"/>
<form-item
class="edit-content-form-item"
label="成为会员"
validateState="{{formState['taskMap.beMembership'].status}}"
help="{{formState['taskMap.beMembership'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.beMembership.checked}}" data-name="taskMap.beMembership.checked" onChange="onCheckChange"></checkbox>
<tb-config-input
textBefore="获得"
textAfter="体力值"
validateRange="{{[1, 99]}}"
value="{{taskMap.beMembership.value}}"
dataName="taskMap.beMembership.value"
onChange="onTaskInputChange",
placeholder="1-99"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="邀请好友"
validateState="{{formState['taskMap.inviteFriends'].status}}"
help="{{formState['taskMap.inviteFriends'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.inviteFriends.checked}}" data-name="taskMap.inviteFriends.checked" onChange="onCheckChange"></checkbox>
<task-config
unit="体力值"
type="inviteFriends"
taskData="{{taskMap.inviteFriends}}"
dataName="taskMap.inviteFriends"
onUpdate="onTaskChange"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="浏览指定页面"
validateState="{{formState['taskMap.jumpLink'].status}}"
help="{{formState['taskMap.jumpLink'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.jumpLink.checked}}" data-name="taskMap.jumpLink.checked" onChange="onCheckChange"></checkbox>
<task-config
unit="体力值"
type="jumpLink"
hasLink
taskData="{{taskMap.jumpLink}}"
dataName="taskMap.jumpLink"
onUpdate="onTaskChange"
/>
</view>
</form-item>
<form-item
class="edit-content-form-item"
label="寻宝屋商品"
validateState="{{formState['taskMap.browseGoods'].status}}"
help="{{formState['taskMap.browseGoods'].message}}"
asterisk="{{false}}">
<view class="form-flex">
<checkbox class="form-check" checked="{{taskMap.browseGoods.checked}}" disabled="{{true}}"></checkbox>
<items-config itemIds="{{taskMap.browseGoods.itemIds}}" dataName="taskMap.browseGoods.itemIds" onUpdate="onTaskChange"/>
</view>
</form-item>
<form-item
validateState="{{formState.logoImg.status}}"
help="{{formState.logoImg.message}}"
class="edit-content-form-item"
label="logo图片"
asterisk="{{false}}">
<view style="display:flex;">
<tb-image-upload url="{{logoImg}}" dataName="logoImg" onSuccess="onChangeByDataName" imageLimit="{{[200, 90]}}"/>
<question-tips>
<image style="width:200px;height:400px;border:1px solid #ccc;margin-right:10px" src="//yun.duiba.com.cn/20200410/image2020-6-7_18-16-3.png"></image>
</question-tips>
</view>
</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="20"
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="30"
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 url="{{commandImg}}" dataName="commandImg" onSuccess="onChangeByDataName" imageLimit="{{[400, 300]}}"/>
</form-item>
<tb-label title="规则配置"/>
<form-item
validateState="{{formState.rule.status}}"
help="{{formState.rule.message}}"
class="edit-content-form-item"
label="活动规则"
asterisk="{{false}}">
<tb-rule value="{{rule}}" onChange="onRuleChange" generateRuleInfo="{{{title: subtitle, startTime, endTime, prizeInfoList}}}"/>
</form-item>
<view class="submit-btn">
<button onTap="onSubmit" type="primary">确定</button>
<button onTap="cancelEdit">取消</button>
</view>
</form>
</view>
\ No newline at end of file
import moment from 'moment'
import schema from 'async-validator';
import {
descriptor,
formatValidator
} from './validate';
import { descriptor, formatValidator } from './validate';
import {
getActivityDetail,
saveActivityInfo,
......@@ -19,15 +16,57 @@ var validator = new schema(descriptor);
Component({
data: {
labelCol: {
fixedSpan: 5
},
labelCol: { fixedSpan: 5 },
id: '',
title: '',
subtitle: '',
startTime: '',
endTime: '',
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
taskList: [
timeRange: [],
rule: '',
prizeInfoList: [
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "1"
},
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "2"
},
{
ename: "",
id: "",
stock: "",
type: 1,
image: "",
credits: "",
name: "",
limitStock: 0,
useStock: 0,
rank: "3"
}
],
commandTitle: '',
commandImg: '',
logoImg: '',
beenInvitedText: '',
taskList:[
// {
// type: "beMembership",//会员
// value: 20,//完成任务获得值
......@@ -87,20 +126,20 @@ Component({
],
taskMap: {
attentionStore: {
value: '',
},
// attentionStore: {
// value: '',
// },
beMembership: {
value: '',
value:'',
checked: false
},
sign: {
value: ''
},
exchangeCredits: {
value: '',
times: '',
},
// sign: {
// value: ''
// },
// exchangeCredits: {
// value: '',
// times: '',
// },
inviteFriends: {
title: '', // 任务标题
taskRateType: 1, // 任务频率类型
......@@ -117,17 +156,17 @@ Component({
itemIds: '',
checked: true
},
collectGoods: {
title: "",
taskRateType: 1,
times: 3,
value: '90',
itemIds: "",
},
// collectGoods: {
// title: "",
// taskRateType: 1,
// times: 3,
// value: '90',
// itemIds: "",
// },
jumpLink: {
title: "",
taskRateType: 3,
link: "", //跳转链接
link: "",//跳转链接
times: 3,
value: '',
checked: false
......@@ -142,9 +181,7 @@ Component({
},
props: {},
didMount() {
const {
id
} = this.$page.$router.params
const { id } = this.$page.$router.params
if (id) {
this.getActivityInfo(id)
}
......@@ -153,22 +190,13 @@ Component({
// 获取id活动信息
async getActivityInfo(activityId) {
try {
const {
success,
data,
message
} = await getActivityDetail({
activityId
})
const { success, data, message } = await getActivityDetail({ activityId })
if (!success) {
this.showFailToast(message);
return;
}
let {
prizeInfoList,
...rest
} = data;
let { prizeInfoList, ...rest } = data;
this.setData({
...rest,
......@@ -176,6 +204,7 @@ Component({
originalStartTime: +rest.startTime,
isStart: +rest.startTime < Date.now(),
isEnd: +rest.endTime < Date.now(),
prizeInfoList: prizeInfoList && prizeInfoList.length > 0 ? prizeInfoList : this.data.prizeInfoList,
taskList: rest.taskList,
taskMap: this.formatTaskListToMap(rest.taskList)
})
......@@ -185,12 +214,8 @@ Component({
}
},
onChange(e) {
const {
value
} = e.detail;
const {
name
} = e.target.dataset;
const { value } = e.detail;
const { name } = e.target.dataset;
this.setData({
[name]: value
})
......@@ -202,12 +227,12 @@ Component({
},
setDataByKey(name, val) {
const keys = name.split('.');
if (keys.length === 1) {
if(keys.length === 1) {
this.setData({
[keys[0]]: val
})
}
if (keys.length === 2) {
if(keys.length === 2) {
let targetKey = this.data[keys[0]];
targetKey[keys[1]] = val;
let newVal = Object.assign({}, targetKey)
......@@ -215,7 +240,7 @@ Component({
[keys[0]]: newVal
})
}
if (keys.length === 3) {
if(keys.length === 3) {
let targetKey = this.data[keys[0]];
targetKey[keys[1]][keys[2]] = val;
let newVal = Object.assign({}, targetKey)
......@@ -225,21 +250,13 @@ Component({
}
},
onTaskInputChange(e) {
const {
name
} = e.target.dataset;
const {
value
} = e.detail;
const { name } = e.target.dataset;
const { value } = e.detail;
this.setDataByKey(name, value);
},
onCheckChange(e) {
const {
name
} = e.target.dataset;
const {
value
} = e.detail;
const { name } = e.target.dataset;
const { value } = e.detail;
this.setDataByKey(name, value);
},
onTaskChange(data, key) {
......@@ -253,9 +270,7 @@ Component({
})
},
onTimeChange(timeRange, error) {
const {
formState
} = this.data;
const { formState } = this.data;
this.setData({
timeRange,
......@@ -283,11 +298,9 @@ Component({
validator.validate(data, (errors, fields) => {
console.log('errors', errors);
console.log('fields', fields);
const {
formState
} = _this.data;
const { formState } = _this.data;
_this.setFormTips(formState, errors, target)
if (errors) {
if(errors) {
resolve(false);
} else {
resolve(true);
......@@ -303,7 +316,7 @@ Component({
Object.keys(formState).forEach(key => {
let error = errors.filter(v => target ? v.field === target && v.field === key : v.field === key).length && errors.filter(v => v.field === key)[0];
// 时间实时校验
if (key === 'timeRange' && formState[key].status === 'error') {
if(key === 'timeRange' && formState[key].status === 'error') {
return
}
newValidator[key] = {
......@@ -322,11 +335,11 @@ Component({
async onSubmit() {
const isValidForm = await this.validateForm(this.data);
// console.log(this.formatActivityParams(this.data))
if (!isValidForm) return;
if(!isValidForm) return;
console.log('成功')
......@@ -359,29 +372,40 @@ Component({
activityId = '',
startTime,
endTime,
rule,
title,
subtitle,
logoImg,
prizeInfoList,
taskList,
taskMap,
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
commandTitle,
commandImg,
beenInvitedText,
} = params;
return {
id,
activityId,
title,
subtitle,
logoImg,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
// prizeInfoList: this.formatPrizeList(prizeInfoList),
rule,
prizeInfoList: this.formatPobalityPrizeList(prizeInfoList),
taskList: this.formatTaskMapToList(taskMap),
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].key !== 'label' ? configList[i].key + ',' : '' %><% } %>
commandTitle,
commandImg,
beenInvitedText
}
},
// taskMap转化taskList
formatTaskMapToList(taskMap) {
let list = [];
Object.keys(taskMap).forEach(type => {
if (!taskMap[type].checked) return;
if(!taskMap[type].checked) return;
let task = {
...taskMap[type],
type
......@@ -399,16 +423,13 @@ Component({
return taskMap
},
// 补足谢谢参与类型
formatPrizeList(prizeInfoList = []) {
formatPobalityPrizeList(prizeInfoList = []) {
let totalPercent = prizeInfoList.reduce((total, next) => {
return total = addFloat(total, +next.probablity)
return total = addFloat(total, +next.probablity)
}, 0)
// 排名类型不含谢谢参与
if (prizeInfoList[0].rank) return prizeInfoList;
let prizeInfoListCopy = prizeInfoList.concat().map((v, index) => ({
...v,
level: index
}));
if(prizeInfoList[0].rank) return prizeInfoList;
let prizeInfoListCopy = prizeInfoList.concat().map((v, index) => ({ ...v, level: index }));
if (totalPercent < 100) {
let thanksType = {
......@@ -424,24 +445,86 @@ Component({
this.backList()
},
onInputChange(e) {
let {
detail: {
value
},
currentTarget: {
dataset
}
let { detail: { value },
currentTarget: { dataset }
} = e
let {
name
} = dataset
this.setData({
[name]: value
})
let { name } = dataset
this.setData({ [name]: value })
},
onChangeByDataName(val, dataName) {
this.setDataByKey(dataName, val)
},
// 选择奖品弹窗
handlerShowPrize(evt) {
const {
prizeInfoList
} = this.data
let {
name
} = evt.target.dataset
if (name === 'edit') {
this.setData({
showPrize: true,
prizeDialogData: evt.target.dataset.x,
prizeDialogEdit: true,
hasEditPrize: true
})
} else {
if (prizeInfoList.length >= 20) {
this.showFailToast('最多创建20个奖励配置')
return false
}
this.setData({
showPrize: true,
prizeDialogData: {},
prizeDialogEdit: false,
hasEditPrize: false
})
}
},
//生成规则
generateRule() {
const {
title,
startTime,
endTime,
prizeInfoList
} = this.data;
if (title && startTime && endTime && prizeInfoList.length) {
let bool = true;
prizeInfoList.forEach(i => {
if (!i.image || !i.name) {
bool = false
}
})
if (!bool) {
this.showFailToast('请检查奖品配置是否正确')
return
}
console.log({
title,
startTime: startTime,
endTime: endTime,
prizeInfoList
}, 'time');
generateRule({
title,
startTime: new Date(startTime).getTime(),
endTime: new Date(endTime).getTime(),
prizeInfoList
}).then(res => {
if (res.success) {
this.setData({
rule: res.data,
hasEditChangePrize: false
})
}
})
} else {
this.showFailToast('请填写完整信息')
}
},
onCloseDialog(data) {
switch (data) {
......
import { TASK_RATE_TYPE } from '../const'
import flatten from 'lodash/flatten'
import { rankTableValidator } from "../../../utils/validate";
// 使用 async-validator 校验
// 文档地址: https://github.com/yiminghe/async-validator
export const descriptor = {
title: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value && value.length <= 12
},
message: "请输入正确的活动名称"
},
subtitle: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value && value.length <= 16
},
message: "请输入正确的活动副标题"
},
prizeInfoList: {
required: true,
validator: rankTableValidator
},
timeRange: {required: true
},
logoImg: {
required: true,
message: '请配置图片'
},
commandTitle: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入淘口令名称'
},
beenInvitedText: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入被邀请者文案'
},
commandImg: {
required: true,
message: '请输入淘口令图片'
},
rule: {
required: true,
validator: (rule, value) => {
value = value.trim();
return !!value;
},
message: '请输入活动规则'
},
taskMap: {
type: 'object',
required: true,
fields: {
beMembership: {
validator: (rule, val, cb, source) => {
if(!source.beMembership.checked) return true;
return !!val.value
},
message: '请输入成为会员任务的奖励'
},
inviteFriends: {
validator: (rule, val, cb, source) => {
if(!source.inviteFriends.checked) return true;
return !!(val.title && val.value)
},
message: '请输入邀请任务'
},
jumpLink: {
validator: (rule, val, cb, source) => {
if(!source.jumpLink.checked) return true;
return !!(val.title && val.value && val.link);
},
message: '请输入浏览指定页面任务'
},
browseGoods: {
validator: (rule, val) => {
return !!(val.itemIds);
},
message: '请输入寻宝屋商品任务'
}
}
}
};
export const formatValidator = (descriptor, validators) => {
validators = validators || {}
Object.keys(descriptor).forEach(key => {
if(descriptor[key].fields) {
Object.keys(descriptor[key].fields).forEach(fieldKey => {
validators[`${key}.${fieldKey}`] = {
status: 'success',
message: ''
}
})
} else {
validators[key] = {
status: 'success',
message: ''
}
}
});
return validators
}
\ No newline at end of file
<view class="edit-container">
<view class="edit-breadcrumb">
<text class="edit-title edit-title_my" onTap="backList">我的活动</text>
<text class="edit-title edit-title-separate">/</text>
<text class="edit-title">{{activityId ? '编辑' : '新建'}} 「 <%=appName%> 」 活动</text>
</view>
<view class="edit-content">
<form class="edit-content-form" inline="true" labelTextAlign="right" labelCol="{{labelCol}}">
<% for(var i = 0; i < configList.length; ++i) {%>
<%-configList[i].template%><% } %>
<view class="submit-btn">
<button onTap="onSubmit" type="primary">确定</button>
<button>取消</button>
</view>
</form>
</view>
\ No newline at end of file
import { rankTableValidator } from "../../../utils/validate";
// 使用 async-validator 校验
// 文档地址: https://github.com/yiminghe/async-validator
export const descriptor = {
<% for(var i = 0; i < configList.length; ++i) {%>
<%- !taskKeys.includes(configList[i].key) && configList[i].validator ? configList[i].validator + ',' : '' %><% } %>
taskMap: {
type: 'object',
required: false,
fields: {
<% for(var i = 0; i < configList.length; ++i) {%>
<%- taskKeys.includes(configList[i].key) && configList[i].validator ? configList[i].validator + ',' : '' %><% } %>
}
}
}
export const formatValidator = (descriptor, validators) => {
validators = validators || {}
Object.keys(descriptor).forEach(key => {
if(descriptor[key].fields) {
Object.keys(descriptor[key].fields).forEach(fieldKey => {
validators[`${key}.${fieldKey}`] = {
status: 'success',
message: ''
}
})
} else {
validators[key] = {
status: 'success',
message: ''
}
}
});
return validators
}
\ No newline at end of file
......@@ -2,4 +2,4 @@
<text class="db-title">活动管理</text>
<button type="primary" onTap="tapname">创建活动</button>
</view>
<list-table/>
<%- listTable %>
......@@ -3,6 +3,9 @@ const { function: fc } = cloud;
Component({
props: {},
data: {
buttons: <%= buttons %>
},
methods: {
// 创建活动
tapname() {
......
......@@ -2,4 +2,4 @@
<text class="db-title">活动管理</text>
<button type="primary" onTap="tapname">创建活动</button>
</view>
<%- listTable %>
<list-table/>
......@@ -3,9 +3,6 @@ const { function: fc } = cloud;
Component({
props: {},
data: {
buttons: <%= buttons %>
},
methods: {
// 创建活动
tapname() {
......
......@@ -12,11 +12,11 @@ export default {
},
{
path: "/list",
component: "listTemp",
component: "list",
},
{
path: "/add",
component: "addTemp",
component: "add",
},
{
path: '/data/:id',
......@@ -24,7 +24,7 @@ export default {
},
{
path: "/edit/:id",
component: "addTemp",
component: "add",
},
],
}
......
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