aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-23 09:27:06 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-23 09:27:06 +0900
commitb5b6471b5a5420d1bd410907ac12570b8436702e (patch)
treeec04b6e36653e3f7aa02090f3936e45c0abac384
parent09ab25113c299b8f3208a717cee9e9b8c7b07fe9 (diff)
sanpi: 集計・全期間一覧・前後リンクを修正し、非公開に戻す
-rw-r--r--src/components/SanpiAllTable.astro52
-rw-r--r--src/components/SanpiChart.astro2
-rw-r--r--src/components/SanpiPagination.astro93
-rw-r--r--src/components/starlight/Footer.astro40
-rw-r--r--src/content/docs/sanpi.mdx14
-rw-r--r--src/content/docs/sanpi/ichiran.mdx35
-rw-r--r--src/content/docs/sanpi/r8d.mdx26
-rw-r--r--src/styles/custom.css27
-rw-r--r--src/utils/sanpiStats.ts112
9 files changed, 389 insertions, 12 deletions
diff --git a/src/components/SanpiAllTable.astro b/src/components/SanpiAllTable.astro
new file mode 100644
index 0000000..bd0f131
--- /dev/null
+++ b/src/components/SanpiAllTable.astro
@@ -0,0 +1,52 @@
+---
+// 全期間の議案賛否一覧。年度別ページの表から安竹洋平の列だけを取り出し、
+// 市側の議案・議員提出の議案・請願に分けて表示する。
+import { computeSanpiBills, type BillType } from "@/utils/sanpiStats";
+
+interface Props {
+ type: BillType;
+}
+
+const { type } = Astro.props;
+const rows = computeSanpiBills().filter((row) => row.type === type);
+
+const PASS = ["可決", "認定", "採択", "同意", "承認"];
+const STOP = ["否決", "不採択"];
+
+function kekkaClass(result: string): string {
+ if (STOP.some((key) => result.includes(key))) return "stop";
+ if (PASS.some((key) => result.includes(key))) return "pass";
+ return "";
+}
+---
+
+<table>
+ <thead>
+ <tr>
+ <th>議案</th>
+ <th>年度</th>
+ <th>定例会</th>
+ <th>議決結果</th>
+ <th><span class="sanpi-me">安竹</span></th>
+ </tr>
+ </thead>
+ <tbody>
+ {
+ rows.map((row) => (
+ <tr>
+ <td>{row.title}</td>
+ <td>
+ <a href={row.yearHref}>{row.year}</a>
+ </td>
+ <td>{row.session}</td>
+ <td>
+ <span class={`sanpi-kekka ${kekkaClass(row.result)}`}>{row.result}</span>
+ </td>
+ <td>
+ <span class="sanpi-me">{row.me}</span>
+ </td>
+ </tr>
+ ))
+ }
+ </tbody>
+</table>
diff --git a/src/components/SanpiChart.astro b/src/components/SanpiChart.astro
index 7bc4174..643eafa 100644
--- a/src/components/SanpiChart.astro
+++ b/src/components/SanpiChart.astro
@@ -15,7 +15,7 @@ const rows = computeSanpiStats();
<ul class="sanpi-chart-list">
{rows.map(({ label, yes, no, yesPct, noPct, me }) => (
<li class="sanpi-chart-item">
- <span class="sanpi-chart-label" style={me ? "font-weight: 700" : undefined}>
+ <span class="sanpi-chart-label" title={label} style={me ? "font-weight: 700" : undefined}>
{label}
</span>
<span class="sanpi-chart-bar" title={`賛成${yes}件/反対${no}件`}>
diff --git a/src/components/SanpiPagination.astro b/src/components/SanpiPagination.astro
new file mode 100644
index 0000000..294ad76
--- /dev/null
+++ b/src/components/SanpiPagination.astro
@@ -0,0 +1,93 @@
+---
+// 年度別の賛否一覧ページの末尾に、前年度・次年度へのリンクを
+// Starlight のページネーションと同じ見た目で表示する。
+// 年度別ページはサイドバーに登録していないため、Starlight 標準の
+// Pagination では前後関係が決まらない。ここで明示的にリンクを渡す。
+import { Icon } from "@astrojs/starlight/components";
+
+interface Link {
+ href: string;
+ label: string;
+}
+
+interface Props {
+ prev?: Link;
+ next?: Link;
+}
+
+const { prev, next } = Astro.props;
+---
+
+{
+ (prev || next) && (
+ <div class="pagination-links print:hidden" dir="ltr">
+ {prev && (
+ <a href={prev.href} rel="prev">
+ <Icon name="left-arrow" size="1.5rem" />
+ <span>
+ {Astro.locals.t("page.previousLink")}
+ <br />
+ <span class="link-title">{prev.label}</span>
+ </span>
+ </a>
+ )}
+ {next && (
+ <a href={next.href} rel="next">
+ <Icon name="right-arrow" size="1.5rem" />
+ <span>
+ {Astro.locals.t("page.nextLink")}
+ <br />
+ <span class="link-title">{next.label}</span>
+ </span>
+ </a>
+ )}
+ </div>
+ )
+}
+
+<style>
+ @layer starlight.core {
+ .pagination-links {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
+ gap: 1rem;
+ }
+
+ a {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 0.5rem;
+ width: 100%;
+ flex-basis: calc(50% - 0.5rem);
+ flex-grow: 1;
+ border: 1px solid var(--sl-color-gray-5);
+ border-radius: 0.5rem;
+ padding: 1rem;
+ text-decoration: none;
+ color: var(--sl-color-gray-2);
+ box-shadow: var(--sl-shadow-md);
+ overflow-wrap: anywhere;
+ }
+
+ [rel="next"] {
+ justify-content: end;
+ text-align: end;
+ flex-direction: row-reverse;
+ }
+
+ a:hover {
+ border-color: var(--sl-color-gray-2);
+ }
+
+ .link-title {
+ color: var(--sl-color-white);
+ font-size: var(--sl-text-2xl);
+ line-height: var(--sl-line-height-headings);
+ }
+
+ svg {
+ flex-shrink: 0;
+ }
+ }
+</style>
diff --git a/src/components/starlight/Footer.astro b/src/components/starlight/Footer.astro
index 65a61ce..63470a4 100644
--- a/src/components/starlight/Footer.astro
+++ b/src/components/starlight/Footer.astro
@@ -3,6 +3,7 @@ import Pagination from 'virtual:starlight/components/Pagination';
import config from 'virtual:starlight/user-config';
import { Icon } from '@astrojs/starlight/components';
import SocialShare from '../SocialShare.astro';
+import SanpiPagination from '../SanpiPagination.astro';
import { shareCaption } from '../../utils/share-caption';
const route = Astro.locals.starlightRoute;
@@ -32,6 +33,37 @@ function toJapaneseDateTime(date: Date): string {
}
const lastUpdated = route.lastUpdated;
+
+// 年度別の賛否一覧はサイドバーに登録していないため、Starlight 標準の
+// 前後ページは決まらない。URL から年度を判定し、前年度・次年度を渡す。
+const SANPI_YEARS = [
+ { key: 'r1d', label: '令和元年度の賛否一覧' },
+ { key: 'r2d', label: '令和2年度の賛否一覧' },
+ { key: 'r3d', label: '令和3年度の賛否一覧' },
+ { key: 'r4d', label: '令和4年度の賛否一覧' },
+ { key: 'r5d', label: '令和5年度の賛否一覧' },
+ { key: 'r6d', label: '令和6年度の賛否一覧' },
+ { key: 'r7d', label: '令和7年度の賛否一覧' },
+ { key: 'r8d', label: '令和8年度の賛否一覧' },
+];
+const sanpiMatch = Astro.url.pathname.match(/^\/sanpi\/(r\d+d)\/?$/);
+const sanpiIndex = sanpiMatch
+ ? SANPI_YEARS.findIndex((year) => year.key === sanpiMatch[1])
+ : -1;
+const sanpiPrev =
+ sanpiIndex > 0
+ ? {
+ href: `/sanpi/${SANPI_YEARS[sanpiIndex - 1].key}/`,
+ label: SANPI_YEARS[sanpiIndex - 1].label,
+ }
+ : undefined;
+const sanpiNext =
+ sanpiIndex >= 0 && sanpiIndex < SANPI_YEARS.length - 1
+ ? {
+ href: `/sanpi/${SANPI_YEARS[sanpiIndex + 1].key}/`,
+ label: SANPI_YEARS[sanpiIndex + 1].label,
+ }
+ : undefined;
---
<footer class="sl-flex">
@@ -55,7 +87,13 @@ const lastUpdated = route.lastUpdated;
)
}
</div>
- <Pagination />
+ {
+ sanpiIndex >= 0 ? (
+ <SanpiPagination prev={sanpiPrev} next={sanpiNext} />
+ ) : (
+ <Pagination />
+ )
+ }
{
config.credits && (
diff --git a/src/content/docs/sanpi.mdx b/src/content/docs/sanpi.mdx
index eb8f76c..2eac504 100644
--- a/src/content/docs/sanpi.mdx
+++ b/src/content/docs/sanpi.mdx
@@ -17,11 +17,15 @@ import SanpiChart from '@/components/SanpiChart.astro';
:::note
- 議員名は敬称略としています
- 〇=賛成、×=反対、—=表決に加わらない(議長・欠席・退場)
+- 佐藤徹議員(公明)は体調不良等により欠席・退席した議案がありますが、グラフでは公明に含め、表決に加わらない票はカウントしていません
- 議決結果は、可決・認定・採択はグレーの印、否決・不採択は青色の印で示しています(カーソルを合わせると内容が出ます)
-- 会派内で賛否が分かれた場合は、同じ賛否の議員は「会派(人数)」にまとめ、異なる議員だけ名前を出して列を分けています。「一人」および「一人と維」は常に議員ごとに示します。安竹洋平の列は色をつけています
+- 会派内で賛否が分かれた場合は、同じ賛否の議員は「会派(人数)」にまとめ、異なる議員だけ名前を出して列を分けています。「一人」と「一人と維」は常に議員ごとに示します。安竹洋平の列は色をつけています
- 賛否が分かれた議案のみを掲載しています(全会一致の議案は除く)
- パソコンでは議案名にカーソルを合わせると全文が表示されます。議案名をタップ/クリックすると、その場で全文が表示されます。スマートフォンでは表を横にスクロールできます
-- 会派の略称は次のとおりです。政和=自民党小平政和会、公明=市議会公明党、フォ=フォーラム小平、共産=日本共産党小平市議団、生ネ=生活者ネットワーク、市民=まちづくり市民こだいら、れ新=市議会れいわ新選組、緑風=緑の風、一人=一人会派の会、一人と維=一人会派と維新の会
+- 会派の略称は次のとおりです
+- 政和=自民党小平政和会、公明=市議会公明党、フォ=フォーラム小平、共産=日本共産党小平市議団
+- 生ネ=生活者ネットワーク、市民=まちづくり市民こだいら、れ新=市議会れいわ新選組
+- 緑風=緑の風、一人=一人会派の会、一人と維=一人会派と維新の会
:::
:::note
@@ -40,3 +44,9 @@ import SanpiChart from '@/components/SanpiChart.astro';
- [令和3年度](/sanpi/r3d/)(令和4年3月、令和3年12月・9月・6月定例会)
- [令和2年度](/sanpi/r2d/)(令和3年3月、令和2年12月・9月・6月定例会、令和2年11月・8月臨時会)
- [令和元年度](/sanpi/r1d/)(令和2年3月、令和元年12月・9月定例会)
+
+## 全期間の議案賛否
+
+安竹洋平の議員就任以降の議案への賛否を、市側の議案・議員提出の議案・請願に分けて一覧にしています。
+
+- [議案の賛否一覧(全期間)](/sanpi/ichiran/)
diff --git a/src/content/docs/sanpi/ichiran.mdx b/src/content/docs/sanpi/ichiran.mdx
new file mode 100644
index 0000000..080b17b
--- /dev/null
+++ b/src/content/docs/sanpi/ichiran.mdx
@@ -0,0 +1,35 @@
+---
+title: 議案の賛否一覧(全期間)
+description: 安竹洋平の議員就任以降の議案への賛否を、市側の議案、議員提出の議案(意見書・決議を含む)、請願に分けて一覧にしたものです。小平市議会議員 安竹洋平の活動記録です。
+draft: true
+tableOfContents: true
+---
+
+import SanpiAllTable from '@/components/SanpiAllTable.astro';
+import SanpiTable from '@/components/SanpiTable.astro';
+
+安竹洋平が議員になってから(令和元年6月定例会以降)の議案への賛否を、市側の議案・議員提出の議案・請願に分けて一覧にしたものです。各会派・議員の賛否は、[年度別の賛否一覧](/sanpi/)をご覧ください。
+
+<SanpiTable />
+
+:::note
+- 全会一致で可決・認定された議案は掲載していません
+- 〇=賛成、×=反対、—=表決に加わらない(議長・欠席・退場)
+- 年度をクリックすると、その年度の詳細な表と賛否理由のページに移動します
+:::
+
+## 市側の議案
+
+市長が提出した議案です。
+
+<SanpiAllTable type="city" />
+
+## 議員提出の議案(意見書・決議を含む)
+
+議員が提出した議案です。意見書、決議(附帯決議を含む)、動議、議員提出の条例制定を含みます。
+
+<SanpiAllTable type="member" />
+
+## 請願
+
+<SanpiAllTable type="petition" />
diff --git a/src/content/docs/sanpi/r8d.mdx b/src/content/docs/sanpi/r8d.mdx
index 02adbcd..4cf43a2 100644
--- a/src/content/docs/sanpi/r8d.mdx
+++ b/src/content/docs/sanpi/r8d.mdx
@@ -14,6 +14,32 @@ import SanpiTable from '@/components/SanpiTable.astro';
<SanpiTable />
+## 令和8年9月定例会
+
+| 議案 | 議決結果 | <span class="sanpi-me">安竹洋平<br />(一人と維)</span> | 伊藤央<br />(一人と維) | 石津はるか<br />(一人と維) | 政和<br />(5人) | 外山まなみ<br />(政和) | 公明 | フォ | 共産 | 生ネ | 市民 | い党 | 国民 |
+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
+| 第55号 小平市教育委員会委員の任命同意 | <span class="sanpi-kekka pass" title="同意">同意</span> | <span class="sanpi-me">×</span> | × | × | 〇 | × | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
+| 第63号 小平市立集会室条例等の一部を改正する条例 | <span class="sanpi-kekka pass" title="原案可決">可決</span> | <span class="sanpi-me">×</span> | × | × | 〇 | 〇 | 〇 | 〇 | × | × | × | × | 〇 |
+| 第64号 小平市立学校施設使用条例 | <span class="sanpi-kekka pass" title="原案可決">可決</span> | <span class="sanpi-me">〇</span> | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | × | 〇 | × | 〇 | 〇 |
+| 第65号 小平市立体育施設条例の一部を改正する条例 | <span class="sanpi-kekka pass" title="原案可決">可決</span> | <span class="sanpi-me">×</span> | × | × | 〇 | 〇 | 〇 | 〇 | × | × | × | 〇 | 〇 |
+| 第66号 小平市西部市民センター解体工事請負契約の締結 | <span class="sanpi-kekka pass" title="原案可決">可決</span> | <span class="sanpi-me">〇</span> | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | × | 〇 | × | 〇 | 〇 |
+| 第67号 小川駅西口地下自転車駐車場整備工事請負契約の締結 | <span class="sanpi-kekka pass" title="原案可決">可決</span> | <span class="sanpi-me">×</span> | × | × | 〇 | 〇 | 〇 | 〇 | × | 〇 | × | 〇 | 〇 |
+| <span class="sanpi-shugan">請願</span>第19号 小平市内の社会福祉法人が運営する通所介護事業所による介護報酬の不適切な受給及び賃金未払いに係る市委託事業者の運営実態の是正を求めることについて | <span class="sanpi-kekka pass" title="採択">採択</span> | <span class="sanpi-me">〇</span> | 〇 | 〇 | 〇 | 〇 | 〇 | × | × | × | × | × | × |
+
+<div class="sanpi-reasons">
+
+**安竹の賛否理由**
+
+- **第55号(教育委員会委員の任命同意)**:再任される望月委員が、令和6年7月18日の教育委員会で請願第1号・第2号を審査した際、請願第2号については質疑も討論もせずに不採択の判断に加わりました。請願第1号についても「運用上困難ではないか」と述べるにとどまり、請願者に判断理由は示されていません。同趣旨の請願は後に市議会で全会一致で採択され、教育委員会と議会の判断が正面から食い違ったままになっています。市長・教育部長に判断理由の把握や困難論の検証、議会採択後の対応、説明責任、再任後の指導を尋ねました。しかし、明確な答弁はありませんでした。そのため反対しました。
+- **第63号(集会室条例等)**:夜間利用を1時間短縮し、喜平図書館集会室の夜間利用を終了、上宿図書館集会室を廃止する見直しについて、一人会派と維新の会として反対しました。委員会では、地域センターの午後9時以降の利用実態を把握していない点が問われました。葬儀・飲食など地域センターでしかできない利用を公民館で代替できるのか、予約や団体登録の窓口が閉まる影響も指摘されています。利用率向上の取組を尽くしたのか、人件費削減効果の内訳と整合性、段階的・試行的実施を検討したのかも課題となりました。
+- **第64号(学校施設使用条例)**:体育館への冷暖房設備設置に伴い、冷暖房使用料(1時間300円)を含む学校施設の使用料を条例で明確化するものとして、一人会派と維新の会は賛成しました。委員会では、PTA・青少年対策地区委員会など学校関係団体の減免範囲や、一般の少年スポーツ団体の負担増が課題となりました。熱中症対策としての冷房利用の促進、還付範囲、規則で決まる減免・運用の内容と周知時期も指摘されています。
+- **第65号(体育施設条例)**:中央公園グラウンドのPark-PFI改修に伴う使用料改定と、東部公園・萩山公園のプールなどの廃止について、一人会派と維新の会として反対しました。委員会では、利用料が3〜4倍になることの便益、多目的エリアの子ども・付添いの有料化、気軽に使える公園から本格施設への転換などが問われました。指定管理者との関係で市の意向がどこまで反映されるのか、Park-PFIで市民・利用者の声が届きにくくなっていないかも懸念されました。
+- **第66号(西部市民センター解体工事)**:新複合施設への機能移転に伴う解体工事契約について、一人会派と維新の会は賛成しました。委員会では、最低制限価格未満による失格・辞退の多さ、市内事業者の参加機会、近隣住民への周知が課題となりました。アスベスト除去費が契約に含まれるのか、解体車両が通学路など狭隘な道路を通行すること、公共施設マネジメントの考え方も指摘されています。
+- **第67号(小川駅西口地下自転車駐車場整備工事)**:約29億円の工事契約について、一人会派と維新の会として反対しました。1者入札で落札率99%という高額契約であること、西武鉄道との関係、地質調査の追加費用の負担が問題となりました。地下化の唐突さと市民周知不足、仮設自転車駐車場の存続、西部市民センター跡地の資材置場利用との連動疑義も指摘されています。
+- **請願第19号(介護報酬の不適切受給と賃金未払い)**:市が調査中を理由に自らの対応の説明を拒むのは別問題です。2月17日に何を聞き、東京都や労働基準監督署にいつ・どう働きかけたのかは説明できるとして、賛成しました。ほかの地域包括支援センターへの注意喚起だけで確認しない姿勢は、所轄庁・委託者としての責任放棄です。重大な疑義が残る中で4月1日に年間6,000万円超の委託契約を更新したことも問題視しました。10分未満の時間外手当切捨てを法人が認めながら是正指導してこなかったことや、3年分の未払い精算を従業員の手計算に丸投げしていることも同様です。調査結果を待つ反対意見には、今こそ処分・公表・再発防止を議会として縛る必要があると反論しました。東京都に勧告権限があることを理由に、請願自体を否定すべきでないとも述べています。
+
+</div>
+
## 令和8年6月定例会
| 議案 | 議決結果 | <span class="sanpi-me">安竹洋平<br />(一人と維)</span> | 伊藤央<br />(一人と維) | 石津はるか<br />(一人と維) | 政和 | 公明 | フォ | 共産 | 生ネ | 市民 | れ新 | 緑風 |
diff --git a/src/styles/custom.css b/src/styles/custom.css
index 01fd450..1ea4aa7 100644
--- a/src/styles/custom.css
+++ b/src/styles/custom.css
@@ -58,7 +58,7 @@
line-height: 1.75;
color: var(--sl-color-text);
}
-.sl-markdown-content img {
+.sl-markdown-content img:not(.leaflet-tile) {
border: 1px solid var(--sl-color-gray-4);
border-radius: 6px;
}
@@ -1710,7 +1710,7 @@ td.sanpi-open .sanpi-title {
}
.sanpi-chart-item {
display: grid;
- grid-template-columns: 8.5em 1fr 12em;
+ grid-template-columns: 10.5em 1fr 12em;
gap: 0.5rem;
align-items: center;
margin: 0.3rem 0;
@@ -1752,7 +1752,12 @@ td.sanpi-open .sanpi-title {
}
@media (max-width: 480px) {
.sanpi-chart-item {
- grid-template-columns: 6em 1fr 5.5em;
+ grid-template-columns: 7.5em 1fr 5.5em;
+ }
+
+ .sanpi-chart-label {
+ white-space: normal;
+ line-height: 1.2;
}
}
@@ -1991,6 +1996,22 @@ td.sanpi-open .sanpi-title {
.schedule-table tbody tr[hidden] {
display: none !important;
}
+.schedule-table tbody tr.is-ended td {
+ color: var(--sl-color-gray-3);
+}
+.schedule-ended-badge {
+ display: inline-block;
+ margin-left: 0.35rem;
+ padding: 0 0.35rem;
+ border: 1px solid var(--sl-color-gray-5);
+ border-radius: 999px;
+ background: var(--sl-color-gray-6);
+ font-size: 0.7rem;
+ line-height: 1.5;
+ color: var(--sl-color-gray-3);
+ vertical-align: middle;
+ white-space: nowrap;
+}
.schedule-row-highlight,
.schedule-table tbody tr.schedule-row-highlight td {
background: var(--sl-color-accent-low, #fff3bf) !important;
diff --git a/src/utils/sanpiStats.ts b/src/utils/sanpiStats.ts
index b2bfed3..33d5231 100644
--- a/src/utils/sanpiStats.ts
+++ b/src/utils/sanpiStats.ts
@@ -24,12 +24,13 @@ export interface SanpiChartRow {
/** グラフの説明文。 */
export const SANPI_CHART_CAPTION =
- "市が提出した議案(請願・意見書・決議・条例制定・動議などの議員提出議案を除く)に対する、会派ごとの議員の賛成・反対の割合です。安竹洋平が議員になってからの累計で、反対の割合が高い順に並べています。会派が分かれた場合は表の各列の票を1件として数えています。会派に合流している期間(中江美和議員のフォーラム、石津はるか議員の政和会)は、会派の票を個人に充当しています。件数が少ない会派は参考程度にご覧ください。";
+ "市が提出した議案(請願・意見書・決議(附帯決議を含む)・条例制定・動議などの議員提出議案を除く)に対する、会派ごとの議員の賛成・反対の割合です。安竹洋平が議員になってからの累計で、反対の割合が高い順に並べています。会派が分かれた場合は表の各列の票を1件として数えています。会派に合流している期間(中江美和議員のフォーラム、石津はるか議員の政和会)は、会派の票を個人に充当しています。件数が少ない会派は参考程度にご覧ください。";
// グラフの表示名(議員名を添える)。
const DISPLAY_NAME: Record<string, string> = {
れ新: "れ新(中倉)",
市民: "市民(水口)",
+ 橋本久雄: "橋本久雄(元議員)",
};
const ME_NAME = "安竹洋平";
@@ -54,6 +55,10 @@ function groupLabel(headerText: string): string {
const label = m[2];
// 会派(N人)は会派そのもの。
if (/^\d+人$/.test(label)) return name;
+ // 佐藤徹議員(公明)は、体調不良等による欠席・退席で列が分かれているだけで、
+ // 所属は公明党。公明の列が別にあるため、この個人列は集計しない
+ // (同じ議案を二重に数えない)。
+ if (name === "佐藤徹" && label === "公明") return "";
// 個人の(政和)は政和会に合算する(外山議員は常に、石津議員も一人でないときは政和会)。
if (label === "政和") return "政和";
// (一人)などは議員ごとに分ける。
@@ -67,11 +72,19 @@ function voteChar(cell: string): "〇" | "×" | null {
return null;
}
+export type BillType = "city" | "member" | "petition";
+
+// 議案の種別。グラフの集計と全期間一覧の分類で共通に使う。
+export function billType(cell: string): BillType {
+ if (cell.includes("sanpi-shugan")) return "petition";
+ const text = stripTags(cell);
+ if (/意見書|附帯決議|付帯決議|決議|動議|制定/.test(text)) return "member";
+ return "city";
+}
+
// 市が提出した議案か(請願・意見書・決議・条例制定・動議などの議員提出議案を除く)。
function isCityBill(cell: string): boolean {
- if (cell.includes("sanpi-shugan")) return false;
- const text = stripTags(cell);
- return !/意見書|決議|動議|制定/.test(text);
+ return billType(cell) === "city";
}
function eraKey(text: string): number | null {
@@ -141,7 +154,7 @@ export function computeSanpiStats(): SanpiChartRow[] {
for (const rule of MEMBER_RULES) {
const fromKey = eraKey(rule.from);
const untilKey = rule.until ? eraKey(rule.until) : Infinity;
- if (fromKey == null || sessionKey < fromKey || sessionKey > untilKey) continue;
+ if (fromKey == null || untilKey == null || sessionKey < fromKey || sessionKey > untilKey) continue;
if (groups.includes(rule.name)) continue;
const gi = groups.indexOf(rule.group);
if (gi < 0) continue;
@@ -174,3 +187,92 @@ export function computeSanpiStats(): SanpiChartRow[] {
};
});
}
+
+export interface SanpiBillRow {
+ /** 年度(例: 令和8年度)。 */
+ year: string;
+ /** 年度別ページへのリンク。 */
+ yearHref: string;
+ /** 定例会(例: 令和8年9月定例会)。 */
+ session: string;
+ /** 議案名(HTMLを除いたもの)。 */
+ title: string;
+ /** 議決結果(例: 可決、否決、採択、不採択)。 */
+ result: string;
+ /** 安竹洋平の賛否。—は表決に加わらない(議長・欠席・退場)。 */
+ me: "〇" | "×" | "—";
+ /** 市側の議案・議員提出の議案・請願の別。 */
+ type: BillType;
+}
+
+const YEAR_LABELS: Record<string, string> = {
+ r1d: "令和元年度",
+ r2d: "令和2年度",
+ r3d: "令和3年度",
+ r4d: "令和4年度",
+ r5d: "令和5年度",
+ r6d: "令和6年度",
+ r7d: "令和7年度",
+ r8d: "令和8年度",
+};
+
+/**
+ * 全期間の議案を、市側の議案・議員提出の議案・請願に分類して返す。
+ * 年度別ページの表をそのまま読み、安竹洋平の列だけを取り出す。
+ */
+export function computeSanpiBills(): SanpiBillRow[] {
+ const sources = import.meta.glob("/src/content/docs/sanpi/r*.mdx", {
+ query: "?raw",
+ import: "default",
+ eager: true,
+ }) as Record<string, string>;
+
+ const rows: { key: string; row: SanpiBillRow }[] = [];
+
+ for (const [path, source] of Object.entries(sources)) {
+ const key = path.match(/(r\d+d)\.mdx$/)?.[1] ?? "";
+ const year = YEAR_LABELS[key] ?? "";
+ const yearHref = key ? `/sanpi/${key}/` : "";
+ let session = "";
+ let header: string[] | null = null;
+ let meIndex = -1;
+
+ for (const line of source.split(/\r?\n/)) {
+ if (line.startsWith("## ")) {
+ session = line.slice(3).trim();
+ header = null;
+ meIndex = -1;
+ continue;
+ }
+ if (!line.startsWith("|")) {
+ header = null;
+ meIndex = -1;
+ continue;
+ }
+ const cells = splitRow(line);
+ if (isSeparatorRow(cells)) continue;
+ if (header === null) {
+ header = cells;
+ meIndex = header.findIndex((h) => groupLabel(h) === ME_NAME);
+ continue;
+ }
+ if (meIndex < 0) continue;
+ const me = voteChar(cells[meIndex] ?? "") ?? "—";
+ rows.push({
+ key,
+ row: {
+ year,
+ yearHref,
+ session,
+ title: stripTags(cells[0] ?? "").trim(),
+ result: stripTags(cells[1] ?? "").trim(),
+ me,
+ type: billType(cells[0] ?? ""),
+ },
+ });
+ }
+ }
+
+ rows.sort((a, b) => a.key.localeCompare(b.key));
+ return rows.map(({ row }) => row);
+}