backup: 完成 HR_position_ 表格前綴重命名與欄位對照表整理
變更內容: - 所有資料表加上 HR_position_ 前綴 - 整理完整欄位顯示名稱與 ID 對照表 - 模組化 JS 檔案 (admin.js, ai.js, csv.js 等) - 專案結構優化 (docs/, scripts/, tests/ 等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
382
scripts/generate_review.py
Normal file
382
scripts/generate_review.py
Normal file
@@ -0,0 +1,382 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
|
||||
# 讀取表格數據
|
||||
with open('excel_table.md', 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
# 解析數據(跳過表頭和分隔線)
|
||||
data = []
|
||||
for line in lines[2:]: # 跳過表頭和分隔線
|
||||
line = line.strip()
|
||||
if not line or not line.startswith('|'):
|
||||
continue
|
||||
# 移除首尾的管道符號並分割
|
||||
parts = [p.strip() for p in line[1:-1].split('|')]
|
||||
if len(parts) >= 4:
|
||||
data.append({
|
||||
'事業體': parts[0],
|
||||
'處級單位': parts[1],
|
||||
'部級單位': parts[2],
|
||||
'崗位名稱': parts[3]
|
||||
})
|
||||
|
||||
# 生成 HTML
|
||||
html_content = '''<!DOCTYPE html>
|
||||
<html lang="zh-TW">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>組織架構預覽</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Microsoft JhengHei", "微軟正黑體", Arial, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 20px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Header using Float */
|
||||
.header {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden; /* Clear float */
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
float: left;
|
||||
color: #333;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.header .stats {
|
||||
float: right;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.header::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Filter Section using Float */
|
||||
.filters {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
float: left;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.filter-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #555;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.filter-group select,
|
||||
.filter-group input {
|
||||
padding: 8px 12px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.filter-group select:focus,
|
||||
.filter-group input:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.filters::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Table Container using Float */
|
||||
.table-container {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
thead {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid #eee;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(even) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(even):hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 12px 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
font-weight: 600;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
color: #764ba2;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Empty cells styling */
|
||||
td:empty::before {
|
||||
content: "—";
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* Footer using Float */
|
||||
.footer {
|
||||
margin-top: 20px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.filter-group {
|
||||
float: none;
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.filter-group select,
|
||||
.filter-group input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
float: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header .stats {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>📊 公司組織架構預覽</h1>
|
||||
<div class="stats">總計: <span id="totalCount">''' + str(len(data)) + '''</span> 筆資料</div>
|
||||
</div>
|
||||
|
||||
<div class="filters">
|
||||
<div class="filter-group">
|
||||
<label for="filterBusiness">事業體篩選</label>
|
||||
<select id="filterBusiness">
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label for="filterDepartment">處級單位篩選</label>
|
||||
<select id="filterDepartment">
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label for="filterDivision">部級單位篩選</label>
|
||||
<select id="filterDivision">
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-group">
|
||||
<label for="searchPosition">崗位搜尋</label>
|
||||
<input type="text" id="searchPosition" placeholder="輸入崗位名稱...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>事業體</th>
|
||||
<th>處級單位</th>
|
||||
<th>部級單位</th>
|
||||
<th>崗位名稱</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tableBody">
|
||||
'''
|
||||
|
||||
# 添加表格行
|
||||
for row in data:
|
||||
html_content += f''' <tr>
|
||||
<td>{row['事業體']}</td>
|
||||
<td>{row['處級單位'] if row['處級單位'] else ''}</td>
|
||||
<td>{row['部級單位'] if row['部級單位'] else ''}</td>
|
||||
<td>{row['崗位名稱']}</td>
|
||||
</tr>
|
||||
'''
|
||||
|
||||
html_content += ''' </tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>組織架構資料預覽系統 | 使用 CSS Float Layout 設計</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 獲取所有數據
|
||||
const allData = ''' + json.dumps(data, ensure_ascii=False) + ''';
|
||||
|
||||
// 獲取唯一的選項值
|
||||
function getUniqueValues(key) {
|
||||
const values = new Set();
|
||||
allData.forEach(row => {
|
||||
if (row[key]) {
|
||||
values.add(row[key]);
|
||||
}
|
||||
});
|
||||
return Array.from(values).sort();
|
||||
}
|
||||
|
||||
// 填充下拉選單
|
||||
function populateSelects() {
|
||||
const businessSelect = document.getElementById('filterBusiness');
|
||||
const deptSelect = document.getElementById('filterDepartment');
|
||||
const divSelect = document.getElementById('filterDivision');
|
||||
|
||||
getUniqueValues('事業體').forEach(value => {
|
||||
const option = document.createElement('option');
|
||||
option.value = value;
|
||||
option.textContent = value;
|
||||
businessSelect.appendChild(option);
|
||||
});
|
||||
|
||||
getUniqueValues('處級單位').forEach(value => {
|
||||
const option = document.createElement('option');
|
||||
option.value = value;
|
||||
option.textContent = value;
|
||||
deptSelect.appendChild(option);
|
||||
});
|
||||
|
||||
getUniqueValues('部級單位').forEach(value => {
|
||||
const option = document.createElement('option');
|
||||
option.value = value;
|
||||
option.textContent = value;
|
||||
divSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
// 過濾數據
|
||||
function filterData() {
|
||||
const businessFilter = document.getElementById('filterBusiness').value;
|
||||
const deptFilter = document.getElementById('filterDepartment').value;
|
||||
const divFilter = document.getElementById('filterDivision').value;
|
||||
const positionSearch = document.getElementById('searchPosition').value.toLowerCase();
|
||||
|
||||
const filtered = allData.filter(row => {
|
||||
const matchBusiness = !businessFilter || row['事業體'] === businessFilter;
|
||||
const matchDept = !deptFilter || row['處級單位'] === deptFilter;
|
||||
const matchDiv = !divFilter || row['部級單位'] === divFilter;
|
||||
const matchPosition = !positionSearch || row['崗位名稱'].toLowerCase().includes(positionSearch);
|
||||
return matchBusiness && matchDept && matchDiv && matchPosition;
|
||||
});
|
||||
|
||||
renderTable(filtered);
|
||||
document.getElementById('totalCount').textContent = filtered.length;
|
||||
}
|
||||
|
||||
// 渲染表格
|
||||
function renderTable(data) {
|
||||
const tbody = document.getElementById('tableBody');
|
||||
tbody.innerHTML = '';
|
||||
|
||||
data.forEach(row => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${row['事業體'] || ''}</td>
|
||||
<td>${row['處級單位'] || ''}</td>
|
||||
<td>${row['部級單位'] || ''}</td>
|
||||
<td>${row['崗位名稱'] || ''}</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
// 事件監聽
|
||||
document.getElementById('filterBusiness').addEventListener('change', filterData);
|
||||
document.getElementById('filterDepartment').addEventListener('change', filterData);
|
||||
document.getElementById('filterDivision').addEventListener('change', filterData);
|
||||
document.getElementById('searchPosition').addEventListener('input', filterData);
|
||||
|
||||
// 初始化
|
||||
populateSelects();
|
||||
</script>
|
||||
</body>
|
||||
</html>'''
|
||||
|
||||
# 寫入文件
|
||||
with open('review.html', 'w', encoding='utf-8') as f:
|
||||
f.write(html_content)
|
||||
|
||||
print(f"預覽頁面已生成:review.html")
|
||||
print(f"共包含 {len(data)} 筆組織架構資料")
|
||||
|
||||
Reference in New Issue
Block a user