2ND
This commit is contained in:
@@ -19,9 +19,133 @@
|
||||
<label for="signed_file" class="form-label"><strong>已簽核的 PDF 檔案</strong></label>
|
||||
<input class="form-control" type="file" id="signed_file" name="signed_file" accept=".pdf" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">上傳並啟用</button>
|
||||
|
||||
<!-- 郵件通知對象選擇 -->
|
||||
<div class="mb-3">
|
||||
<label for="recipients" class="form-label"><strong>郵件通知對象</strong></label>
|
||||
<select id="recipients" multiple placeholder="請輸入姓名或 Email 來搜尋...">
|
||||
</select>
|
||||
<input type="hidden" id="recipients-hidden" name="recipients" value="" />
|
||||
<div class="form-text">可搜尋姓名或 Email 地址,支援多人選擇</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-success" onclick="submitFormWithDebug()">上傳並啟用</button>
|
||||
<a href="{{ url_for('temp_spec.spec_list') }}" class="btn btn-secondary">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function updateHiddenField() {
|
||||
if (window.recipientTomSelect) {
|
||||
const selectedValues = window.recipientTomSelect.getValue();
|
||||
const hiddenField = document.getElementById('recipients-hidden');
|
||||
hiddenField.value = Array.isArray(selectedValues) ? selectedValues.join(',') : selectedValues;
|
||||
console.log('[DEBUG] 更新隱藏字段:', hiddenField.value);
|
||||
}
|
||||
}
|
||||
|
||||
function submitFormWithDebug() {
|
||||
// 確保隱藏字段有最新的值
|
||||
updateHiddenField();
|
||||
|
||||
const recipientSelect = document.getElementById('recipients');
|
||||
const hiddenField = document.getElementById('recipients-hidden');
|
||||
const selectedValues = Array.from(recipientSelect.selectedOptions).map(option => option.value);
|
||||
|
||||
console.log('[FORM DEBUG] 表單提交時選中的收件者:', selectedValues);
|
||||
console.log('[FORM DEBUG] Recipients input value:', recipientSelect.value);
|
||||
console.log('[FORM DEBUG] Hidden field value:', hiddenField.value);
|
||||
|
||||
// 確認 Tom Select 的值
|
||||
if (window.recipientTomSelect) {
|
||||
console.log('[FORM DEBUG] Tom Select getValue():', window.recipientTomSelect.getValue());
|
||||
}
|
||||
|
||||
// 發送除錯資訊到後端
|
||||
const debugData = {
|
||||
selectedValues: selectedValues,
|
||||
recipientValue: recipientSelect.value,
|
||||
hiddenFieldValue: hiddenField.value,
|
||||
tomSelectValue: window.recipientTomSelect ? window.recipientTomSelect.getValue() : null
|
||||
};
|
||||
|
||||
// 透過 fetch 發送除錯資訊
|
||||
fetch('/api/debug-form', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(debugData)
|
||||
}).then(() => {
|
||||
console.log('[FORM DEBUG] 除錯資訊已發送,準備提交表單...');
|
||||
// 延遲一點點後提交表單
|
||||
setTimeout(() => {
|
||||
document.querySelector('form').submit();
|
||||
}, 200);
|
||||
}).catch(error => {
|
||||
console.error('Debug sending failed:', error);
|
||||
// 即使除錯失敗也要提交表單
|
||||
document.querySelector('form').submit();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const recipientSelect = new TomSelect('#recipients', {
|
||||
valueField: 'value',
|
||||
labelField: 'text',
|
||||
searchField: 'text',
|
||||
placeholder: '請輸入姓名或 Email 來搜尋...',
|
||||
plugins: ['remove_button'],
|
||||
maxItems: null,
|
||||
create: false,
|
||||
load: function(query, callback) {
|
||||
if (!query || query.length < 2) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/ldap-search?q=${encodeURIComponent(query)}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
callback(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('LDAP search error:', error);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
onItemAdd: function(value, item) {
|
||||
// 選擇項目後清空搜尋框
|
||||
this.setTextboxValue('');
|
||||
this.refreshOptions(false);
|
||||
// 更新隱藏字段
|
||||
updateHiddenField();
|
||||
},
|
||||
onItemRemove: function(value) {
|
||||
// 移除項目時更新隱藏字段
|
||||
updateHiddenField();
|
||||
},
|
||||
render: {
|
||||
option: function(item, escape) {
|
||||
return `<div class="py-1">${escape(item.text)}</div>`;
|
||||
},
|
||||
item: function(item, escape) {
|
||||
// 移除藍底背景,改用淺灰背景
|
||||
return `<div class="badge bg-light text-dark border me-1">${escape(item.text)}</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 將 Tom Select 實例儲存到全域變數以便偵錯
|
||||
window.recipientTomSelect = recipientSelect;
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@@ -14,6 +14,8 @@
|
||||
<link rel="stylesheet" href="https://uicdn.toast.com/editor-plugin-color-syntax/latest/toastui-editor-plugin-color-syntax.min.css" />
|
||||
<link rel="stylesheet" href="https://uicdn.toast.com/editor-plugin-table-merged-cell/latest/toastui-editor-plugin-table-merged-cell.min.css" />
|
||||
<link rel="stylesheet" href="https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.min.css">
|
||||
<!-- Tom Select CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.bootstrap5.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
@@ -35,7 +37,7 @@
|
||||
</li>
|
||||
{% if current_user.role == 'admin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('admin.user_list') }}">帳號管理</a>
|
||||
<a class="nav-link" href="{{ url_for('admin.user_list') }}">權限管理</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item">
|
||||
@@ -82,6 +84,8 @@
|
||||
<!-- Plugins JS -->
|
||||
<script src="https://uicdn.toast.com/editor-plugin-color-syntax/latest/toastui-editor-plugin-color-syntax.min.js"></script>
|
||||
<script src="https://uicdn.toast.com/editor-plugin-table-merged-cell/latest/toastui-editor-plugin-table-merged-cell.min.js"></script>
|
||||
<!-- Tom Select JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/js/tom-select.complete.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 啟用所有 Toast
|
||||
|
@@ -27,9 +27,68 @@
|
||||
<div class="form-text">請上傳展延申請的相關佐證文件 (PDF 格式)。</div>
|
||||
</div>
|
||||
|
||||
<!-- 郵件通知對象選擇 -->
|
||||
<div class="mb-3">
|
||||
<label for="recipients" class="form-label"><strong>郵件通知對象</strong></label>
|
||||
<select id="recipients" name="recipients" multiple placeholder="請輸入姓名或 Email 來搜尋...">
|
||||
</select>
|
||||
<div class="form-text">可搜尋姓名或 Email 地址,支援多人選擇</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">確認展延</button>
|
||||
<a href="{{ url_for('temp_spec.spec_list') }}" class="btn btn-secondary">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const recipientSelect = new TomSelect('#recipients', {
|
||||
valueField: 'value',
|
||||
labelField: 'text',
|
||||
searchField: 'text',
|
||||
placeholder: '請輸入姓名或 Email 來搜尋...',
|
||||
plugins: ['remove_button'],
|
||||
maxItems: null,
|
||||
create: false,
|
||||
load: function(query, callback) {
|
||||
if (!query || query.length < 2) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/ldap-search?q=${encodeURIComponent(query)}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
callback(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('LDAP search error:', error);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
onItemAdd: function(value, item) {
|
||||
// 選擇項目後清空搜尋框
|
||||
this.setTextboxValue('');
|
||||
this.refreshOptions(false);
|
||||
},
|
||||
render: {
|
||||
option: function(item, escape) {
|
||||
return `<div class="py-1">${escape(item.text)}</div>`;
|
||||
},
|
||||
item: function(item, escape) {
|
||||
// 移除藍底背景,改用淺灰背景
|
||||
return `<div class="badge bg-light text-dark border me-1">${escape(item.text)}</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
@@ -22,8 +22,10 @@
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">使用者帳號</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
<label for="username" class="form-label">使用者帳號 (完整格式)</label>
|
||||
<input type="email" class="form-control" id="username" name="username"
|
||||
placeholder="請輸入完整AD帳號 (如: user@domain.com)" required>
|
||||
<div class="form-text text-light fw-bold">請輸入完整的 AD 帳號格式 (包含 @domain)</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">密碼</label>
|
||||
@@ -33,10 +35,6 @@
|
||||
<button type="submit" class="btn btn-primary">登入</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="text-center mt-3">
|
||||
<p class="mb-0">還沒有帳號嗎?</p>
|
||||
<a href="{{ url_for('auth.register') }}" class="btn btn-outline-success">立即註冊</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,47 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}註冊新帳號 - 暫時規範系統{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<h2 class="text-center mb-4">建立新帳號</h2>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category or 'danger' }} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">使用者帳號</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">密碼</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirm_password" class="form-label">確認密碼</label>
|
||||
<input type="password" class="form-control" id="confirm_password" name="confirm_password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-success">註冊</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ url_for('auth.login') }}">已經有帳號了?返回登入</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -19,9 +19,69 @@
|
||||
<label for="reason" class="form-label"><strong>提早結束原因</strong></label>
|
||||
<textarea class="form-control" id="reason" name="reason" rows="4" required></textarea>
|
||||
</div>
|
||||
|
||||
<!-- 郵件通知對象選擇 -->
|
||||
<div class="mb-3">
|
||||
<label for="recipients" class="form-label"><strong>郵件通知對象</strong></label>
|
||||
<select id="recipients" name="recipients" multiple placeholder="請輸入姓名或 Email 來搜尋...">
|
||||
</select>
|
||||
<div class="form-text">可搜尋姓名或 Email 地址,支援多人選擇</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-danger">確認終止</button>
|
||||
<a href="{{ url_for('temp_spec.spec_list') }}" class="btn btn-secondary">取消</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const recipientSelect = new TomSelect('#recipients', {
|
||||
valueField: 'value',
|
||||
labelField: 'text',
|
||||
searchField: 'text',
|
||||
placeholder: '請輸入姓名或 Email 來搜尋...',
|
||||
plugins: ['remove_button'],
|
||||
maxItems: null,
|
||||
create: false,
|
||||
load: function(query, callback) {
|
||||
if (!query || query.length < 2) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/ldap-search?q=${encodeURIComponent(query)}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
callback(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('LDAP search error:', error);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
onItemAdd: function(value, item) {
|
||||
// 選擇項目後清空搜尋框
|
||||
this.setTextboxValue('');
|
||||
this.refreshOptions(false);
|
||||
},
|
||||
render: {
|
||||
option: function(item, escape) {
|
||||
return `<div class="py-1">${escape(item.text)}</div>`;
|
||||
},
|
||||
item: function(item, escape) {
|
||||
// 移除藍底背景,改用淺灰背景
|
||||
return `<div class="badge bg-light text-dark border me-1">${escape(item.text)}</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}帳號管理{% endblock %}
|
||||
{% block title %}權限管理{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4">帳號管理</h2>
|
||||
<h2 class="mb-4">權限管理</h2>
|
||||
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
@@ -16,76 +16,219 @@
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- 新增使用者表單 -->
|
||||
<!-- 設定新管理員 -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
新增使用者
|
||||
<div class="card-header bg-primary text-white">
|
||||
<i class="bi bi-person-plus-fill"></i> 設定管理員權限
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="{{ url_for('admin.create_user') }}" method="post" class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="username" class="form-control" placeholder="使用者名稱" required>
|
||||
<form action="{{ url_for('admin.set_admin') }}" method="post" class="row g-3">
|
||||
<div class="col-md-8">
|
||||
<label for="username" class="form-label">AD 帳號</label>
|
||||
<input type="text" name="username" class="form-control" id="username"
|
||||
placeholder="例如:user@panjit.com.tw 或 username" required>
|
||||
<div class="form-text">輸入需要設定為管理員的 AD 帳號</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="password" name="password" class="form-control" placeholder="密碼" required>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select name="role" class="form-select" required>
|
||||
<option value="viewer">Viewer</option>
|
||||
<option value="editor">Editor</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">建立</button>
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-shield-check"></i> 設定為管理員
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 使用者列表 -->
|
||||
<!-- 現有使用者權限管理 -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
現有使用者列表
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<i class="bi bi-people-fill"></i> 現有使用者權限管理
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>使用者名稱</th>
|
||||
<th>權限</th>
|
||||
<th>上次登入</th>
|
||||
<th colspan="2">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.id }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<form action="{{ url_for('admin.edit_user', user_id=user.id) }}" method="post" class="d-inline">
|
||||
{% if users %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>AD 帳號</th>
|
||||
<th>目前權限</th>
|
||||
<th>上次登入</th>
|
||||
<th>權限管理</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr {% if user.id == current_user.id %}class="table-warning"{% endif %}>
|
||||
<td>{{ user.id }}</td>
|
||||
<td>
|
||||
<select name="role" class="form-select form-select-sm">
|
||||
<option value="viewer" {% if user.role == 'viewer' %}selected{% endif %}>Viewer</option>
|
||||
<option value="editor" {% if user.role == 'editor' %}selected{% endif %}>Editor</option>
|
||||
<option value="admin" {% if user.role == 'admin' %}selected{% endif %}>Admin</option>
|
||||
</select>
|
||||
{{ user.username }}
|
||||
{% if user.id == current_user.id %}
|
||||
<span class="badge bg-info ms-1">目前使用者</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ user.last_login.strftime('%Y-%m-%d %H:%M') if user.last_login else '從未' }}</td>
|
||||
<td>
|
||||
<button type="submit" class="btn btn-sm btn-success">更新</button>
|
||||
<span class="badge
|
||||
{% if user.role == 'admin' %}bg-danger
|
||||
{% elif user.role == 'editor' %}bg-warning text-dark
|
||||
{% else %}bg-secondary
|
||||
{% endif %}">
|
||||
{% if user.role == 'admin' %}
|
||||
<i class="bi bi-shield-fill"></i> 管理員
|
||||
{% elif user.role == 'editor' %}
|
||||
<i class="bi bi-pencil-fill"></i> 編輯者
|
||||
{% else %}
|
||||
<i class="bi bi-eye-fill"></i> 檢視者
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
</form>
|
||||
<td>
|
||||
<form action="{{ url_for('admin.delete_user', user_id=user.id) }}" method="post" onsubmit="return confirm('確定要刪除這位使用者嗎?');" class="d-inline">
|
||||
<button type="submit" class="btn btn-sm btn-danger" {% if user.id == current_user.id %}disabled{% endif %}>刪除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<td>
|
||||
{% if user.last_login %}
|
||||
{{ user.last_login.strftime('%Y-%m-%d %H:%M') }}
|
||||
{% else %}
|
||||
<span class="text-muted">從未登入</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<form action="{{ url_for('admin.edit_user_role', user_id=user.id) }}"
|
||||
method="post" class="d-inline">
|
||||
<div class="input-group input-group-sm">
|
||||
<select name="role" class="form-select form-select-sm">
|
||||
<option value="viewer" {% if user.role == 'viewer' %}selected{% endif %}>
|
||||
檢視者 (Viewer)
|
||||
</option>
|
||||
<option value="editor" {% if user.role == 'editor' %}selected{% endif %}>
|
||||
編輯者 (Editor)
|
||||
</option>
|
||||
<option value="admin" {% if user.role == 'admin' %}selected{% endif %}>
|
||||
管理員 (Admin)
|
||||
</option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-check-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
{% if user.id != current_user.id %}
|
||||
<form action="{{ url_for('admin.delete_user', user_id=user.id) }}"
|
||||
method="post"
|
||||
onsubmit="return confirm('確定要刪除使用者 {{ user.username }} 嗎?此操作無法復原!');"
|
||||
class="d-inline">
|
||||
<button type="submit" class="btn btn-outline-danger btn-sm">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" disabled
|
||||
title="無法刪除自己的帳號">
|
||||
<i class="bi bi-shield-x"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i>
|
||||
目前沒有任何使用者記錄。使用者會在首次透過 AD 登入時自動建立。
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 權限說明 -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-info-circle"></i> 權限等級說明
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<h6><span class="badge bg-secondary"><i class="bi bi-eye-fill"></i> 檢視者 (Viewer)</span></h6>
|
||||
<ul class="small">
|
||||
<li>登入系統</li>
|
||||
<li>檢視規範列表</li>
|
||||
<li>下載已生效的 PDF 文件</li>
|
||||
<li>查看歷史記錄</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6><span class="badge bg-warning text-dark"><i class="bi bi-pencil-fill"></i> 編輯者 (Editor)</span></h6>
|
||||
<ul class="small">
|
||||
<li>包含 Viewer 所有權限</li>
|
||||
<li>建立新的暫時規範</li>
|
||||
<li>編輯規範內容</li>
|
||||
<li>展延規範</li>
|
||||
<li>終止規範</li>
|
||||
<li>下載 Word 編輯檔案</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6><span class="badge bg-danger"><i class="bi bi-shield-fill"></i> 管理員 (Admin)</span></h6>
|
||||
<ul class="small">
|
||||
<li>包含 Editor 所有權限</li>
|
||||
<li>啟用待生效的規範</li>
|
||||
<li>管理使用者權限</li>
|
||||
<li>刪除規範</li>
|
||||
<li>系統設定管理</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LDAP 整合說明 -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<i class="bi bi-diagram-3"></i> LDAP/AD 整合說明
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>系統運作方式:</strong></p>
|
||||
<ol>
|
||||
<li>使用者首次使用 AD 帳號登入時,系統會自動建立本地使用者記錄,預設權限為 <code>viewer</code></li>
|
||||
<li>管理員可以在此頁面調整使用者權限等級</li>
|
||||
<li>使用者的身份認證完全由 Active Directory 處理,本系統不儲存密碼</li>
|
||||
<li>刪除本地使用者記錄不會影響 AD 帳號,使用者仍可重新登入(但會重置為 viewer 權限)</li>
|
||||
</ol>
|
||||
|
||||
<div class="alert alert-warning mt-3">
|
||||
<i class="bi bi-exclamation-triangle"></i>
|
||||
<strong>重要提醒:</strong>確保至少保留一個管理員帳號,避免無法進行權限管理。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// 自動提交表單當選擇權限改變時的確認
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const roleSelects = document.querySelectorAll('select[name="role"]');
|
||||
roleSelects.forEach(select => {
|
||||
select.addEventListener('change', function() {
|
||||
const form = this.closest('form');
|
||||
const username = form.closest('tr').querySelector('td:nth-child(2)').textContent.trim();
|
||||
const newRole = this.value;
|
||||
|
||||
if (confirm(`確定要將使用者 "${username}" 的權限變更為 "${newRole}" 嗎?`)) {
|
||||
// 使用者確認後自動提交
|
||||
setTimeout(() => {
|
||||
form.submit();
|
||||
}, 100);
|
||||
} else {
|
||||
// 使用者取消,恢復原來的選擇
|
||||
this.selectedIndex = this.getAttribute('data-original-index') || 0;
|
||||
}
|
||||
});
|
||||
|
||||
// 記錄原始選擇索引
|
||||
select.setAttribute('data-original-index', select.selectedIndex);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user