Authored by yyq

edit

@@ -56,7 +56,21 @@ const zeroBuy = { @@ -56,7 +56,21 @@ const zeroBuy = {
56 res.setHeader('Content-Disposition', `attachment; filename=zerobuy_${id}_${new Date().getTime()}.xlsx`); 56 res.setHeader('Content-Disposition', `attachment; filename=zerobuy_${id}_${new Date().getTime()}.xlsx`);
57 res.end(excelExport.execute(result), 'binary'); 57 res.end(excelExport.execute(result), 'binary');
58 }).catch(next); 58 }).catch(next);
59 - } 59 + },
  60 + zeroBuyEdit(req, res, next) {
  61 + req.ctx(ActivityModel).getZerobuyContent(req.query.id).then(result => {
  62 + res.render('activity/zero-buy-edit', {
  63 + bodyClass: 'nav-md',
  64 + content: result,
  65 + module: 'admin',
  66 + page: 'zero-buy'
  67 + });
  68 + }).catch(next);
  69 + },
  70 + zeroBuySave(req, res, next) {
  71 + req.ctx(ActivityModel).saveZerobuyContent(req.body)
  72 + .then(res.json).catch(next);
  73 + },
60 }; 74 };
61 75
62 const activity = { 76 const activity = {
@@ -18,8 +18,7 @@ const TB_ACT_ARTICLE_GOOD = 'act_article_good'; @@ -18,8 +18,7 @@ const TB_ACT_ARTICLE_GOOD = 'act_article_good';
18 const TB_ACT_ARTICLE_Y100 = 'act_article_y100'; 18 const TB_ACT_ARTICLE_Y100 = 'act_article_y100';
19 19
20 const TABLE_ACT_PRIZE_PRODUCT = 'act_prize_product'; 20 const TABLE_ACT_PRIZE_PRODUCT = 'act_prize_product';
21 -  
22 -// const TABLE_ACT_PRIZE_PRODUCT_CONTENT = 'act_prize_product_content'; 21 +const TABLE_ACT_PRIZE_PRODUCT_CONTENT = 'act_prize_product_content';
23 const TABLE_ACT_PRIZE_PRODUCT_USER = 'act_prize_product_user'; 22 const TABLE_ACT_PRIZE_PRODUCT_USER = 'act_prize_product_user';
24 23
25 const timeFormat = (time) => { 24 const timeFormat = (time) => {
@@ -30,6 +29,14 @@ const timeFormat = (time) => { @@ -30,6 +29,14 @@ const timeFormat = (time) => {
30 return moment(time).format('YYYY-MM-DD HH:mm:ss'); 29 return moment(time).format('YYYY-MM-DD HH:mm:ss');
31 }; 30 };
32 31
  32 +const parseJSON = (json) => {
  33 + try {
  34 + return JSON.parse(json);
  35 + } catch(e) { // eslint-disable-line
  36 + return '';
  37 + }
  38 +};
  39 +
33 class AdminModel extends global.yoho.BaseModel { 40 class AdminModel extends global.yoho.BaseModel {
34 constructor(ctx) { 41 constructor(ctx) {
35 super(ctx); 42 super(ctx);
@@ -565,6 +572,150 @@ class AdminModel extends global.yoho.BaseModel { @@ -565,6 +572,150 @@ class AdminModel extends global.yoho.BaseModel {
565 }; 572 };
566 }); 573 });
567 } 574 }
  575 +
  576 + getZerobuyContent(id) {
  577 + if (!id) {
  578 + return Promise.resolve({});
  579 + }
  580 +
  581 + return Promise.all([
  582 + mysqlCli.query(`select * from ${TABLE_ACT_PRIZE_PRODUCT}
  583 + where id = :id limit 1;`, {id}),
  584 + mysqlCli.query(`select * from ${TABLE_ACT_PRIZE_PRODUCT_CONTENT}
  585 + where act_prize_id = :id;`, {id})
  586 + ]).then(result => {
  587 + let resData = {};
  588 + let [product, content] = result;
  589 +
  590 + if (product && product.length) {
  591 + resData = product[0];
  592 + resData.content = _.sortBy(content || [], o => {
  593 + return o.sort;
  594 + });
  595 +
  596 + resData.time = `${timeFormat(resData.start_time)} - ${timeFormat(resData.end_time)}`;
  597 + }
  598 +
  599 + return resData;
  600 + });
  601 + }
  602 +
  603 + saveZerobuyContent(params) {
  604 + let sqls = [];
  605 +
  606 + let times = _.split(params.time, ' - ', 2);
  607 + let proParams = {
  608 + id: params.id,
  609 + name: params.name,
  610 + price: params.price,
  611 + sort: params.sort || 0,
  612 + cover: params.cover,
  613 + limit: params.limit,
  614 + startTime: Date.parse(new Date(_.trim(times[0]).replace(/-/g, '/'))) / 1000,
  615 + endTime: Date.parse(new Date(_.trim(times[1]).replace(/-/g, '/'))) / 1000
  616 + };
  617 +
  618 + if (params.id) {
  619 + sqls.push(mysqlCli.update(`update ${TABLE_ACT_PRIZE_PRODUCT} set
  620 + name = :name, price = :price, \`limit\` = :limit,
  621 + cover_img = :cover, sort = :sort,
  622 + start_time = :startTime, end_time = :endTime
  623 + where id = :id`, proParams));
  624 +
  625 + // 更新楼层
  626 + let editFloors = params.editFloors ? parseJSON(params.editFloors) : '';
  627 +
  628 + if (editFloors && editFloors.length) {
  629 + let editParams = {};
  630 + let ids = [];
  631 + let contentWhen = [];
  632 + let sortWhen = [];
  633 +
  634 + _.forEach(editFloors, (value, index) => {
  635 + let id = parseInt(value.id, 10);
  636 + let contentKey = `content${index}`;
  637 + let sortKey = `sort${index}`;
  638 +
  639 + if (!id) {
  640 + return;
  641 + }
  642 +
  643 + ids.push(id);
  644 + contentWhen.push(`when ${id} then :${contentKey}`);
  645 + sortWhen.push(`when ${id} then :${sortKey}`);
  646 + editParams[contentKey] = value.content;
  647 + editParams[sortKey] = value.sort;
  648 + });
  649 +
  650 + if (ids.length) {
  651 + sqls.push(mysqlCli.update(`update ${TABLE_ACT_PRIZE_PRODUCT_CONTENT} set
  652 + content = case id ${contentWhen.join(' ')} end,
  653 + sort = case id ${sortWhen.join(' ')} end
  654 + where id in (${ids.join(',')})`, editParams));
  655 + }
  656 + }
  657 +
  658 + // 删除楼层
  659 + let deleteFloors = params.deleteFloors ? parseJSON(params.deleteFloors) : '';
  660 +
  661 + if (deleteFloors && deleteFloors.length) {
  662 + _.remove(deleteFloors, n => {
  663 + return !(+n);
  664 + });
  665 +
  666 + if (deleteFloors.length) {
  667 + sqls.push(mysqlCli.delete(`delete from ${TABLE_ACT_PRIZE_PRODUCT_CONTENT}
  668 + where id in (${deleteFloors.join(',')})`, {}));
  669 + }
  670 + }
  671 + } else {
  672 + sqls.push(mysqlCli.insert(`insert into ${TABLE_ACT_PRIZE_PRODUCT} (
  673 + name, price, \`limit\`, sort, cover_img, start_time, end_time) values (
  674 + :name, :price, :limit, :sort, :cover, :startTime, :endTime
  675 + )`, proParams));
  676 + }
  677 +
  678 + return Promise.all(sqls).then(result => {
  679 + let pid = params.id || result[0];
  680 +
  681 + // 删除楼层
  682 + let newFloors = params.newFloors ? parseJSON(params.newFloors) : '';
  683 +
  684 + if (newFloors && newFloors.length) {
  685 + let unionParams = {};
  686 + let union = [];
  687 +
  688 + _.forEach(newFloors, (value, index) => {
  689 + if (!value.content) {
  690 + return;
  691 + }
  692 +
  693 + let typeKey = `type${index}`;
  694 + let contentKey = `content${index}`;
  695 + let sortKey = `sort${index}`;
  696 +
  697 + unionParams[typeKey] = value.type;
  698 + unionParams[contentKey] = value.content;
  699 + unionParams[sortKey] = value.sort;
  700 +
  701 + union.push(`select ${pid}, :${typeKey}, :${contentKey}, :${sortKey}`);
  702 + });
  703 +
  704 + if (union.length) {
  705 + mysqlCli.insert(`insert into ${TABLE_ACT_PRIZE_PRODUCT_CONTENT} (
  706 + act_prize_id, floor_type, content, sort)
  707 + ${union.join(' union all')}`, unionParams);
  708 + }
  709 + }
  710 +
  711 + return {
  712 + code: 200,
  713 + data: {
  714 + id: pid
  715 + }
  716 + };
  717 + });
  718 + }
568 } 719 }
569 720
570 module.exports = AdminModel; 721 module.exports = AdminModel;
@@ -24,6 +24,8 @@ router.get('/activity/zerobuy', activity.zeroBuyList); @@ -24,6 +24,8 @@ router.get('/activity/zerobuy', activity.zeroBuyList);
24 router.post('/activity/zerobuy/switch', activity.zeroBuySwitch); 24 router.post('/activity/zerobuy/switch', activity.zeroBuySwitch);
25 router.post('/activity/zerobuy/publish', activity.zeroBuyPublish); 25 router.post('/activity/zerobuy/publish', activity.zeroBuyPublish);
26 router.get('/activity/zerobuy/export', activity.zeroBuyExport); 26 router.get('/activity/zerobuy/export', activity.zeroBuyExport);
  27 +router.get('/activity/zerobuy/edit', activity.zeroBuyEdit);
  28 +router.post('/activity/zerobuy/save', activity.zeroBuySave);
27 29
28 // 用户管理[page] 30 // 用户管理[page]
29 router.get('/user/list', user.userListPage); 31 router.get('/user/list', user.userListPage);
  1 +<div class="right_col" role="main">
  2 + <div class="col-md-12 col-sm-12 col-xs-12">
  3 + <div class="x_panel">
  4 + {{# content}}
  5 + <div class="x_title">
  6 + <h2>基本信息</h2>
  7 + <div class="clearfix"></div>
  8 + </div>
  9 + <form id="createForm" class="form-horizontal form-label-left">
  10 + <input class="form-imput" type="hidden" data-type="id" value="{{id}}">
  11 + <div class="item form-group">
  12 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">
  13 + 商品名称<span class="required">*</span>
  14 + </label>
  15 + <div class="col-md-6 col-sm-6 col-xs-12">
  16 + <input class="form-control col-md-7 col-xs-12 form-imput"
  17 + data-type="name"
  18 + data-toggle="tooltip"
  19 + data-placement="bottom"
  20 + title="商品名称不能为空"
  21 + name="actName"
  22 + type="text"
  23 + maxlength="50"
  24 + value="{{name}}">
  25 + </div>
  26 + </div>
  27 + <div class="item form-group">
  28 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">
  29 + 商品图片<span class="required">*</span>
  30 + </label>
  31 + <div class="col-md-6 col-sm-6 col-xs-12">
  32 + <img src="{{cover_img}}" class="col-md-6 product-thumb {{#unless cover_img}}hide{{/unless}}">
  33 +
  34 + <button type="button" class="btn btn-primary btn-upload-thumb" data-cover="{{cover_img}}">上传</button>
  35 + </div>
  36 + </div>
  37 + <div class="item form-group">
  38 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">
  39 + 商品价格<span class="required">*</span>
  40 + </label>
  41 + <div class="col-md-6 col-sm-6 col-xs-12">
  42 + <input class="form-control col-md-7 col-xs-12 form-imput"
  43 + data-type="price"
  44 + data-toggle="tooltip"
  45 + data-placement="bottom"
  46 + title="商品价格不能为空"
  47 + name="actName"
  48 + type="text"
  49 + maxlength="10"
  50 + value="{{price}}">
  51 + </div>
  52 + </div>
  53 + <div class="item form-group">
  54 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="activityTime">活动有效时间<span
  55 + class="required">*</span>
  56 + </label>
  57 + <div class="col-md-6 col-sm-6 col-xs-12">
  58 + <div class="input-prepend input-group">
  59 + <span class="add-on input-group-addon"><i
  60 + class="glyphicon glyphicon-calendar fa fa-calendar"></i></span>
  61 + <input type="text" name="activityTime" id="activityTime"
  62 + class="form-control col-md-7 col-xs-12 form-imput"
  63 + data-type="time"
  64 + placeholder="开始时间 - 结束时间"
  65 + value="{{time}}"/>
  66 + </div>
  67 + </div>
  68 + </div>
  69 + <div class="item form-group">
  70 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">开奖需要人数<span
  71 + class="required">*</span>
  72 + </label>
  73 + <div class="col-md-2 col-sm-2 col-xs-12">
  74 + <input id="actVoteLimit" class="form-control col-md-2 form-imput"
  75 + data-type="limit"
  76 + data-toggle="tooltip" data-placement="bottom" title="开奖需要人数"
  77 + name="actVoteLimit"
  78 + type="text"
  79 + maxlength="10"
  80 + value="{{limit}}">
  81 + </div>
  82 + </div>
  83 + <div class="item form-group">
  84 + <label class="control-label col-md-3 col-sm-3 col-xs-12" for="actName">排序<span
  85 + class="required">*</span>
  86 + </label>
  87 + <div class="col-md-2 col-sm-2 col-xs-12">
  88 + <input id="actVoteLimit" class="form-control col-md-2 form-imput"
  89 + data-type="sort"
  90 + data-toggle="tooltip" data-placement="bottom" title="排序"
  91 + name="actVoteLimit"
  92 + type="text"
  93 + maxlength="10"
  94 + value="{{sort}}">
  95 + </div>
  96 + </div>
  97 + </form>
  98 + <div class="x_title">
  99 + <h2>详情内容</h2>
  100 + <div class="clearfix"></div>
  101 + </div>
  102 + <div>
  103 + <div class="col-md-6 col-md-offset-3 floor-view-box">
  104 + {{# content}}
  105 + <div class="floor-item"
  106 + data-id="{{id}}"
  107 + data-sort="{{sort}}"
  108 + data-content="{{content}}"
  109 + {{#isEqualOr floor_type 1}}
  110 + data-type="text">
  111 +
  112 + <p class="item-content">{{content}}</p
  113 + {{/isEqualOr}}
  114 + {{#isEqualOr floor_type 2}}
  115 + data-type="img">
  116 + <img src="{{content}}" class="item-content"
  117 + {{/isEqualOr}}
  118 + {{#isEqualOr floor_type 3}}
  119 + data-type="video">
  120 + <video src="{{content}}" class="item-content">
  121 + 您的浏览器不支持 video 标签。
  122 + </video>
  123 + {{/isEqualOr}}
  124 + >
  125 +
  126 + <div class="option-btns">
  127 + <span class="glyphicon glyphicon-arrow-up up-item-btn"></span>
  128 + <span class="glyphicon glyphicon-arrow-down down-item-btn"></span>
  129 + </div>
  130 + <span class="del-item-btn">删除</span>
  131 + </div>
  132 + {{/ content}}
  133 + </div>
  134 + <div class="col-md-6 col-md-offset-3">
  135 + <button type="button" class="btn btn-primary btn-add-floor" data-type="text">文本</button>
  136 + <button type="button" class="btn btn-primary btn-add-floor" data-type="img">图片</button>
  137 + <button type="button" class="btn btn-primary btn-add-floor" data-type="video">视频</button>
  138 + </div>
  139 + <div class="col-md-2 col-md-offset-10 action-wrap">
  140 + <button type="button" class="btn btn-primary btn-save-activity">保存</button>
  141 + </div>
  142 + </div>
  143 + <a id="upload-btn"></a>
  144 +
  145 + {{/ content}}
  146 + </div>
  147 + </div>
  148 +</div>
1 <!-- page content --> 1 <!-- page content -->
2 -<div class="right_col" role="main"> 2 +<div class="right_col zerobuy-list-page" role="main">
3 <div class="col-md-12 col-sm-12 col-xs-12"> 3 <div class="col-md-12 col-sm-12 col-xs-12">
4 <div class="x_panel"> 4 <div class="x_panel">
  5 + <div>
  6 + <a href="/admin/activity/zerobuy/edit" class="btn btn-primary">创建抽奖活动</a>
  7 + <div class="clearfix"></div>
  8 +{{!--
  9 + <input type="text" class="form-control" aria-label="...">
  10 + <div class="btn-group">
  11 + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">全部 <span class="caret"></span></button>
  12 + <ul class="dropdown-menu">
  13 + <li><a href="#">关闭</a></li>
  14 + <li><a href="#">开启</a></li>
  15 + <li><a href="#">已开奖</a></li>
  16 + </ul>
  17 + </div>
  18 +
  19 + <button type="button" class="btn btn-primary">筛选</button>
  20 + <button type="button" class="btn btn-primary">全部</button> --}}
  21 +
  22 +
  23 + </div>
  24 +
5 <table class="table table-bordered"> 25 <table class="table table-bordered">
6 <thead> 26 <thead>
7 <tr class="headings"> 27 <tr class="headings">
1 -require('admin/activity.page.css'); 1 +require('admin/zero-buy.page.css');
  2 +require('bootstrap-daterangepicker');
2 3
  4 +const _ = require('lodash');
3 const $alert = $('#alert-modal'); 5 const $alert = $('#alert-modal');
4 const $confirm = $('#confirm-modal'); 6 const $confirm = $('#confirm-modal');
5 7
6 -function bindEvent() { 8 +function bindListPageEvent() {
7 const editFn = function() { 9 const editFn = function() {
8 window.open('/admin/activity/zerobuy/edit?id=' + 10 window.open('/admin/activity/zerobuy/edit?id=' +
9 $(this).data('id'), '_blank'); 11 $(this).data('id'), '_blank');
@@ -61,5 +63,342 @@ function bindEvent() { @@ -61,5 +63,342 @@ function bindEvent() {
61 $('.sure-publish-btn').on('click', publishFn); 63 $('.sure-publish-btn').on('click', publishFn);
62 } 64 }
63 65
  66 +let uploadedFn;
  67 +let $upload;
64 68
65 -bindEvent(); 69 +function initUpload() {
  70 + $upload = $('#upload-btn');
  71 +
  72 + if (!$upload.length) {
  73 + return;
  74 + }
  75 +
  76 + const imgArr = ['image/jpeg', 'image/jpg', 'image/png'];
  77 +
  78 + // why? reference: https://github.com/qiniu/js-sdk/issues/266
  79 + Promise.all([
  80 + require('mOxie/bin/js/moxie'),
  81 + require('plupload/js/plupload.dev'),
  82 + require('qiniu-js')
  83 + ]).then(([moxie, plupload]) => {
  84 + window.moxie = moxie;
  85 + window.plupload = plupload;
  86 +
  87 + Qiniu.uploader({ // eslint-disable-line
  88 + runtimes: 'html5,flash,html4',
  89 + browse_button: 'upload-btn',
  90 + uptoken_url: '/api/getToken',
  91 + unique_names: true,
  92 + multi_selection: false,
  93 + filters: {
  94 + mime_types: [{
  95 + extensions: 'jpg,jpeg,png,mp4'
  96 + }]
  97 + },
  98 + dragdrop: false,
  99 + domain: 'http://img01.yohoboys.com/',
  100 + max_file_size: '10mb',
  101 + max_retries: 3,
  102 + chunk_size: '10mb',
  103 + auto_start: true,
  104 + init: {
  105 + BeforeUpload: function(up) {
  106 + window.checkup = up;
  107 + },
  108 + UploadProgress: function() {
  109 + console.log('上传中...');
  110 + },
  111 + FileUploaded: function(up, file, info) {
  112 + var domain = up.getOption('domain');
  113 + var res = JSON.parse(info.response);
  114 + var url = domain + res.key;
  115 +
  116 + uploadedFn && uploadedFn(url, imgArr.indexOf(file.type) >= 0);
  117 + },
  118 + Error: function(up, err, errTip) {
  119 + console.log(err, errTip);
  120 + }
  121 + }
  122 + });
  123 + });
  124 +}
  125 +
  126 +function generateCid(id) {
  127 + id = parseInt(id, 10) || 0;
  128 +
  129 + return Math.floor(Date.now() + Math.random() * 10000000000 * (id + 1));
  130 +}
  131 +
  132 +function bindEditPageEvent() {
  133 + initUpload();
  134 +
  135 + let $floorBox = $('.floor-view-box');
  136 + let floorContent = {};
  137 + const typeName = {
  138 + text: '文本',
  139 + img: '图片',
  140 + video: '视频'
  141 + };
  142 +
  143 + const typeNum = {
  144 + text: 1,
  145 + img: 2,
  146 + video: 3
  147 + };
  148 +
  149 + function packInfo() {
  150 + let resData = {};
  151 + let error;
  152 +
  153 + $('.form-imput').each(function() {
  154 + let $this = $(this);
  155 + let val = $this.val();
  156 + let data = $this.data();
  157 +
  158 + if (!val && !error && data.type !== 'id') {
  159 + error = data.empty || `请填写${data.type}`;
  160 + }
  161 +
  162 + resData[data.type] = val;
  163 + });
  164 +
  165 + if (error) {
  166 + alert(error);
  167 + return;
  168 + }
  169 +
  170 + resData.cover = $('.btn-upload-thumb').data('cover');
  171 +
  172 + if (!resData.cover) {
  173 + alert('请上传商品图');
  174 + return;
  175 + }
  176 +
  177 + let newFloors = [];
  178 + let editFloors = [];
  179 + let deleteFloors = [];
  180 + let index = 0;
  181 +
  182 + $floorBox.children('.floor-item').each(function() {
  183 + let item = floorContent[$(this).data('cid')];
  184 +
  185 + if (!item) {
  186 + return;
  187 + }
  188 +
  189 + if (!item.id) {
  190 + newFloors.push({
  191 + content: item.newContent,
  192 + sort: index
  193 + });
  194 + } else if (item.newContent || +item.sort !== index) {
  195 + editFloors.push({
  196 + id: item.id,
  197 + type: typeNum[item.type] || 1,
  198 + content: item.newContent || item.content,
  199 + sort: index
  200 + });
  201 + }
  202 + index++;
  203 + });
  204 +
  205 + for (let i in floorContent) {
  206 + if (floorContent.hasOwnProperty(i) && floorContent[i].id && floorContent[i].delete) {
  207 + deleteFloors.push(floorContent[i].id);
  208 + }
  209 + }
  210 +
  211 + return _.assign(resData, {
  212 + newFloors: newFloors.length ? JSON.stringify(newFloors) : '',
  213 + editFloors: editFloors.length ? JSON.stringify(editFloors) : '',
  214 + deleteFloors: deleteFloors.length ? JSON.stringify(deleteFloors) : ''
  215 + });
  216 + }
  217 +
  218 + function GenUploadedFn($dom, isThumb) {
  219 + if (isThumb) {
  220 + return function(url, isImg) {
  221 + if (!isImg) {
  222 + alert('请上传图片');
  223 + }
  224 +
  225 + $dom.prev().attr('src', url).removeClass('hide');
  226 + $dom.data('cover', url);
  227 + };
  228 + }
  229 +
  230 + return function(url, isImg) {
  231 + let cid = $dom.data('cid');
  232 + let info = floorContent[cid];
  233 + let type = isImg ? 'img' : 'video';
  234 + let $content = $dom.children('.item-content');
  235 +
  236 + info.newContent = url;
  237 +
  238 + if (info.type !== type || $content.hasClass('item-default')) {
  239 + info.type = type;
  240 + $content.remove();
  241 + $content.length = 0;
  242 + }
  243 +
  244 + if ($content.length) {
  245 + $content.attr('src', url);
  246 + return;
  247 + }
  248 +
  249 + console.log(isImg);
  250 + if (isImg) {
  251 + $dom.append(`<img src="${url}" class="item-content">`);
  252 + } else {
  253 + $dom.append(`<video src="${url}" class="item-content">您的浏览器不支持video标签。</video>`);
  254 + }
  255 + };
  256 + }
  257 +
  258 + $floorBox.children('.floor-item').each(() => {
  259 + let $this = $(this);
  260 + let data = $this.data();
  261 + let cid = generateCid(data.id);
  262 +
  263 + $this.data('cid', cid);
  264 + floorContent[cid] = data;
  265 + });
  266 +
  267 + if (typeof ($.fn.daterangepicker) !== 'undefined') {
  268 + $('#activityTime').daterangepicker({
  269 + timePicker: true,
  270 + timePickerIncrement: 30,
  271 + locale: {
  272 + format: 'YYYY-MM-DD HH:mm:ss'
  273 + }
  274 + });
  275 + }
  276 +
  277 + $('.btn-upload-thumb').on('click', function() {
  278 + uploadedFn = new GenUploadedFn($(this), true);
  279 + $upload[0].click();
  280 + });
  281 +
  282 + $('.floor-view-box').on('click', '.option-btns', function(e) {
  283 + if (e && e.stopPropagation) {
  284 + e.stopPropagation();
  285 + } else {
  286 + window.event.cancelBubble = true;
  287 + }
  288 +
  289 + let $this = $(e.target);
  290 + let $parent = $this.closest('.floor-item');
  291 +
  292 + if ($this.hasClass('up-item-btn')) {
  293 + $parent.prev().before($parent);
  294 + } else if ($this.hasClass('down-item-btn')) {
  295 + $parent.next().after($parent);
  296 + }
  297 + }).on('click', '.del-item-btn', function(e) {
  298 + if (e && e.stopPropagation) {
  299 + e.stopPropagation();
  300 + } else {
  301 + window.event.cancelBubble = true;
  302 + }
  303 +
  304 + let $this = $(this).closest('.floor-item');
  305 + let cid = $this.data('cid');
  306 +
  307 + if (floorContent[cid].id) {
  308 + floorContent[cid].delete = true;
  309 + } else {
  310 + delete floorContent[cid];
  311 + }
  312 +
  313 + $this.remove();
  314 + }).on('click', '.edit-text', function(e) {
  315 + if (e && e.stopPropagation) {
  316 + e.stopPropagation();
  317 + } else {
  318 + window.event.cancelBubble = true;
  319 + }
  320 + }).on('click', '.floor-item', function() {
  321 + let $this = $(this);
  322 + let data = $this.data();
  323 +
  324 + switch (data.type) {
  325 + case 'img':
  326 + case 'video':
  327 + uploadedFn = new GenUploadedFn($this);
  328 + $upload[0].click();
  329 + break;
  330 + default:
  331 + let info = floorContent[data.cid];
  332 + let content = info.newContent || info.content;
  333 + let $dom = $(`<textarea class="edit-text form-control">${content}</textarea>`);
  334 +
  335 + $dom.blur(function() {
  336 + let val = $dom.val();
  337 +
  338 + if (content !== val) {
  339 + info.newContent = val;
  340 + $this.children('.item-content').html(val);
  341 + }
  342 +
  343 + $dom.remove();
  344 + });
  345 +
  346 + $this.append($dom);
  347 + break;
  348 + }
  349 + });
  350 +
  351 + $('.btn-add-floor').on('click', function() {
  352 + let $this = $(this);
  353 + let data = {
  354 + cid: generateCid(),
  355 + type: $this.data('type')
  356 + };
  357 +
  358 +
  359 + let $addDom = $('<div class="floor-item">' +
  360 + '<p class="item-content item-default">' + typeName[data.type] + '</p>' +
  361 + '<div class="option-btns">' +
  362 + '<span class="glyphicon glyphicon-arrow-up up-item-btn"></span>' +
  363 + '<span class="glyphicon glyphicon-arrow-down down-item-btn"></span>' +
  364 + '</div>' +
  365 + '<span class="del-item-btn">删除</span>' +
  366 + '</div>');
  367 +
  368 +
  369 + $addDom.data(data);
  370 + floorContent[data.cid] = data;
  371 +
  372 + $floorBox.append($addDom);
  373 + });
  374 +
  375 + $('.btn-save-activity').on('click', function() {
  376 + let info = packInfo();
  377 +
  378 + if (!info || window.saveing) {
  379 + return;
  380 + }
  381 +
  382 + window.saveing = true;
  383 +
  384 + $.ajax({
  385 + method: 'post',
  386 + url: '/admin/activity/zerobuy/save',
  387 + data: info
  388 + }).then(res => {
  389 + window.saveing = false;
  390 + if (res.code === 200) {
  391 + alert('保存成功');
  392 + location.href = '/admin/activity/zerobuy/edit?id=' + res.data.id;
  393 + } else {
  394 + alert(res.message || '保存失败');
  395 + }
  396 + });
  397 + });
  398 +}
  399 +
  400 +if ($('.zerobuy-list-page').length) {
  401 + bindListPageEvent();
  402 +} else {
  403 + bindEditPageEvent();
  404 +}
  1 +@import '~bootstrap-daterangepicker';
  2 +
  3 +.floor-view-box {
  4 + min-height: 300px;
  5 + border: 1px solid #ccc;
  6 + border-radius: 4px;
  7 + margin-top: 30px;
  8 + margin-bottom: 30px;
  9 + padding: 0;
  10 +}
  11 +
  12 +.floor-item {
  13 + position: relative;
  14 + min-height: 100px;
  15 + background-color: #eee;
  16 +}
  17 +
  18 +.option-btns {
  19 + position: absolute;
  20 + top: 0;
  21 + right: 10px;
  22 + font-size: 20px;
  23 +}
  24 +
  25 +.option-btns > * {
  26 + display: inline-block;
  27 + width: 30px;
  28 + text-align: center;
  29 + cursor: pointer;
  30 +}
  31 +
  32 +.del-item-btn {
  33 + position: absolute;
  34 + top: 0;
  35 + right: -60px;
  36 + line-height: 30px;
  37 + width: 60px;
  38 + background-color: #d44950;
  39 + color: #fff;
  40 + text-align: center;
  41 + display: none;
  42 + cursor: pointer;
  43 +}
  44 +
  45 +.floor-item > textarea {
  46 + position: absolute;
  47 + top: 28px;
  48 + left: 0;
  49 + right: 0;
  50 + bottom: 0;
  51 +}
  52 +
  53 +.floor-item > img,
  54 +.floor-item > video {
  55 + width: 100%;
  56 +}
  57 +
  58 +.floor-item > p {
  59 + padding: 30px 10px;
  60 + text-align: center;
  61 + word-break: break-all;
  62 +}
  63 +
  64 +.floor-item:hover .del-item-btn {
  65 + display: block;
  66 +}