/**
* スプレッドシートAPI
* Google Apps ScriptのWeb Appを呼び出す実装
*/
import { SpreadsheetInfo, SheetData } from './types.js';
import { config } from '../config.js';
/**
* スプレッドシートのURLからIDを抽出する関数
* @param url スプレッドシートのURL
* @returns スプレッドシートID
*/
export function extractSpreadsheetId(url: string): string | null {
try {
// URL自体がnullまたはundefinedの場合
if (!url) {
return null;
}
// 実際のGoogle SpreadsheetのURLからIDを抽出
// 例: https://docs.google.com/spreadsheets/d/1a2b3c4d5e6f7g8h9i0j/edit#gid=0
const regex = /\/d\/([a-zA-Z0-9_-]+)/;
const match = url.match(regex);
if (match && match[1]) {
return match[1];
}
// モック用に特殊なURLも処理
if (config.isMockMode && (url.includes("budget") || url.includes("project"))) {
return url.includes("budget") ? "mock_budget" : "mock_project";
}
return null;
} catch (error) {
console.error("URL解析エラー:", error);
return null;
}
}
/**
* スプレッドシートの基本情報を取得するAPIクライアント関数
* @param spreadsheetId スプレッドシートID
* @returns スプレッドシート情報
*/
export async function getSpreadsheetInfo(spreadsheetId: string): Promise<SpreadsheetInfo> {
// モックモードの場合はモックデータを返す
if (config.isMockMode) {
return getMockSpreadsheetInfo(spreadsheetId);
}
// API呼び出し用のURLを生成
const apiUrl = new URL(config.gas.webAppUrl);
apiUrl.searchParams.append('action', 'getSpreadsheet');
apiUrl.searchParams.append('id', spreadsheetId);
apiUrl.searchParams.append('apiKey', config.gas.apiKey);
// APIリクエスト
const response = await fetch(apiUrl);
// ステータスコードのチェック
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || `API Error: ${response.status}`);
}
// レスポンスをJSONとしてパース
return await response.json() as SpreadsheetInfo;
}
/**
* シートのデータを取得するAPIクライアント関数
* @param spreadsheetId スプレッドシートID
* @param sheetName シート名
* @returns シートデータ(二次元配列)
*/
export async function getSheetData(
spreadsheetId: string,
sheetName: string
): Promise<SheetData> {
// モックモードの場合はモックデータを返す
if (config.isMockMode) {
return getMockSheetData(spreadsheetId, sheetName);
}
// API呼び出し用のURLを生成
const apiUrl = new URL(config.gas.webAppUrl);
apiUrl.searchParams.append('action', 'getSheetData');
apiUrl.searchParams.append('id', spreadsheetId);
apiUrl.searchParams.append('sheetName', sheetName);
apiUrl.searchParams.append('apiKey', config.gas.apiKey);
// 任意のパラメータ(必要に応じて)
// apiUrl.searchParams.append('maxRows', '1000');
// APIリクエスト
const response = await fetch(apiUrl);
// ステータスコードのチェック
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || `API Error: ${response.status}`);
}
// レスポンスをJSONとしてパース
const result = await response.json();
// APIのレスポンス形式を SheetData 形式(二次元配列)に変換
return result.data as SheetData;
}
/**
* モック用のスプレッドシート情報データ
*/
function getMockSpreadsheetInfo(spreadsheetId: string): SpreadsheetInfo {
// 異なるスプレッドシートIDで異なるモックを返す
if (spreadsheetId === "mock_budget") {
return {
id: "mock_budget",
name: "家計簿 2024",
url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}`,
lastModified: "2024-04-01T10:30:00Z",
sheets: [
{ id: 1, name: "4月", index: 0, rowCount: 100, columnCount: 10 },
{ id: 2, name: "5月", index: 1, rowCount: 100, columnCount: 10 },
{ id: 3, name: "集計", index: 2, rowCount: 50, columnCount: 8 }
]
};
} else if (spreadsheetId === "mock_project") {
return {
id: "mock_project",
name: "プロジェクト管理",
url: `https://docs.google.com/spreadsheets/d/${spreadsheetId}`,
lastModified: "2024-03-28T15:45:00Z",
sheets: [
{ id: 1, name: "タスク一覧", index: 0, rowCount: 200, columnCount: 12 },
{ id: 2, name: "予算", index: 1, rowCount: 50, columnCount: 8 },
{ id: 3, name: "メンバー", index: 2, rowCount: 20, columnCount: 6 }
]
};
} else {
// 存在しないスプレッドシートIDの場合はエラーを投げる
throw new Error(`スプレッドシート「${spreadsheetId}」は存在しないか、アクセスできません。`);
}
}
/**
* モック用のシートデータ
*/
function getMockSheetData(spreadsheetId: string, sheetName: string): SheetData {
// 家計簿のモックデータ
if (spreadsheetId === "mock_budget") {
if (sheetName === "4月") {
return [
["日付", "カテゴリ", "内容", "金額", "備考"],
["2024/4/1", "食費", "スーパー", 3500, null],
["2024/4/2", "交通費", "電車", 500, "通勤"],
["2024/4/3", "日用品", "ドラッグストア", 2800, null],
["2024/4/5", "食費", "外食", 4200, "ランチミーティング"],
["2024/4/7", "娯楽", "映画", 1800, null]
];
} else if (sheetName === "5月") {
return [
["日付", "カテゴリ", "内容", "金額", "備考"],
["2024/5/1", "食費", "スーパー", 3800, null],
["2024/5/3", "交通費", "電車", 500, "通勤"],
["2024/5/5", "日用品", "ホームセンター", 5600, "掃除用品"],
["2024/5/8", "食費", "外食", 3500, null]
];
} else if (sheetName === "集計") {
return [
["月", "食費", "交通費", "日用品", "娯楽", "その他", "合計"],
["4月", 7700, 500, 2800, 1800, 0, 12800],
["5月", 7300, 500, 5600, 0, 0, 13400]
];
}
// シートが見つからない場合はエラーを投げる
throw new Error(`シート「${sheetName}」は「家計簿 2024」に存在しません。`);
}
// プロジェクト管理のモックデータ
else if (spreadsheetId === "mock_project") {
if (sheetName === "タスク一覧") {
return [
["ID", "タスク名", "担当者", "開始日", "期限", "状態", "進捗率"],
[1, "要件定義", "佐藤", "2024/3/1", "2024/3/15", "完了", 100],
[2, "設計", "田中", "2024/3/16", "2024/3/31", "完了", 100],
[3, "実装", "鈴木", "2024/4/1", "2024/4/30", "進行中", 60],
[4, "テスト", "高橋", "2024/5/1", "2024/5/15", "未着手", 0],
[5, "リリース", "伊藤", "2024/5/16", "2024/5/20", "未着手", 0]
];
} else if (sheetName === "予算") {
return [
["項目", "予算", "実績", "差異"],
["人件費", 5000000, 4800000, 200000],
["ハードウェア", 1000000, 950000, 50000],
["ソフトウェア", 800000, 820000, -20000],
["外注費", 1500000, 1400000, 100000],
["その他", 500000, 300000, 200000],
["合計", 8800000, 8270000, 530000]
];
} else if (sheetName === "メンバー") {
return [
["名前", "役割", "部署", "参画率"],
["佐藤", "PM", "システム開発部", 100],
["田中", "設計", "システム開発部", 80],
["鈴木", "開発", "システム開発部", 100],
["高橋", "テスト", "品質保証部", 50],
["伊藤", "インフラ", "運用部", 30]
];
}
// シートが見つからない場合はエラーを投げる
throw new Error(`シート「${sheetName}」は「プロジェクト管理」に存在しません。`);
}
// 存在しないスプレッドシートIDの場合はエラーを投げる
throw new Error(`スプレッドシート「${spreadsheetId}」は存在しないか、アクセスできません。`);
}