Microsoft SharePoint
コラボレーションツール
Microsoft SharePoint
概要
Microsoft SharePointは、Microsoft提供の企業向けコラボレーション・コンテンツ管理プラットフォームです。ドキュメント管理、イントラネット構築、ワークフロー自動化、Office 365との完全統合を提供。Microsoft環境の大企業での標準採用となっており、Teams統合により現代的なコラボレーション体験を実現。レガシーシステムとの互換性を保ちながら進化し、2024-2025年にはAI機能、自動化ワークフロー、高度なドキュメント管理機能を大幅強化しています。
詳細
Microsoft SharePoint 2025年版は、AIとMicrosoft 365エコシステムの完全統合により、エンタープライズコラボレーションの最前線に立っています。SharePoint Copilot AIアシスタントによる自動タスク処理、コンテンツ分析、インサイト生成により生産性が劇的に向上。Teams、Outlook、OneDrive、Power Platform、Viva Suiteとのシームレス統合により、統合されたデジタルワークスペースを提供。2024年の主要アップデートには、AI駆動のドキュメント管理、スマートバージョン管理、電子署名統合(DocuSign、Adobe Acrobat Sign)、カスタムテーマ・フォント対応、高度なワークフロー自動化が含まれます。エンタープライズセキュリティ、コンプライアンス、ガバナンス機能により、大規模組織の厳格な要件に対応しています。
主な特徴
- Teams完全統合: ファイル管理とコミュニケーションの統合プラットフォーム
- AI駆動の自動化: SharePoint Copilotによるスマートコンテンツ管理
- 高度なワークフロー: Power Automate統合による業務プロセス自動化
- エンタープライズセキュリティ: 高度な権限管理とコンプライアンス機能
- カスタマイズ性: カスタムテーマ、フォント、レイアウト対応
- バージョン管理: スマートな版数管理とストレージ最適化
メリット・デメリット
メリット
- Microsoft 365エコシステムとの完璧な統合によるワークフロー効率化
- 強力なエンタープライズセキュリティとコンプライアンス機能
- AIによる自動化とインテリジェントなコンテンツ管理
- 大規模組織対応のスケーラビリティと安定性
- 豊富なテンプレートとベストプラクティスの実装
- Teams統合による現代的なコラボレーション体験
- Power Platform統合による高度なカスタマイズ
- 既存Microsoftインフラとの親和性
デメリット
- 高額なライセンス費用(特に大規模組織)
- 複雑な設定と管理による高い運用コスト
- Microsoft環境以外との統合制限
- 従来的なUI/UXによる学習コスト
- オンプレミス版の段階的廃止によるクラウド移行圧力
- カスタマイズには高度な技術知識が必要
- 大量データ処理時のパフォーマンス課題
- ベンダーロックインのリスク
参考ページ
- Microsoft SharePoint 公式サイト
- SharePoint 開発者向けドキュメント
- SharePoint コミュニティ
- SharePoint REST API
- Power Platform
書き方の例
基本設定とサイト構築
# SharePoint Online基本セットアップ
# 1. Microsoft 365管理センターでのSharePointライセンス確認
# 2. SharePoint管理センターでのサイト作成
# 3. Teams統合の設定
# 4. 権限とセキュリティ設定
# 基本的なサイト構造例
企業イントラネット/
├── ホーム/
│ ├── お知らせ
│ ├── 企業ニュース
│ └── イベント情報
├── 部門サイト/
│ ├── 人事部/
│ ├── 営業部/
│ └── 開発部/
├── プロジェクトサイト/
│ ├── プロジェクトA/
│ ├── プロジェクトB/
│ └── アーカイブ/
└── ナレッジベース/
├── 技術文書/
├── 業務マニュアル/
└── FAQ/
SharePoint REST API基本操作
// SharePoint REST API基本設定
class SharePointAPI {
constructor(siteUrl, accessToken) {
this.siteUrl = siteUrl.replace(/\/$/, ''); // 末尾のスラッシュを除去
this.accessToken = accessToken;
this.headers = {
'Authorization': `Bearer ${accessToken}`,
'Accept': 'application/json; odata=verbose',
'Content-Type': 'application/json; odata=verbose',
};
}
// リスト一覧取得
async getLists() {
try {
const response = await fetch(`${this.siteUrl}/_api/web/lists`, {
method: 'GET',
headers: this.headers,
});
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const data = await response.json();
return data.d.results;
} catch (error) {
console.error('リスト取得エラー:', error);
throw error;
}
}
// リストアイテム取得
async getListItems(listTitle, selectFields = '', filterQuery = '', orderBy = '') {
try {
let apiUrl = `${this.siteUrl}/_api/web/lists/getbytitle('${listTitle}')/items`;
const params = new URLSearchParams();
if (selectFields) params.append('$select', selectFields);
if (filterQuery) params.append('$filter', filterQuery);
if (orderBy) params.append('$orderby', orderBy);
if (params.toString()) {
apiUrl += `?${params.toString()}`;
}
const response = await fetch(apiUrl, {
method: 'GET',
headers: this.headers,
});
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const data = await response.json();
return data.d.results;
} catch (error) {
console.error('リストアイテム取得エラー:', error);
throw error;
}
}
// リストアイテム作成
async createListItem(listTitle, itemData) {
try {
// Request Digestを取得
const digestResponse = await fetch(`${this.siteUrl}/_api/contextinfo`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Accept': 'application/json; odata=verbose',
},
});
if (!digestResponse.ok) {
throw new Error(`Digest取得エラー: ${digestResponse.status}`);
}
const digestData = await digestResponse.json();
const requestDigest = digestData.d.GetContextWebInformation.FormDigestValue;
// アイテム作成
const response = await fetch(`${this.siteUrl}/_api/web/lists/getbytitle('${listTitle}')/items`, {
method: 'POST',
headers: {
...this.headers,
'X-RequestDigest': requestDigest,
},
body: JSON.stringify(itemData),
});
if (!response.ok) {
throw new Error(`アイテム作成エラー: ${response.status}`);
}
const data = await response.json();
return data.d;
} catch (error) {
console.error('アイテム作成エラー:', error);
throw error;
}
}
// リストアイテム更新
async updateListItem(listTitle, itemId, itemData) {
try {
// Request Digestを取得
const digestResponse = await fetch(`${this.siteUrl}/_api/contextinfo`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Accept': 'application/json; odata=verbose',
},
});
const digestData = await digestResponse.json();
const requestDigest = digestData.d.GetContextWebInformation.FormDigestValue;
// アイテム更新
const response = await fetch(`${this.siteUrl}/_api/web/lists/getbytitle('${listTitle}')/items(${itemId})`, {
method: 'POST',
headers: {
...this.headers,
'X-RequestDigest': requestDigest,
'X-HTTP-Method': 'MERGE',
'IF-MATCH': '*',
},
body: JSON.stringify(itemData),
});
if (!response.ok) {
throw new Error(`アイテム更新エラー: ${response.status}`);
}
return true;
} catch (error) {
console.error('アイテム更新エラー:', error);
throw error;
}
}
// ファイルアップロード
async uploadFile(libraryName, fileName, fileContent) {
try {
// Request Digestを取得
const digestResponse = await fetch(`${this.siteUrl}/_api/contextinfo`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Accept': 'application/json; odata=verbose',
},
});
const digestData = await digestResponse.json();
const requestDigest = digestData.d.GetContextWebInformation.FormDigestValue;
// ファイルアップロード
const response = await fetch(
`${this.siteUrl}/_api/web/GetFolderByServerRelativeUrl('${libraryName}')/Files/add(url='${fileName}',overwrite=true)`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Accept': 'application/json; odata=verbose',
'X-RequestDigest': requestDigest,
},
body: fileContent,
}
);
if (!response.ok) {
throw new Error(`ファイルアップロードエラー: ${response.status}`);
}
const data = await response.json();
return data.d;
} catch (error) {
console.error('ファイルアップロードエラー:', error);
throw error;
}
}
// 検索実行
async search(query, selectProperties = '', rowLimit = 50) {
try {
const searchUrl = `${this.siteUrl}/_api/search/query?querytext='${encodeURIComponent(query)}'&selectproperties='${selectProperties}'&rowlimit=${rowLimit}`;
const response = await fetch(searchUrl, {
method: 'GET',
headers: this.headers,
});
if (!response.ok) {
throw new Error(`検索エラー: ${response.status}`);
}
const data = await response.json();
return data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results;
} catch (error) {
console.error('検索エラー:', error);
throw error;
}
}
}
// 使用例
const sharepoint = new SharePointAPI(
'https://yourcompany.sharepoint.com/sites/yoursite',
'your-access-token'
);
// タスクリスト管理の例
async function manageTaskList() {
try {
// 新しいタスク作成
const newTask = {
__metadata: { type: 'SP.Data.TasksListItem' },
Title: 'プロジェクト資料作成',
Description: 'Q1プロジェクトの資料を作成する',
AssignedTo: { __metadata: { type: 'SP.Data.UserGroupValue' }, LookupId: 12 },
DueDate: '2025-01-31T00:00:00Z',
Priority: '高',
Status: '進行中',
};
const createdTask = await sharepoint.createListItem('Tasks', newTask);
console.log('タスク作成完了:', createdTask.Title);
// タスク一覧取得(期限でソート)
const tasks = await sharepoint.getListItems(
'Tasks',
'ID,Title,Description,DueDate,Priority,Status',
"Status ne '完了'",
'DueDate asc'
);
console.log('未完了タスク:', tasks.length);
tasks.forEach(task => {
console.log(`- ${task.Title} (期限: ${task.DueDate})`);
});
// 期限が迫っているタスクの更新
const urgentTasks = tasks.filter(task => {
const dueDate = new Date(task.DueDate);
const today = new Date();
const diffTime = dueDate.getTime() - today.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays <= 3 && diffDays >= 0;
});
for (const task of urgentTasks) {
await sharepoint.updateListItem('Tasks', task.ID, {
__metadata: { type: 'SP.Data.TasksListItem' },
Priority: '緊急',
});
console.log(`タスク "${task.Title}" を緊急に変更`);
}
} catch (error) {
console.error('タスク管理エラー:', error);
}
}
// ドキュメント検索の例
async function searchDocuments() {
try {
const searchResults = await sharepoint.search(
'プロジェクト AND 仕様書',
'Title,Path,Author,LastModifiedTime',
20
);
console.log('検索結果:');
searchResults.forEach(result => {
const cells = result.Cells.results;
const title = cells.find(c => c.Key === 'Title')?.Value || 'タイトル不明';
const path = cells.find(c => c.Key === 'Path')?.Value || '';
const author = cells.find(c => c.Key === 'Author')?.Value || '作成者不明';
console.log(`- ${title} (作成者: ${author})`);
console.log(` パス: ${path}`);
});
} catch (error) {
console.error('文書検索エラー:', error);
}
}
Power Automate統合とワークフロー自動化
// Power Automate(旧Flow)との統合例
class SharePointWorkflow {
constructor(siteUrl, accessToken) {
this.sharepoint = new SharePointAPI(siteUrl, accessToken);
this.flowApiUrl = 'https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple';
}
// 承認ワークフロートリガー
async triggerApprovalWorkflow(documentUrl, approvers, requestMessage) {
try {
// SharePoint上のドキュメント情報取得
const fileInfo = await this.getFileInfo(documentUrl);
// Power Automate HTTPトリガーの呼び出し
const workflowData = {
documentTitle: fileInfo.Title,
documentUrl: documentUrl,
requestedBy: fileInfo.Author.Title,
approvers: approvers,
message: requestMessage,
timestamp: new Date().toISOString(),
};
// カスタムHTTPトリガーエンドポイント
const response = await fetch('https://prod-xx.eastus.logic.azure.com:443/workflows/xxxxx/triggers/manual/paths/invoke', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(workflowData),
});
if (!response.ok) {
throw new Error(`ワークフロートリガーエラー: ${response.status}`);
}
const result = await response.json();
return result;
} catch (error) {
console.error('承認ワークフローエラー:', error);
throw error;
}
}
// ドキュメント情報取得
async getFileInfo(documentUrl) {
try {
// URLからサーバー相対パスを取得
const url = new URL(documentUrl);
const serverRelativeUrl = url.pathname;
const response = await fetch(
`${this.sharepoint.siteUrl}/_api/web/GetFileByServerRelativeUrl('${serverRelativeUrl}')?$expand=Author,CheckedOutByUser,ModifiedBy`,
{
method: 'GET',
headers: this.sharepoint.headers,
}
);
if (!response.ok) {
throw new Error(`ファイル情報取得エラー: ${response.status}`);
}
const data = await response.json();
return data.d;
} catch (error) {
console.error('ファイル情報取得エラー:', error);
throw error;
}
}
// 定期レポート生成ワークフロー
async scheduleWeeklyReport(listName, reportRecipients) {
try {
// 今週のデータ取得
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
const isoDate = oneWeekAgo.toISOString();
const weeklyData = await this.sharepoint.getListItems(
listName,
'ID,Title,Created,Modified,Author/Title',
`Created ge datetime'${isoDate}'`,
'Created desc'
);
// レポートデータ集計
const reportData = {
period: `${oneWeekAgo.toLocaleDateString()} - ${new Date().toLocaleDateString()}`,
totalItems: weeklyData.length,
itemsByDay: this.groupByDay(weeklyData),
topContributors: this.getTopContributors(weeklyData),
summary: this.generateSummary(weeklyData),
};
// Power Automate経由でメール送信
const emailData = {
to: reportRecipients,
subject: `週次レポート - ${listName} (${reportData.period})`,
body: this.generateEmailBody(reportData),
isHtml: true,
};
// Email送信トリガー
const response = await fetch('https://prod-xx.eastus.logic.azure.com:443/workflows/xxxxx/triggers/manual/paths/invoke', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(emailData),
});
return reportData;
} catch (error) {
console.error('週次レポートエラー:', error);
throw error;
}
}
// 日別グループ化
groupByDay(items) {
return items.reduce((groups, item) => {
const date = new Date(item.Created).toLocaleDateString();
if (!groups[date]) {
groups[date] = [];
}
groups[date].push(item);
return groups;
}, {});
}
// トップ貢献者の取得
getTopContributors(items) {
const contributors = items.reduce((counts, item) => {
const author = item.Author ? item.Author.Title : '不明';
counts[author] = (counts[author] || 0) + 1;
return counts;
}, {});
return Object.entries(contributors)
.sort(([,a], [,b]) => b - a)
.slice(0, 5)
.map(([name, count]) => ({ name, count }));
}
// サマリー生成
generateSummary(items) {
return {
averagePerDay: (items.length / 7).toFixed(1),
peakDay: this.getPeakDay(items),
categories: this.getCategoryDistribution(items),
};
}
// メール本文生成
generateEmailBody(reportData) {
return `
<h2>週次レポート - ${reportData.period}</h2>
<h3>概要</h3>
<ul>
<li>総件数: ${reportData.totalItems}件</li>
<li>1日平均: ${reportData.summary.averagePerDay}件</li>
<li>最も活発な日: ${reportData.summary.peakDay}</li>
</ul>
<h3>トップ貢献者</h3>
<ol>
${reportData.topContributors.map(c => `<li>${c.name}: ${c.count}件</li>`).join('')}
</ol>
<h3>日別内訳</h3>
<table border="1" style="border-collapse: collapse;">
<tr><th>日付</th><th>件数</th></tr>
${Object.entries(reportData.itemsByDay).map(([date, items]) =>
`<tr><td>${date}</td><td>${items.length}</td></tr>`
).join('')}
</table>
`;
}
}
// 使用例
const workflow = new SharePointWorkflow(
'https://yourcompany.sharepoint.com/sites/yoursite',
'your-access-token'
);
// ドキュメント承認ワークフローの開始
async function initiateDocumentApproval() {
try {
const result = await workflow.triggerApprovalWorkflow(
'https://yourcompany.sharepoint.com/sites/yoursite/Documents/Project_Spec.docx',
['[email protected]', '[email protected]'],
'プロジェクト仕様書の承認をお願いします。'
);
console.log('承認ワークフロー開始:', result);
} catch (error) {
console.error('承認ワークフローエラー:', error);
}
}
// 週次レポート自動生成
async function generateAutomaticWeeklyReport() {
try {
const reportData = await workflow.scheduleWeeklyReport(
'ProjectTasks',
['[email protected]', '[email protected]']
);
console.log('週次レポート生成完了:', reportData);
} catch (error) {
console.error('週次レポートエラー:', error);
}
}
Teams統合とモダンコラボレーション
// Microsoft Teams + SharePoint統合
class TeamsSharePointIntegration {
constructor(teamsApiUrl, sharePointSiteUrl, accessToken) {
this.teamsApiUrl = teamsApiUrl;
this.sharepoint = new SharePointAPI(sharePointSiteUrl, accessToken);
this.accessToken = accessToken;
}
// Teams チャネルとSharePointフォルダの同期
async syncTeamsChannel(teamId, channelId, documentLibrary) {
try {
// Teamsチャネル情報取得
const channelInfo = await this.getChannelInfo(teamId, channelId);
// SharePointフォルダ作成/確認
const folderName = channelInfo.displayName.replace(/[^a-zA-Z0-9]/g, '_');
await this.ensureFolderExists(documentLibrary, folderName);
// チャネルタブにSharePointフォルダを追加
await this.addSharePointTab(teamId, channelId, folderName, documentLibrary);
return {
channelName: channelInfo.displayName,
folderPath: `/${documentLibrary}/${folderName}`,
tabAdded: true,
};
} catch (error) {
console.error('Teams-SharePoint同期エラー:', error);
throw error;
}
}
// Teamsチャネル情報取得
async getChannelInfo(teamId, channelId) {
const response = await fetch(`${this.teamsApiUrl}/teams/${teamId}/channels/${channelId}`, {
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`Teams API Error: ${response.status}`);
}
return await response.json();
}
// SharePointフォルダ存在確認・作成
async ensureFolderExists(libraryName, folderName) {
try {
// フォルダ存在確認
const response = await fetch(
`${this.sharepoint.siteUrl}/_api/web/GetFolderByServerRelativeUrl('${libraryName}/${folderName}')`,
{
method: 'GET',
headers: this.sharepoint.headers,
}
);
if (response.status === 404) {
// フォルダが存在しない場合は作成
await this.createFolder(libraryName, folderName);
}
} catch (error) {
if (error.message.includes('404')) {
await this.createFolder(libraryName, folderName);
} else {
throw error;
}
}
}
// SharePointフォルダ作成
async createFolder(libraryName, folderName) {
// Request Digest取得
const digestResponse = await fetch(`${this.sharepoint.siteUrl}/_api/contextinfo`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Accept': 'application/json; odata=verbose',
},
});
const digestData = await digestResponse.json();
const requestDigest = digestData.d.GetContextWebInformation.FormDigestValue;
// フォルダ作成
const response = await fetch(
`${this.sharepoint.siteUrl}/_api/web/folders`,
{
method: 'POST',
headers: {
...this.sharepoint.headers,
'X-RequestDigest': requestDigest,
},
body: JSON.stringify({
__metadata: { type: 'SP.Folder' },
ServerRelativeUrl: `/${libraryName}/${folderName}`,
}),
}
);
if (!response.ok) {
throw new Error(`フォルダ作成エラー: ${response.status}`);
}
return await response.json();
}
// TeamsチャネルにSharePointタブ追加
async addSharePointTab(teamId, channelId, folderName, libraryName) {
const tabData = {
displayName: `${folderName} ファイル`,
'[email protected]': `${this.teamsApiUrl}/appCatalogs/teamsApps/2a527703-1f6f-4559-a332-d8a7d288cd88`, // SharePoint アプリID
configuration: {
entityId: '',
contentUrl: `${this.sharepoint.siteUrl}/${libraryName}/${folderName}`,
websiteUrl: `${this.sharepoint.siteUrl}/${libraryName}/${folderName}`,
removeUrl: null,
},
};
const response = await fetch(`${this.teamsApiUrl}/teams/${teamId}/channels/${channelId}/tabs`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(tabData),
});
if (!response.ok) {
throw new Error(`Teams タブ追加エラー: ${response.status}`);
}
return await response.json();
}
// Teams会議録をSharePointに自動保存
async saveMeetingNotes(teamId, meetingData) {
try {
// 会議録HTML生成
const meetingNotesHtml = this.generateMeetingNotesHtml(meetingData);
// ファイル名生成(日付・タイトル・バージョン管理)
const fileName = `会議録_${meetingData.date}_${meetingData.title.replace(/[^a-zA-Z0-9]/g, '_')}.html`;
// SharePointドキュメントライブラリにアップロード
const uploadResult = await this.sharepoint.uploadFile(
'MeetingNotes',
fileName,
meetingNotesHtml
);
// メタデータ更新
await this.updateMeetingFileMetadata(uploadResult.Name, meetingData);
return {
fileName: fileName,
url: uploadResult.ServerRelativeUrl,
uploadedAt: new Date().toISOString(),
};
} catch (error) {
console.error('会議録保存エラー:', error);
throw error;
}
}
// 会議録HTML生成
generateMeetingNotesHtml(meetingData) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>会議録 - ${meetingData.title}</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 20px; }
.header { border-bottom: 2px solid #0078d4; padding-bottom: 10px; margin-bottom: 20px; }
.section { margin-bottom: 20px; }
.attendees { display: flex; flex-wrap: wrap; gap: 10px; }
.attendee { background: #f3f2f1; padding: 5px 10px; border-radius: 15px; }
.action-item { background: #fff4ce; padding: 10px; border-left: 4px solid #ffb900; margin: 5px 0; }
.decision { background: #dff6dd; padding: 10px; border-left: 4px solid #107c10; margin: 5px 0; }
</style>
</head>
<body>
<div class="header">
<h1>${meetingData.title}</h1>
<p><strong>日時:</strong> ${meetingData.date} ${meetingData.time}</p>
<p><strong>場所:</strong> ${meetingData.location}</p>
</div>
<div class="section">
<h2>参加者</h2>
<div class="attendees">
${meetingData.attendees.map(attendee => `<span class="attendee">${attendee}</span>`).join('')}
</div>
</div>
<div class="section">
<h2>議題</h2>
<ol>
${meetingData.agenda.map(item => `<li>${item}</li>`).join('')}
</ol>
</div>
<div class="section">
<h2>議事内容</h2>
${meetingData.notes}
</div>
<div class="section">
<h2>決定事項</h2>
${meetingData.decisions.map(decision => `<div class="decision">${decision}</div>`).join('')}
</div>
<div class="section">
<h2>アクションアイテム</h2>
${meetingData.actionItems.map(item =>
`<div class="action-item">
<strong>${item.task}</strong><br>
担当: ${item.assignee} | 期限: ${item.dueDate}
</div>`
).join('')}
</div>
<div class="section">
<h2>次回会議</h2>
<p>${meetingData.nextMeeting || '未定'}</p>
</div>
</body>
</html>`;
}
// 会議ファイルメタデータ更新
async updateMeetingFileMetadata(fileName, meetingData) {
try {
const metadata = {
__metadata: { type: 'SP.Data.MeetingNotesItem' },
MeetingDate: meetingData.date,
MeetingTitle: meetingData.title,
Attendees: meetingData.attendees.join('; '),
ActionItemsCount: meetingData.actionItems.length,
DecisionsCount: meetingData.decisions.length,
};
// ファイルのリストアイテムID取得
const fileResponse = await fetch(
`${this.sharepoint.siteUrl}/_api/web/GetFileByServerRelativeUrl('/MeetingNotes/${fileName}')/ListItemAllFields`,
{
method: 'GET',
headers: this.sharepoint.headers,
}
);
const fileData = await fileResponse.json();
const itemId = fileData.d.ID;
// メタデータ更新
await this.sharepoint.updateListItem('MeetingNotes', itemId, metadata);
} catch (error) {
console.error('メタデータ更新エラー:', error);
// メタデータ更新エラーは非致命的エラーとして処理
}
}
}
// 使用例
const teamsIntegration = new TeamsSharePointIntegration(
'https://graph.microsoft.com/v1.0',
'https://yourcompany.sharepoint.com/sites/yoursite',
'your-access-token'
);
// Teams-SharePoint同期の実行
async function setupTeamsSharePointSync() {
try {
const result = await teamsIntegration.syncTeamsChannel(
'team-id-123',
'channel-id-456',
'Shared Documents'
);
console.log('同期完了:', result);
} catch (error) {
console.error('同期エラー:', error);
}
}
// 会議録の自動保存
async function saveMeetingToSharePoint() {
const meetingData = {
title: 'Q1計画レビュー会議',
date: '2025-01-15',
time: '10:00-11:00',
location: 'Teams会議',
attendees: ['田中', '佐藤', '鈴木', '高橋'],
agenda: [
'Q4実績確認',
'Q1目標設定',
'リソース配分検討',
'リスク分析'
],
notes: '<p>Q4の実績は目標を上回り、Q1も積極的な目標設定を行う方針となった。</p>',
decisions: [
'Q1売上目標を15%上方修正',
'新規プロジェクトを2件追加承認'
],
actionItems: [
{ task: 'Q1詳細計画書作成', assignee: '田中', dueDate: '2025-01-20' },
{ task: 'リソース配分表更新', assignee: '佐藤', dueDate: '2025-01-18' }
],
nextMeeting: '2025-02-15 10:00 Q1進捗レビュー'
};
try {
const result = await teamsIntegration.saveMeetingNotes('team-id-123', meetingData);
console.log('会議録保存完了:', result);
} catch (error) {
console.error('会議録保存エラー:', error);
}
}