開発tax-assistantメモ
Vue.jsで重複チェック画面をテーブル形式に刷新
tax-assistantの重複レシートチェック画面(DuplicateView.vue)を大幅に改善した。
改善の背景
従来のカード形式UIでは以下の問題があった。
- 同じhash_idを持つレシート群の関連性が視覚的にわかりにくい
- 一覧性が低く、多数の重複候補がある場合にスクロールが多発
- 画像プレビューが別画面遷移で、確認作業が煩雑
実装した機能
1. テーブル形式への変更
カード形式からテーブル形式に変更し、一覧性を向上させた。
Before(カード形式)
- 各レシートが個別カードで表示
- グループの境界が不明確
- 縦に長いスクロールが必要
After(テーブル形式)
- 行ごとにレシート情報を表示
- グループヘッダーで関連レシートを明示
- コンパクトな表示で一覧性向上
2. グループ単位の表示
同じhash_idを持つレシートをグループ化して表示する機能を実装した。
// hash_idでレシートをグループ化
const groupedReceipts = computed(() => {
const groups = new Map<string, Receipt[]>();
receipts.value.forEach(receipt => {
const hashId = receipt.hash_id;
if (!groups.has(hashId)) {
groups.set(hashId, []);
}
groups.get(hashId)!.push(receipt);
});
return groups;
});
グループ選択時にはそのグループ内の全レシートが強調表示され、関連性が一目でわかる。
3. ImageNavigationPanelを使った画像プレビュー
別コンポーネントとして実装済みのImageNavigationPanelを活用し、画面遷移なしで画像プレビューを実現した。
- グループ選択時に関連画像を右パネルに表示
- 矢印キーで画像を切り替え可能
- ズームイン・ズームアウト対応
4. 帳票リンクから読取一覧タブへの遷移
帳票リンクをクリックすると、読取一覧タブに遷移して該当レシートを選択状態にする機能を追加した。
const navigateToReceipt = (receiptId: string) => {
router.push({
path: '/receipts',
query: {
tab: 'scan-list',
receiptId
}
});
};
5. URLクエリパラメータでの状態管理
選択中のグループIDをURLクエリパラメータ(dupGroup)で管理し、ブラウザの戻る・進むボタンやブックマークに対応した。
// URLからグループIDを復元
const route = useRoute();
const selectedGroupId = computed(() => route.query.dupGroup as string || null);
// グループ選択時にURLを更新
const selectGroup = (groupId: string) => {
router.push({
query: { ...route.query, dupGroup: groupId }
});
};
6. タブ切り替え時の自動選択
重複チェックタブに切り替えた際、自動で最初のグループを選択する処理を追加した。
watch(() => activeTab.value, (newTab) => {
if (newTab === 'duplicate-check' && !selectedGroupId.value) {
const firstGroup = Array.from(groupedReceipts.value.keys())[0];
if (firstGroup) {
selectGroup(firstGroup);
}
}
});
7. 4カラムレイアウト
重複レシートの状態を4つのカラムで管理する。
| カラム | 状態 | 説明 |
|---|---|---|
| pending | 未処理 | 確認待ちの重複候補 |
| in_progress | 処理中 | 確認作業中 |
| completed | 完了 | 重複確認済み |
| archived | アーカイブ | 対応不要として保管 |
ドラッグ&ドロップでカラム間を移動できる。
技術的なポイント
computed内でのMap使用
Vue 3のリアクティビティでMapを使用する場合、computedで新しいMapインスタンスを返すことで変更検知が正しく動作する。
URLクエリパラメータの同期
useRoute()とuseRouter()を組み合わせ、URLとコンポーネント状態を双方向に同期させた。router.pushではなくrouter.replaceを使うことで、履歴を汚さない選択肢もある。
今後の改善予定
- グループ内レシートの一括削除機能
- 重複判定ロジックの精度向上
- キーボードショートカットの拡充