LoginSignup
11
1

More than 1 year has passed since last update.

アプリ内検索に入力された検索ワードを伝えたい

Last updated at Posted at 2022-12-02

はじめに

自己紹介

刷毛.jpg

  • イシイケンタロウですハケをつくっている会社の兼業情シスです
  • kintone触る係をしてます認定資格5つ持ち&公認Evangelistです

資格ロゴ統合.png

  • その他にITストラテジストやシステム監査技術者などの国家資格をいくつか取得しています
  • kintoneのカスタマイズは社内向けのみで、プラグインは作ってません(作れません)

やりたいこと

  • アプリ内検索でどのような単語で検索されているのかをいまから検索する人に伝えたい
  • 「へぇーみんなは最近こんな単語を検索してるのかーなるほどねー」と思ってくれるハズ

考え方

  • 右上のkintone標準検索ボックスと同じ機能の検索ボックスをメニュー位置に作成する
  • 作成した検索ボックスクリック時にアプリ内検索に入力された検索ワードを調べたいで貯めた検索ワードの直近何件かを表示する
  • アクセスログから取得するので検索成功した検索ワードしか出てこない(良いか悪いかわからないけど

完成!

無題.png

  • 見た目をkintoneライクにするため ui component v1 を使いたかったんですが、list属性を付与する方法がわかりませんでした(v0 だとできるんだけど現在はメンテナンスモード)
  • それならばと51-modern-default.cssを使おうとしたけど今度はdisplayにinline-blockを適用する方法がわからなかった(floatをleftにすることもできなかった)
  • ということで旧来システムみが溢れるテキストボックスとボタンですご容赦ください🙇‍♂️

検索対象アプリ

  • 2年前の使いまわしです
  • 質問を投稿し、コメントで回答するアプリです
  • アプリ内検索は添付ファイルの中身(の一部)やコメントも検索してくれます
フィールド名 / フィールドコード フィールドタイプ
質問内容 文字列(複数行)
添付ファイル 添付ファイル

アクセスログアプリ

  • こちらも使いまわしです
  • 1アクセスごとに1レコードを新規登録します
フィールド名 / フィールドコード フィールドタイプ
keyword 文字列(1行)
accessUrl 文字列(1行)

検索対象アプリに実装

アクセスログアプリのアプリIDだけ書き換えてください


(() => {
  'use strict';
/**
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
●              定数および無名即時関数スコープ変数の宣言
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
// アクセスログアプリのアプリID
const accessLogAppId = XXX;

/**
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
●                        function                          
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/	
/**
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
▼             アクセスログアプリへ登録する関数                          
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/
const postLog = async () => {
  
  // keywordの抽出(「&s.keyword=」の次の文字から「&s.app」の手前の文字まで)
  let keyword = '';
  if (location.href.match(/s.keyword/)){
      const indexStart = location.href.indexOf('&s.keyword=') + '&s.keyword='.length;
      const indexEnd = location.href.indexOf('&s.app');
      keyword = decodeURI(decodeURI(location.href.substring(indexStart, indexEnd)));
  }

  // アクセスログアプリへの登録
  const paramPost = {
      'app': accessLogAppId,
      'record': {
          'accessUrl': {
              'value': location.href
          },
          'keyword': {
              'value': keyword
          }
      }
  };
  const respPost = await kintone.api(kintone.api.url('/k/v1/record', true), 'POST', paramPost);
}
/**
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
▼             検索ワードリストを作成する関数                          
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/
const makeSearchWords = async () => {
  // アクセスログアプリから検索ワードを取得する(API仕様に任せて最大500件)
  const paramGet = {
      'app': accessLogAppId,
      'fields': ['keyword'],
      'query': 'accessUrl like "https://' + location.hostname + '/k/' + kintone.app.getId() + '/" and accessUrl like "s.keyword"'
  };
  const respGet = await kintone.api(kintone.api.url('/k/v1/records', true), 'GET', paramGet);
  
  // 重複を排除して配列に変換する
  const respArray = [];
  respGet.records.forEach((record) => {
      respArray.push(record.keyword.value);
  });
  const wordList = [...new Set(respArray)];
    
  return wordList;  
};

/**
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
▼              検索ボックスを配置する関数                          
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
*/
const makeSearchBox = async (event) => {
  
  // 増殖バグ回避
  if(document.getElementById('divSearchBox')){
      return;
  }
  
  // ヘッダースペース(一覧画面と詳細画面で配置場所分岐制御)
  let spaceHeader;
  if(event.type === 'app.record.index.show'){
    spaceHeader = kintone.app.getHeaderMenuSpaceElement();
  }else{
    spaceHeader = kintone.app.record.getSpaceElement('searchBoxSpace');
  }

  // 検索窓div
  const divSearchBox = document.createElement('div');
  divSearchBox.id = 'divSearchBox';

  // 検索ワードdatalist
  const wordList = document.createElement('datalist');
  wordList.id = 'wordList';
  const words = await makeSearchWords();
  words.forEach((word) => {
    const option = document.createElement('option');
    option.value = word;
    wordList.appendChild(option);
  });
  divSearchBox.appendChild(wordList);
  
  // 検索窓text
  const searchBoxText = document.createElement('input');
  searchBoxText.setAttribute('id', 'searchBoxText');
  searchBoxText.setAttribute('type', 'text');
  searchBoxText.setAttribute('list','wordList');
  divSearchBox.appendChild(searchBoxText);

  // 検索button
  const searchBoxButton = document.createElement('button');
  searchBoxButton.setAttribute('class', 'kintoneplugin-button-dialog-ok');
  searchBoxButton.innerText = '検索';
  const getTextBoxValue = () => {
    const textBoxValue = document.getElementById('searchBoxText').value;
    location.href = 'https://' + location.hostname + '/k/search?keyword=' + textBoxValue + '&app=' + kintone.app.getId();
  };
  searchBoxButton.addEventListener('click', getTextBoxValue);
  divSearchBox.appendChild(searchBoxButton);

  // ヘッダーに検索divを配置
  spaceHeader.appendChild(divSearchBox);

};
/**
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
●                         event
● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
*/
kintone.events.on(['app.record.index.show', 'app.record.detail.show'], (event) => {
  // アクセスログアプリへの登録
  postLog();   
  // 検索ボックスの配置
  makeSearchBox(event);
});

})();



おわりに

  • 月刊イシイケンタロウ12月号です
  • ただでさえ遅筆なのにQiita記事久しぶりなのでものすごく時間かかりました
  • 苦闘してたのは2ヶ月近く前でしたw

  • ui component v1 のアップデート期待してます
  • 弊社来年4月に大阪で展示会やります!宣伝!
  • 私も行くので4/1夜お会いできる方募集したいところですが宿がどこだかわからないw
    Fes43.png
11
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
1