kintone活动日历插件的作成范例【前篇】

cybozu发表于:2016年11月25日 14:22:11更新于:2020年09月09日 14:10:44

概要

关于开发插件所需的文件以及插件的打包方法请参考kintone插件开发流程

本次以“kintone日历活动插件”为例,向大家介绍插件的做成方法。

步骤0.准备插件用的应用

关于应用必须的设置,请参考kintone日历活动插件的设置表单。

0015ecb59fe232cb67de1ab1b4ddbf0

步骤1.准备做成插件所需的文件

根据kintone 插件开发流程,我们来作成文件。

图标文件

使用画图软件作成下面这样的图标文件。

文件名叫“colorful-weekly.png”。

0015ecb5a3f92971c16949e1d40243d

前台PC专用JavaScript文件

重点

  • kintone.plugin.app.getConfig()获取插件的设置信息。

  • 应用列表页面
    - 从插件设置信息中获取列表,用FullCalendar并将其显示成日历形式(可切换显示日/周/月)。
    - 更改活动的时间时,更新相应的数据。
    - 根据插件的设置信息,流程管理状态按照指定的颜色显示。

  • 记录编辑页面/记录添加页面/列表编辑页面
    - 控制活动开始时间和结束时间的输入

  • 时间格式等的处理用了Moment

/*
 * eventCalendar Plug-in
 * Copyright (c) 2016 Cybozu
 *
 * Licensed under the MIT License
 */
jQuery.noConflict();
(function($, PLUGIN_ID) {
    'use strict';

    // 根据用户设置的语言切换显示中/日
    function createMultilingual(num){
        var user_lang = kintone.getLoginUser().language;
        var multilingual = {
            'ja':{
                '1': 'YYYY年M月',
                '2': 'YYYY年 M月 D日',
                '3': 'YYYY年 M月 D日[(]ddd[)]',
                '4':'今日',
                '5': '月',
                '6': '週',
                '7': '日',
                '8': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
                '9': ['日曜', '月曜', '火曜', '水曜', '木曜', '金曜', '土曜'],
                '10': ['日', '月', '火', '水', '木', '金', '土'],
                '11': 'すべて見る',
                '12':'未入力項目があります',
                '13': '必須です',
                '14': '開始日時が終了日時より未来になっています',
                '15': '終了日時より過去にして下さい',
                '16': '開始日時より未来にして下さい',
                '17': '開始日時と終了日時は1分以上あけて下さ'
            },
            'zh':{
                '1': 'YYYY年M月',
                '2': 'YYYY年 M月 D日',
                '3': 'YYYY年 M月 D日[(]ddd[)]',
                '4':'今天',
                '5': '月',
                '6': '周',
                '7': '日',
                '8': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
                '9': ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
                '10': ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
                '11': '显示全部',
                '12':'有必填项未填',
                '13': '必填',
                '14': '开始时间比结束时间晚',
                '15': '请选择比结束时间早的时间',
                '16': '请选择比开始时间晚的时间',
                '17': '开始时间和结束时间必须间隔至少1分钟'
            }
        };
        if(!multilingual[user_lang]) {
            user_lang = 'ja';
        }
        return multilingual[user_lang][num];
    }

    // 在日历上更改活动时间时的更新处理
    function putRecord(event) {
        var putConfig = kintone.plugin.app.getConfig(PLUGIN_ID);
        var stdtKey = putConfig.start_datetime;
        var eddtKey = putConfig.end_datetime;

        kintone.api('/k/v1/record', 'PUT', {
            'app': kintone.app.getId(),
            'id': event.rec,
            'record': (function() {
                var param = {};
                param[stdtKey] = {
                    'value': moment(event.start).add(-9, 'hours').format('YYYY-MM-DDTHH:mm:ssZ')
                };
                param[eddtKey] = {
                    'value': moment(event.end).add(-9, 'hours').format('YYYY-MM-DDTHH:mm:ssZ')
                };
                return param;
            })()
        });
    }

    // 获取所有记录的函数
    function fetchRecords(appId, query, opt_offset, opt_limit, opt_records) {
        var offset = opt_offset || 0;
        var limit = opt_limit || 500;
        var allRecords = opt_records || [];
        var params = {app: appId, query: query + ' limit ' + limit + ' offset ' + offset};
        return kintone.api('/k/v1/records', 'GET', params).then(function(resp) {
            allRecords = allRecords.concat(resp.records);
            if (resp.records.length === limit) {
                return fetchRecords(appId, query, offset + limit, limit, allRecords);
            }
            return allRecords;
        });
    }

    // 显示记录列表页面时的处理
    kintone.events.on('app.record.index.show', function(event) {
        var config = kintone.plugin.app.getConfig(PLUGIN_ID);
        if (!config) {
            return false;
        }

        new kintone.Promise(function(resolve, reject) {

            var evTitle = config.name;
            var evStart = config.start_datetime;
            var evEnd = config.end_datetime;

            var startDate;
            var endDate;

            fetchRecords(kintone.app.getId(), '').then(function(calRecords) {

                var records = calRecords;
                var recEvents = [];
                // 当有记录存在时循环以下处理
                if (records.length !== 0) {
                    for (var i = 0; i < records.length; i++) {
                        startDate = moment(records[i][evStart].value);
                        endDate = moment(records[i][evEnd].value);

                        // 当活动背景设设置有误或流程管理功能未启用时默认显示蓝色
                        var eventColor = '#0000ff';
                        // 设置活动背景色的处理
                        var eventStatus
                        var flag = false;
                        if(typeof (records[i].ステータス) !== 'undefined') {
                            eventStatus = records[i].ステータス.value;
                        } else if(typeof (records[i].状态) !== 'undefined'){
                            eventStatus = records[i].状态.value;
                        } else if(typeof (records[i].Status) !== 'undefined') {
                            eventStatus = records[i].Status.value;
                        } else {
                            flag = true;
                        }

                        if(flag === false) {
                            for (var k = 1; k < 6; k++) {
                                var stsPropName = 'status' + k;
                                var clrPropName = 'color' + k;
                                var status = config[stsPropName];
                                if (status === eventStatus) {
                                    eventColor = config[clrPropName];
                                    break;
                                }
                            }
                        }

                        recEvents.push({
                            title: records[i][evTitle].value,
                            start: startDate.format('YYYY-MM-DD HH:mm:ss'),
                            end: endDate.format('YYYY-MM-DD HH:mm:ss'),
                            url: location.protocol + '//' + location.hostname + '/k/' +
                                kintone.app.getId() + '/show#record=' + records[i].$id.value,
                            rec: records[i].$id.value,
                            backgroundColor: eventColor,
                            borderColor: eventColor
                        });
                    }
                }

                // 设置日历
                $('#calendar').fullCalendar({
                    lang: 'ja',
                    theme: false,
                    // 顶部的按钮和标题
                    header: {
                        left: 'prev,next, today',
                        center: 'title',
                        right: ' month,agendaWeek,agendaDay'
                    },
                    // 日历按日显示时
                    columnFormat: {
                        month: 'ddd',
                        week: 'M/D[(]ddd[)]',
                        day: 'M/D[(]ddd[)]'
                    },
                    // 日历的标题
                    titleFormat: {
                        month: createMultilingual('1'),
                        week: createMultilingual('2'),
                        day: createMultilingual('3')
                    },
                    // 按钮里的字符
                    buttonText: {
                        prev: '<',
                        next: '>',
                        today: createMultilingual('4'),
                        month: createMultilingual('5'),
                        week: createMultilingual('6'),
                        day: createMultilingual('7')
                    },
                    // 使用以周日为起始日的日历
                    firstDay: '0',
                    // 显示周末(周六,周日)
                    weekends: true,
                    // 默认按月显示
                    defaultView: 'month',
                    // 月的处理
                    monthNames: createMultilingual('8'),
                    monthNamesShort: createMultilingual('8'),
                    // 周的处理
                    dayNames: createMultilingual('9'),
                    dayNamesShort: createMultilingual('10'),
                    // 各日历的时间格式
                    axisFormat: 'H:mm',
                    timeFormat: 'H:mm',
                    // 在日历上编辑活动
                    editable: true,
                    durationEditable: true,
                    startEditable: true,
                    unselectAuto: true,
                    unselectCancel: '',
                    dragRevertDuration: 100,
                    // 不显示一整天的预定
                    allDaySlot: false,
                    // 使用以0点为一天的起点的日历
                    nextDayThreshold: '00:00:00',
                    // 日历的高度
                    height: 700,
                    contentHeight: 600,
                    // 时间轴的单位
                    slotDuration: '01:00:00',
                    // 拉动条状移动时,按每几分为单位移动
                    snapDuration: '01:00:00',
                    // 按日显示时的详细显示
                    views: {
                        day: {
                            slotDuration: '00:30:00',
                            snapDuration: '00:30:00',
                            scrollTime: '06:00:00'
                        }
                    },
                    minTime: '00:00:00',
                    maxTime: '24:00:00',
                    // 初始时间位置
                    scrollTime: '00:00:00',
                    // 按月显示时,活动如果太多省略显示不下的部分
                    eventLimit: true,
                    eventLimitText: createMultilingual('11'),
                    eventResize: function(ev, delta, revertFunc, jsEvent, ui, view) {
                        putRecord(ev);
                        $('#calendar').fullCalendar('unselect');
                    },
                    eventDrop: function(ev, delta, revertFunc, jsEvent, ui, view) {
                        putRecord(ev);
                        $('#calendar').fullCalendar('unselect');
                    },
                    eventSources: [{
                        events: recEvents
                    }]
                });
                resolve(event);
            });
        }).then(function() {
            return event;
        });
    });


    // 添加记录・编辑记录・在列表页面编辑记录时
    kintone.events.on(['app.record.create.submit', 'app.record.edit.submit',
        'app.record.index.edit.submit'], function(event) {
        var record = event.record;

        var config = kintone.plugin.app.getConfig(PLUGIN_ID);
        if (!config) {
            return false;
        }

        var evTitleVal = record[config.name].value;
        var evStartVal = record[config.start_datetime].value;
        var evEndVal = record[config.end_datetime].value;

        // 活动标题・活动开始/结束时间不可为空
        if (!evTitleVal || !evStartVal || !evEndVal) {
            event.error = createMultilingual('12');
            if (!evTitleVal) {
                record[config.name].error = createMultilingual('13');
            }
            if (!evStartVal) {
                record[config.start_datetime].error = createMultilingual('13');
            }
            if (!evEndVal) {
                record[config.end_datetime].error = createMultilingual('13');
            }
        // 开始时间晚于结束时间时报错
        } else if (moment(evStartVal).format('X') > moment(evEndVal).format('X')) {
            event.error = createMultilingual('14');
            record[config.start_datetime].error = createMultilingual('15');
            record[config.end_datetime].error = createMultilingual('16');
        // 开始时间和结束时间相同时报错(FullCalendar规格上的要求)
        } else if (moment(evStartVal).format('X') === moment(evEndVal).format('X')) {
            event.error = createMultilingual('17');
            record[config.start_datetime].error = createMultilingual('15');
            record[config.end_datetime].error = createMultilingual('16');
        }

        return event;

    });

})(jQuery, kintone.$PLUGIN_ID);

以上代码另存为desktop.js,文字编码设为UTF-8,保存。

前台PC专用CSS文件

对日历列表上的周六/周日和当天等的背景色进行设置。

将以下文件保存为customize.css

/* 周日 */
.fc-head .fc-sun {
    background: rgb(250, 220, 233);
}

/* 周六 */
.fc-head .fc-sat {
    background: rgb(211, 237, 251);
}

/* 今日 */
.fc-today {
    background: rgb(255, 255, 204);
}

.fc-center {
    margin-right: 1.75em;
}

.fc-clear {
    clear: none;
}

另外还用到了FullCalendar库提供的CSS,在后面的资源配置文件中会将其链接添加进去。此处无需做处理。

前台智能手机端专用JavaScript文件

本次省略。

后台设置页面的HTML文件

这次我们将创建一个设置页面的HTML文件。
设置页面上,放置3个下拉框,可分别从应用表单选择一个字段作为活动标题,活动的开始时间和结束数据。还有一个5行列表,可最多对5个流程管理的状态分别设置背景色

重点

  • 设置页面的HTML可以只写正文(body)内容。

  • 本次为了实现可以根据用户设置的语言自动切换中文和日文的功能,使用jsrender库将设置页面上的文字放到JavaScript文件的变量里,然后在HTML里调用该变量。

<!--    
* eventCalendar Plug-in    
* Copyright (c) 2016 Cybozu    
*    
* Licensed under the MIT License    
-->    
<div id="EventCalendarPlugin">    
  <div class="block">    
    <label class="kintoneplugin-label">    
      <span id ="container_label">{{html:terms.event_title}}</span>    
      <span class="kintoneplugin-require">*</span>    
    </label>    
    <div class="kintoneplugin-row">{{html:terms.event_title_description}}</div>    
    <div class="kintoneplugin-select-outer">    
      <div class="kintoneplugin-select">    
        <select id="name_code">    
        </select>    
      </div>    
    </div>    
  </div>    
  <div class="block">    
    <label class="kintoneplugin-label">    
      <span id ="container_label">{{html:terms.start_dateTime}}</span>    
      <span class="kintoneplugin-require">*</span>    
    </label>    
    <div class="kintoneplugin-row">{{html:terms.start_dateTime_description}}</div>    
    <div class="kintoneplugin-select-outer">    
      <div class="kintoneplugin-select">    
        <select id="start_datetime_code">    
        </select>    
      </div>    
    </div>    
  </div>    
  <div class="block">    
    <label class="kintoneplugin-label">    
      <span id ="container_label">{{html:terms.end_dateTime}}</span>    
      <span class="kintoneplugin-require">*</span>    
    </label>    
    <div class="kintoneplugin-row">{{html:terms.end_dateTime_description}}</div>    
    <div class="kintoneplugin-select-outer">    
      <div class="kintoneplugin-select">    
        <select id="end_datetime_code">    
        </select>    
      </div>    
    </div>    
  </div>    
  <div class="block">    
    <label class="kintoneplugin-label">    
      <span id ="container_label">{{html:terms.background}}</span>    
    </label>    
    <div class="kintoneplugin-row">{{html:terms.background_description}}</div>    
      <div class="kintoneplugin-input-outer">    
        <table>    
          <tr style="background:#ccccff">    
            <th>No.</th>    
            <th>{{html:terms.background_status}}</th>    
            <th>{{html:terms.background_color}}</th>    
          </tr>    
          <tr>    
            <td>1</td>    
            <td><input id="status1" class="kintoneplugin-input-text"></input>    
            </td>    
            <td><input id="color1" class="kintoneplugin-input-text"></input>    
            </td>    
          </tr>    
          <tr>    
            <td>2</td>    
            <td><input id="status2" class="kintoneplugin-input-text"></input>    
            </td>    
            <td><input id="color2" class="kintoneplugin-input-text"></input>    
            </td>    
          </tr>    
          <tr>    
            <td>3</td>    
            <td><input id="status3" class="kintoneplugin-input-text"></input>    
            </td>    
            <td><input id="color3" class="kintoneplugin-input-text"></input>    
            </td>    
          </tr>    
          <tr>    
            <td>4</td>    
            <td><input id="status4" class="kintoneplugin-input-text"></input>    
            </td>    
            <td><input id="color4" class="kintoneplugin-input-text"></input>    
            </td>    
          </tr>    
          <tr>    
            <td>5</td>    
            <td><input id="status5" class="kintoneplugin-input-text"></input>    
            </td>    
            <td><input id="color5" class="kintoneplugin-input-text"></input>    
            </td>    
          </tr>    
        </table>    
      </div>    
  </div>    
<div class="block">    
    <button type="button" id="submit" class="kintoneplugin-button-dialog-ok">{{html:terms.save_button}}</button>    
    <button type="button" id="cancel" class="kintoneplugin-button-dialog-cancel">{{html:terms.cancel_button}}</button>    
  </div>    
</div>

单独一个HTML文件在浏览器上打开时显示如下。

0015ecc7dbacb231c683320aeba9738

插件打包后,HTML文件会读取Javascript文件中含有设置页面文字的变量,显示结果如下。

0015ecc7e5800aab5de3945f033ee2d

写完之后,以UTF-8的格式保存。文件名为“config.html"。

后续请点击【kintone活动日历插件的作成范例【后篇】

回复(2)

  • betsy_yan

    你好,打包规则已经更新了,你可以参考以下内容:

    https://developer.cybozu.io/hc/ja/articles/360000910783#step6

    https://developer.cybozu.io/hc/ja/articles/360000975763

    我们会及时更新中文网站,敬请期待。

    引用 closer 的回复:

    keys/   - check_plugin.hkfgjeehkaajnbmfojmpbgcpfalbfhjn.ppk //密钥文件 plugins/   /hkfgjeehkaajnbmfojmpbgcpfalbfhjn   - plugin.zip //打包好的文件请问,最后那个打包好的文件,没有出现是为什么,前面都是按照步骤做的

  • closer
    keys/
      - check_plugin.hkfgjeehkaajnbmfojmpbgcpfalbfhjn.ppk //密钥文件
    plugins/
      /hkfgjeehkaajnbmfojmpbgcpfalbfhjn
      - plugin.zip //打包好的文件

    请问,最后那个打包好的文件,没有出现是为什么,前面都是按照步骤做的