前回はアカウントページにログインユーザーの情報を出力したり、その情報を編集できるように実装しました。
今回はホーム画面の収支データ一覧をエクセルの形式で出力できるようにしたり、表最下行の合計金額を計算して表示するようにします。
↓前回の記事はこちら
収支データをエクセル形式で出力
画面に表示されている文の収支データをボタン1つでエクセル形式に出力できるようにします。
今回はjQueryにプラグインがあるのでそちらを使います。
まずは以下のファイルをダウロードし、JSディレクトリに格納します。
・TableExport.js(min.jsも可) GitHubはこちら
・FileSaver.js(min.jsも可) GitHubはこちら
・xlsx.core.min.js(min.jsも可) GitHubはこちら
ダウンロードとディレクトリへの格納ができたら、index.phpファイルにjQueryと各ファイルを読み込ませます。
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
<!--以下追加-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="./js/FileSaver.min.js"></script>
<script src="./js/xlsx.core.min.js"></script>
<script src="./js/tableexport.min.js"></script>
<!--追加ここまで-->
<script src="./js/radio.js"></script>
<script src="./js/import.js"></script>
<script src="./js/functions.js"></script>
</body>
収支データを出力しているtableタグに「table」というidを付与しています。
この要素に対して出力するボタンをつけるように実装していきます。
以下をJSファイル読み込みの下に追記します。
<script>
$(function() {
$("#table").tableExport({
formats: ["xlsx"], //エクスポートする形式
bootstrap: false, //Bootstrapを利用するかどうか
position: top
});
});
</script>
これで「Export to xlsx」というボタンは表示されるようになりますが、ボタンの文字を日本語にしたいので、もう1つボタンを作ってそちらで出力できるように実装します。
まずはtableタグの上にbuttonタグを含むdiv要素を追加します。
<!--以下追加-->
<div class="excel-button">
<button type="button" id="excelExport">Excel出力</button>
</div>
<!--追加ここまで-->
<table class="p-table p-table--record-output" id="table">
CSSはすでに指定しているので以下のようにボタンが2つ作られます。
今はまだ「Excel出力」に出力する機能がないので、機能を移していきます。
$('#excelExport').on('click', function() {
$('#table caption button').trigger('click');
});
緑背景の「Excel出力ボタン」が押されたら.triggerを使って本来の「Export to xlsx」が押されたときと同じイベントを起こすようにしました。
そして「Export to xlsx」ボタンは不要なので.hideで非表示にします。
$('#table caption').hide();
以上で「Excel出力」からエクセルファイル出力はできるようになったのですが、現在カテゴリーや支払い方法などをカッコ内に出力しているので、少し見辛い形で出力されてしまいます。
そのため、もう1つ非表示のテーブルを作りボタンが押されたらそちらのテーブルデータを出力するようにします。
まずは新しいテーブルを現在の収支データテーブルの下に作成します。
<!--idを空欄にする-->
<table class="p-table p-table--record-output" id="">
:
省略
:
</table>
<!--以下を追加-->
<table class="p-table p-table--hide" id="table">
<!-- タイトル行 -->
<tr>
<th>収支日</th>
<th>タイトル</th>
<th>カテゴリー</th>
<th>収入</th>
<th>支出</th>
<th>支払い方法</th>
<th>クレジットカード</th>
<th>スマホ決済</th>
</tr>
<!-- 収支データ出力 -->
<?php
$sql = 'SELECT records.id, records.date, records.title, records.amount, spending_category.name, income_category.name, records.type, payment_method.name, creditcard.name, qr.name, records.memo, records.input_time
FROM records
LEFT JOIN spending_category ON records.spending_category = spending_category.id
LEFT JOIN income_category ON records.income_category = income_category.id
LEFT JOIN payment_method ON records.payment_method = payment_method.id
LEFT JOIN creditcard ON records.credit = creditcard.id
LEFT JOIN qr ON records.qr = qr.id
WHERE records.date >=? AND records.date <=? AND records.user_id = ?
ORDER BY date DESC, input_time DESC';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssi', $searchDateFrom, $searchDateTo, $user_id);
$success = $stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows();
$stmt->bind_result(
$id,
$date,
$title,
$amount,
$spending_category,
$income_category,
$type,
$paymentmethod,
$credit,
$qr,
$memo,
$input_time
); ?>
<?php while ($stmt->fetch()) : ?>
<tr>
<td><?php echo date($date); ?></td>
<td><?php echo h($title); ?></td>
<td>
<?php
if ($type === 0 && $spending_category !== null) {
echo h($spending_category);
} else if ($type === 1 && $income_category !== null) {
echo h($income_category);
} else {
echo "不明";
}
?>
</td>
<td>
<?php echo $type === 1 ? '¥' . number_format(h($amount)) : ''; ?>
</td>
<td>
<?php echo $type === 0 ? '¥' . number_format($amount) : ''; ?>
</td>
<td><?php echo $type === 0 ? $paymentmethod : ''; ?></td>
<td>
<?php echo $paymentmethod === "クレジット" ? h($credit) : '' ?>
</td>
<td>
<?php echo $paymentmethod === "スマホ決済" ? h($qr) : '' ?>
</td>
</tr>
<?php endwhile; ?>
<!-- //収支データ出力 -->
</table>
<!--追加ここまで-->
既にCSSで非表示の指定をしているので、画面上には表示されません。
また同時に「table」のidを非表示のtableの方に移したので、「Excel出力」を押すと非表示の表のデータがダウンロードされます。
以上でエクセル出力の実装は完了です。
合計金額の計算
以下画像の赤枠が表示しているデータの合計金額orユーザーの初期貯蓄額から全収支データを計算した金額になるように実装します。
まずは現在の貯蓄額をユーザーの初期貯蓄額とこれまでの収支データを計算した結果を出力するようにします。
以下を貯蓄額出力の<th>の前に追記します。
<!--235行目付近-->
<?php
//支出収支金額の抽出
$sql = "SELECT (SELECT SUM(amount) FROM records WHERE type = 0 AND user_id = ?)AS spending, (SELECT SUM(amount) FROM records WHERE type = 1 AND user_id = ?)AS income FROM records WHERE user_id = ? LIMIT 1";
$stmt = $db->prepare($sql);
$stmt->bind_param('iii', $user_id, $user_id, $user_id);
sql_check($stmt, $db);
$stmt->bind_result($spending_amount, $income_amount);
while($stmt->fetch()):
$sum = $income_amount - $spending_amount;
endwhile;
//貯蓄額の計算
$all_sum = $initial_savings + $sum;
$abs_all_sum = abs($all_sum);
if ($all_sum < 0) :
$sign = "-";
else :
$sign = '';
endif;
?>
まず収入金額と支出金額を抽出するSQLを発行します。このSQLは副問合せで支出の合計と収入の合計を抽出しています。
その後はこれまでにも実装した流れと同じです。SQLの抽出結果を取得したらそれを計算して、ユーザーが登録しているデータの中だけで計算をまず行なっています。
ユーザーが登録した収支データの計算をしたあと、アカウントページから確認・編集できる「初期貯蓄額」から計算をし、現在の貯蓄額を$all_sumとして格納しています。
現在の貯蓄額が計算できたら、一度計算結果を絶対値にして$abs_all_sumに格納しています。これは計算結果がマイナス値になった際に、マイナス符号が出力されるのを防ぐためです。
それではマイナスになったときはどう処理をするかというのが、一番下のif文内の処理です。絶対値にする前の$all_sumがマイナス値かプラス値かで条件を置き、$signにマイナスのときに符号を格納しておきます。
ここまでで現在の貯蓄額の計算が完了しました。続いて計算結果を実際に出力します。
<th colspan="6">現在の貯蓄額<span class=""><?php echo $sign . '¥' . number_format($abs_all_sum); ?></span></th>
$signと「¥」、計算結果の$abs_all_sumを連結して出力します。
ユーザーの情報から計算した結果が出力されました。
この表はPCのときの表示なので、スマホの際の貯蓄額計算も実装します。
SQLの発行や実行は一度行っているのでもう一度同じものを記述する必要はありません。
<!--467行目付近-->
<p class="p-sp-data-box__head">現在の貯蓄額<span class=""><?php echo $sign . '¥' . number_format($abs_all_sum); ?></span></p>
続いて表最下段の収入のみや支出のみの計算結果や、それらを計算した指定範囲内の収支合計が出力されるように実装します。
まずは収入のみと支出のみの計算結果の出力を実装します。
<!--365行目付近から-->
<?php
$sql = 'SELECT (SELECT SUM(amount) FROM records WHERE type=1 AND user_id = ? AND date>= ? AND date<=?) AS income, (SELECT SUM(amount) FROM records WHERE type=0 AND user_id = ? AND date>= ? AND date<=?) AS spending FROM records WHERE user_id = ? AND date>= ? AND date<=? LIMIT 1';
$stmt->prepare($sql);
$stmt->bind_param('issississ', $user_id, $searchDateFrom, $searchDateTo, $user_id, $searchDateFrom, $searchDateTo, $user_id, $searchDateFrom, $searchDateTo);
sql_check($stmt, $db);
$stmt->bind_result($income_search, $spending_search);
while($stmt->fetch()):
$sum_search = $income_search - $spending_search;
endwhile;
?>
<tr class="p-table__foot">
<th colspan="2">合計金額 </th>
<!--書き換えここから-->
<th class="text-blue">
<?php echo '¥' . number_format($income_search); ?>
</th>
<th class="text-red">
<?php echo '-¥' . number_format($spending_search); ?>
</th>
<!--書き換えここまで-->
<th colspan="2" class="text-blue">合計 +¥197,000</th>
</tr>
抽出のSQLは副問合せをしているので、かなり長くなっています。
それぞれ該当の日付範囲内の支出金額or収入金額を合計した値のカラムを抽出しています。SQLの発行から実行まではいつも通りです。
抽出した値を取得したらfetchでデータを回し、この後実装する日付範囲内の収支合計金額を計算し「$sum_search」に格納しています。
そしてそれぞれのthタグ内に合計金額を出力したら、収支ごとの合計金額計算は完了です。
最後に日付指定範囲内の収支合計を計算した値を出力します。
$sum_search = $income_search - $spending_search;
$stmt->close();
//以下追記
$abs_sum_search = abs($sum_search);
if ($sum_search >= 0) :
$sign_search = '';
$class = 'text-blue';
else :
$sign_search = '-';
$class = 'text-red';
endif;
//追記ここまで
?>
<!--書き換え前 391行目付近-->
<th colspan="2" class="text-blue">合計 +¥197,000</th>
<!--書き換え後-->
<th colspan="2" class="<?php echo $class; ?>">
合計 <?php echo $sign_search . '¥' . number_format($abs_sum_search); ?>
</th>
先程の貯蓄額の計算部分と同様に、出力用に絶対値を格納した変数を用意します。
その後、if分で計算した値が0以上であるかを条件に置き、thタグのクラス属性に出力するテキスト色を指定する文字列や、符号を格納しておきます。
最後にthタグに符号や合計金額を出力したら完了です。
スマホ版も同様のプログラムで実装していきます。
<!--496行目付近-->
<ul class="p-sp-data-box__item-sum">
<li>収入<br><span class="text-blue"><?php echo '¥' . number_format($income_search); ?></span></li>
<li>支出<br><span class="text-red"><?php echo '-¥' . number_format($spending_search); ?></span></li>
<li>合計<br><span class="<?php echo $class; ?>"><?php echo $sign_search . '¥' . number_format($abs_sum_search); ?></span></li>
</ul>
日付範囲をセッションで記憶する
現在、日付検索の値が他ファイルに遷移するとリセットされてしまいます。
これをセッションに保存して他ページに遷移しホームに戻ってきたときも日付指定が保持されるように実装していきます。
まずはindex.phpに「検索」または「全表示」が押されたときの処理を少し修正します。
//8行目付近
if (isset($_POST['search']) && isset($_POST['date-search'])) :
//検索が押されたときの処理
$date_from = filter_input(INPUT_POST, 'date_from', FILTER_SANITIZE_SPECIAL_CHARS);
$date_to = filter_input(INPUT_POST, 'date_to', FILTER_SANITIZE_SPECIAL_CHARS);
$_SESSION['searchDateFrom'] = $date_from; //書き換え
$_SESSION['searchDateTo'] = $date_to; //書き換え
elseif (isset($_POST['search']) && isset($_POST['all-search'])) :
//全表示押下の処理
$_SESSION['searchDateFrom'] = ''; //書き換え
$_SESSION['searchDateTo'] = date('Y-m-d'); //書き換え
endif;
これまで送信された日付を変数に入れていましたが、$_SESSION[‘ ‘]に変更しました。
またもとのプログラムにはelseの処理を記述していましたが、不要になるので削除しています。
続いてセッション処理を上記のプログラムの下に追記します。
//日付指定セッション処理(23行目付近に追記)
if (isset($_SESSION['searchDateFrom']) && isset($_SESSION['searchDateTo'])) :
$searchDateFrom = $_SESSION['searchDateFrom'];
$searchDateTo = $_SESSION['searchDateTo'];
else :
$searchDateFrom = date('Y-m-01');
$searchDateTo = date('Y-m-d');
endif;
$_SESSION[‘ ‘]のままでは、データ抽出のSQLや日付入力inputに値が渡らずエラーを起こすので、セッションがあるときはその値をこれまで使っていた変数に格納して保存します。
他ページに遷移した後、ホームに戻ってきても日付範囲が保持されるようになりました。
最後に
今回は画面に表示されている収支データをボタン1つでエクセル形式で出力できるようにしたり、表内の合計金額を計算結果を表示するようにしました。
またおまけの小さな修正で、日付指定をセッションで保存するように変更しました。
最後までお読みいただきありがとうございました。
コメント