Skip to content

Instantly share code, notes, and snippets.

@kawaz
Last active Jul 6, 2021
Embed
What would you like to do?
ジョブカン勤怠の画面の使いづらいところを個人的に勝手に直すユーザスクリプト jobcan.user.js

インストール

TamperMonkey拡張をインストール済みのブラウザで以下URLを開くとユーザスクリプトのインストール承認画面が出てくると思う。 https://gist.githubusercontent.com/kawaz/8f08bbc218ab16b92f5e018801cec668/raw/jobcan.user.js

機能

  • 日付セレクタの -年-月-日 の『日』のセレクタに曜日表示をつけ足す
  • 打刻一覧テーブルで「修正レコードが全て承認された」という前提で以下の色つけなどをする
    • 『開始-終了』のペアが分かりやすいよう青のグラデーション背景にする
    • 『開始』で終わってる場合は赤くする(エラーなので
    • 削除レコードはグレーにする
    • 承認待ちレコードの左側を黄色くする(時間列がある左の辺りだけ見て分かるよう
  • 裏で noop API を定期で叩いてセッション切れを回避する

スクショ

Before After
jobcan-before jobcan-after
// ==UserScript==
// @name ジョブカン
// @namespace https://twitter.com/kawaz
// @version 1.1.10
// @description デザインを見やすくしたり色々
// @author kawaz
// @match https://ssl.jobcan.jp/*
// @match https://jobcan.ne.jp/*
// @grant none
// @updateURL https://gist.githubusercontent.com/kawaz/8f08bbc218ab16b92f5e018801cec668/raw/jobcan.user.js
// @downloadURL https://gist.githubusercontent.com/kawaz/8f08bbc218ab16b92f5e018801cec668/raw/jobcan.user.js
// @supportURL https://twitter.com/kawaz
// @require https://gist.githubusercontent.com/kawaz/804ddbcc7ddc5033d09d4e72fdcd3bf5/raw/tools.js?v=321
// ==/UserScript==
// ログインセッション維持
setInterval(() => fetch("https://ssl.jobcan.jp/employee/index/noop", { mode: "cors" }).then(r => r.json()).then(r => console.log({ noop: r })), 600 * 1000)
//トップとか管理者用ログインフォームとかは飛ばして従業員用ログインへ遷移
{
for (const p of [
`https://jobcan.ne.jp/`,
`https://ssl.jobcan.jp/login/client/?.*`,
]) {
if (new RegExp(`^${p}$`).test(location.href)) {
location.href = 'https://ssl.jobcan.jp/login/pc-employee/';
}
}
}
// 勤怠ログテーブルで未承認のレコードが承認されたとみなして勤務時間を見やすくする
const makeupLogsTable = () => {
[...document.querySelectorAll('#logs-table tr')]
.filter(tr => { if (/待ち/.test(tr.textContent)) { tr.querySelector('td').style.borderLeft = '5px solid orange' } return true })
.filter(tr => { if (/削除待ち/.test(tr.textContent)) { tr.style.backgroundColor = 'lightgray'; return false } return true })
.filter(tr => { if (/*時刻が<s>で打ち消されてるパターン*/tr.querySelector("s")) { tr.style.backgroundColor = 'lightgray'; return false } return true })
//始まりと終わりで背景色グラデーションの組を作る&最後が開始で終わってたら赤くする
.map((tr, i, all) => tr.style.background = `linear-gradient(${['lightblue,white', `white,light${i == all.length - 1 ? 'pink' : 'blue'}`][i % 2]}`)
}
if (new RegExp(`^/employee/adit/modify/?`).test(location.pathname)) {
makeupLogsTable()
//時刻入力欄にフォーカスする
ready("input[name=time]").then(e => {e.focus();console.log(e);e.value=''})
//修正フォームの打刻ボタンを押したら再度色つけ
document.querySelector("input[value=打刻]").addEventListener('click', () => setTimeout(makeupLogsTable, 2000))
//時刻入力欄でカンマを消す
document.querySelector("input[name=time]").addEventListener('keyup', e => e.target.value = e.target.value.replace(/(^|.* )(\d\d)/, '$2').replace(/[^0-9]/g, "").replace(/^(\d\d\d\d).*/, '$1'));
//時刻入力欄でEnterしたらsubmitする
[...document.querySelectorAll('input[name=time]')].map(i => i.addEventListener('keyup', e => { if (e.key == "Enter") { [...e.target.form.querySelectorAll("input[type=button],input[type=submit]")].filter(i => /打刻/.test(i.value)).map(i => i.click()); e.target.value=""} }));
//時刻入力で上下したら日付変更
document.querySelector("input[name=time]").addEventListener('keyup', e => {
const diff = { ArrowUp: -1, ArrowDown: 1 }[e.key]
if (diff) {
const day = document.querySelector("select[name=day]")
if (day) {
day.value = parseInt(day.value) + diff
day.form.submit()
}
}
})
}
// 勤怠ボタンページに今日のログテーブルを表示する
const updateLogsTable = async () => {
const logsPlaceholder = document.querySelector('#userjs-today-logs') || document.querySelector('.contents-wrap-middle').appendChild(Object.assign(document.createElement('div'), { id: 'userjs-today-logs' }))
const logsTableHTML = await fetch("https://ssl.jobcan.jp/employee/adit/modify/").then(r => r.text()).then(innerHTML => Object.assign(document.createElement('div'), { innerHTML })).then(d => d.querySelector("#logs-table")).then(d => d.outerHTML)
// ページの一部のHTMLをそのまま持ってきてもHTMLに付いてる onXX 系のイベントは動かないので削除する
logsPlaceholder.innerHTML = logsTableHTML.replace(/\son\w+=(["']).*?\1/g, '');
// 元々のイベントの代わりに打刻修正ページへページ移動するようにする
[...logsPlaceholder.querySelectorAll('a')].map(a => a.addEventListener('click', () => location.pathname = '/employee/adit/modify'))
makeupLogsTable()
}
if (location.pathname == '/employee') {
document.querySelector('#adit-button-push').addEventListener('click', () => setTimeout(updateLogsTable, 1000))
updateLogsTable()
}
//年月日のセレクタに曜日表示を追加する
{
[...document.querySelectorAll("select[name=year]+select[name=month]+select[name=day] option")].forEach(o => {
const y = parseInt(o.parentNode.parentNode.querySelector(`select[name=year]`).value)
const m = parseInt(o.parentNode.parentNode.querySelector(`select[name=month]`).value)
const d = parseInt(o.value)
const date = new Date(y, m - 1, d);
const youbi = "日月火水木金土".split("")[date.getDay()] || ""
o.innerText += ` (${youbi})`
})
}
//年月日のセレクタで日を変更したら自動サブミット
{
[...document.querySelectorAll("select[name=day]")].map(s => s.addEventListener("change", e => e.target.closest("form").submit()))
}
@kawaz

This comment has been minimized.

Copy link
Owner Author

@kawaz kawaz commented Aug 6, 2020

ちなみに従業員用の画面を想定してるので管理者の人が使うとどうなるかは不明です。管理者用のログインフォームをすっ飛ばしてるところとかは消さないと問題あると思います。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment