Add membership fee system with disability discount and fix document permissions
Features: - Implement two fee types: entrance fee and annual fee (both NT$1,000) - Add 50% discount for disability certificate holders - Add disability certificate upload in member profile - Integrate disability verification into cashier approval workflow - Add membership fee settings in system admin Document permissions: - Fix hard-coded role logic in Document model - Use permission-based authorization instead of role checks Additional features: - Add announcements, general ledger, and trial balance modules - Add income management and accounting entries - Add comprehensive test suite with factories - Update UI translations to Traditional Chinese 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
|
||||
{{ __('Create Task') }} (建立任務)
|
||||
新增任務 (建立任務)
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
@@ -14,22 +14,22 @@
|
||||
<!-- Title -->
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Title') }} <span class="text-red-500">*</span>
|
||||
標題 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input type="text" name="title" id="title" value="{{ old('title') }}" required maxlength="255"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('title') border-red-300 @enderror"
|
||||
placeholder="{{ __('Brief summary of the task') }}">
|
||||
placeholder="任務簡述">
|
||||
@error('title')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Description') }}
|
||||
描述
|
||||
</label>
|
||||
<textarea name="description" id="description" rows="5"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100"
|
||||
placeholder="{{ __('Detailed description of the task...') }}">{{ old('description') }}</textarea>
|
||||
placeholder="詳細描述此任務...">{{ old('description') }}</textarea>
|
||||
@error('description')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
@@ -37,30 +37,30 @@
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="issue_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Task Type') }} <span class="text-red-500">*</span>
|
||||
任務類型 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="issue_type" id="issue_type" required
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('issue_type') border-red-300 @enderror">
|
||||
<option value="">{{ __('Select type...') }}</option>
|
||||
<option value="work_item" @selected(old('issue_type') === 'work_item')>{{ __('Work Item') }}</option>
|
||||
<option value="project_task" @selected(old('issue_type') === 'project_task')>{{ __('Project Task') }}</option>
|
||||
<option value="maintenance" @selected(old('issue_type') === 'maintenance')>{{ __('Maintenance') }}</option>
|
||||
<option value="member_request" @selected(old('issue_type') === 'member_request')>{{ __('Member Request') }}</option>
|
||||
<option value="">選擇類型...</option>
|
||||
<option value="work_item" @selected(old('issue_type') === 'work_item')>工作項目</option>
|
||||
<option value="project_task" @selected(old('issue_type') === 'project_task')>專案任務</option>
|
||||
<option value="maintenance" @selected(old('issue_type') === 'maintenance')>維護</option>
|
||||
<option value="member_request" @selected(old('issue_type') === 'member_request')>會員請求</option>
|
||||
</select>
|
||||
@error('issue_type')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="priority" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Priority') }} <span class="text-red-500">*</span>
|
||||
優先級 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="priority" id="priority" required
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('priority') border-red-300 @enderror">
|
||||
<option value="">{{ __('Select priority...') }}</option>
|
||||
<option value="low" @selected(old('priority') === 'low')>{{ __('Low') }} ↓</option>
|
||||
<option value="medium" @selected(old('priority', 'medium') === 'medium')>{{ __('Medium') }} →</option>
|
||||
<option value="high" @selected(old('priority') === 'high')>{{ __('High') }} ↑</option>
|
||||
<option value="urgent" @selected(old('priority') === 'urgent')>{{ __('Urgent') }} ⇈</option>
|
||||
<option value="">選擇優先級...</option>
|
||||
<option value="low" @selected(old('priority') === 'low')>低 ↓</option>
|
||||
<option value="medium" @selected(old('priority', 'medium') === 'medium')>中 →</option>
|
||||
<option value="high" @selected(old('priority') === 'high')>高 ↑</option>
|
||||
<option value="urgent" @selected(old('priority') === 'urgent')>緊急 ⇈</option>
|
||||
</select>
|
||||
@error('priority')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
@@ -70,21 +70,21 @@
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="assigned_to_user_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Assign To') }}
|
||||
指派給
|
||||
</label>
|
||||
<select name="assigned_to_user_id" id="assigned_to_user_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('Unassigned') }}</option>
|
||||
<option value="">未指派</option>
|
||||
@foreach($users as $user)
|
||||
<option value="{{ $user->id }}" @selected(old('assigned_to_user_id') == $user->id)>{{ $user->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ __('Optional: Assign to a team member') }}</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">選填:指派給團隊成員</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="due_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Due Date') }}
|
||||
截止日期
|
||||
</label>
|
||||
<input type="date" name="due_date" id="due_date" value="{{ old('due_date') }}"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
@@ -95,50 +95,50 @@
|
||||
<!-- Estimated Hours -->
|
||||
<div>
|
||||
<label for="estimated_hours" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Estimated Hours') }}
|
||||
預估時數
|
||||
</label>
|
||||
<input type="number" name="estimated_hours" id="estimated_hours" value="{{ old('estimated_hours') }}" step="0.5" min="0"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100"
|
||||
placeholder="0.0">
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ __('Estimated time to complete this task') }}</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">完成此任務的預估時間</p>
|
||||
</div>
|
||||
|
||||
<!-- Member (for member requests) -->
|
||||
<div>
|
||||
<label for="member_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Related Member') }}
|
||||
相關會員
|
||||
</label>
|
||||
<select name="member_id" id="member_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('None') }}</option>
|
||||
<option value="">無</option>
|
||||
@foreach($members as $member)
|
||||
<option value="{{ $member->id }}" @selected(old('member_id') == $member->id)>{{ $member->full_name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ __('Link to a member for member requests') }}</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">連結至會員(用於會員請求)</p>
|
||||
</div>
|
||||
|
||||
<!-- Parent Task (for sub-tasks) -->
|
||||
<div>
|
||||
<label for="parent_issue_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Parent Task') }}
|
||||
父任務
|
||||
</label>
|
||||
<select name="parent_issue_id" id="parent_issue_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('None (top-level task)') }}</option>
|
||||
<option value="">無(頂層任務)</option>
|
||||
@foreach($openIssues as $parentIssue)
|
||||
<option value="{{ $parentIssue->id }}" @selected(old('parent_issue_id') == $parentIssue->id)>
|
||||
{{ $parentIssue->issue_number }} - {{ $parentIssue->title }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">{{ __('Make this a sub-task of another task') }}</p>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">將此設為另一個任務的子任務</p>
|
||||
</div>
|
||||
|
||||
<!-- Labels -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{{ __('Labels') }}
|
||||
標籤
|
||||
</label>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
||||
@foreach($labels as $label)
|
||||
@@ -153,18 +153,18 @@
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">{{ __('Select one or more labels to categorize this task') }}</p>
|
||||
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">選擇一個或多個標籤來分類此任務</p>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex items-center justify-end gap-x-4 border-t border-gray-200 pt-6 dark:border-gray-700">
|
||||
<a href="{{ route('admin.issues.index') }}"
|
||||
class="rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-600">
|
||||
{{ __('Cancel') }}
|
||||
取消
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="inline-flex justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-indigo-500 dark:hover:bg-indigo-400 dark:focus:ring-offset-gray-800">
|
||||
{{ __('Create Task') }}
|
||||
新增任務
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -179,14 +179,14 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">{{ __('Creating Tasks') }}</h3>
|
||||
<h3 class="text-sm font-medium text-blue-800 dark:text-blue-200">建立任務</h3>
|
||||
<div class="mt-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
<ul class="list-disc pl-5 space-y-1">
|
||||
<li>{{ __('Use work items for general tasks and todos') }}</li>
|
||||
<li>{{ __('Project tasks are for specific project milestones') }}</li>
|
||||
<li>{{ __('Member requests track inquiries or requests from members') }}</li>
|
||||
<li>{{ __('Assign tasks to team members to track responsibility') }}</li>
|
||||
<li>{{ __('Use labels to categorize and filter tasks easily') }}</li>
|
||||
<li>使用工作項目處理一般任務和待辦事項</li>
|
||||
<li>專案任務用於特定的專案里程碑</li>
|
||||
<li>會員請求追蹤來自會員的查詢或請求</li>
|
||||
<li>將任務指派給團隊成員以追蹤責任歸屬</li>
|
||||
<li>使用標籤輕鬆分類和篩選任務</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
|
||||
{{ __('Edit Issue') }} - {{ $issue->issue_number }}
|
||||
編輯任務 - {{ $issue->issue_number }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
<!-- Title -->
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Title') }} <span class="text-red-500">*</span>
|
||||
標題 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input type="text" name="title" id="title" value="{{ old('title', $issue->title) }}" required maxlength="255"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('title') border-red-300 @enderror"
|
||||
placeholder="{{ __('Brief summary of the issue') }}">
|
||||
placeholder="任務簡述">
|
||||
@error('title')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div>
|
||||
<label for="description" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Description') }}
|
||||
描述
|
||||
</label>
|
||||
<textarea name="description" id="description" rows="5"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100"
|
||||
placeholder="{{ __('Detailed description of the issue...') }}">{{ old('description', $issue->description) }}</textarea>
|
||||
placeholder="詳細描述此任務...">{{ old('description', $issue->description) }}</textarea>
|
||||
@error('description')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
@@ -38,30 +38,30 @@
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="issue_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Issue Type') }} <span class="text-red-500">*</span>
|
||||
任務類型 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="issue_type" id="issue_type" required
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('issue_type') border-red-300 @enderror">
|
||||
<option value="">{{ __('Select type...') }}</option>
|
||||
<option value="work_item" @selected(old('issue_type', $issue->issue_type) === 'work_item')>{{ __('Work Item') }}</option>
|
||||
<option value="project_task" @selected(old('issue_type', $issue->issue_type) === 'project_task')>{{ __('Project Task') }}</option>
|
||||
<option value="maintenance" @selected(old('issue_type', $issue->issue_type) === 'maintenance')>{{ __('Maintenance') }}</option>
|
||||
<option value="member_request" @selected(old('issue_type', $issue->issue_type) === 'member_request')>{{ __('Member Request') }}</option>
|
||||
<option value="">選擇類型...</option>
|
||||
<option value="work_item" @selected(old('issue_type', $issue->issue_type) === 'work_item')>工作項目</option>
|
||||
<option value="project_task" @selected(old('issue_type', $issue->issue_type) === 'project_task')>專案任務</option>
|
||||
<option value="maintenance" @selected(old('issue_type', $issue->issue_type) === 'maintenance')>維護</option>
|
||||
<option value="member_request" @selected(old('issue_type', $issue->issue_type) === 'member_request')>會員請求</option>
|
||||
</select>
|
||||
@error('issue_type')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="priority" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Priority') }} <span class="text-red-500">*</span>
|
||||
優先級 <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<select name="priority" id="priority" required
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 @error('priority') border-red-300 @enderror">
|
||||
<option value="">{{ __('Select priority...') }}</option>
|
||||
<option value="low" @selected(old('priority', $issue->priority) === 'low')>{{ __('Low') }} ↓</option>
|
||||
<option value="medium" @selected(old('priority', $issue->priority) === 'medium')>{{ __('Medium') }} →</option>
|
||||
<option value="high" @selected(old('priority', $issue->priority) === 'high')>{{ __('High') }} ↑</option>
|
||||
<option value="urgent" @selected(old('priority', $issue->priority) === 'urgent')>{{ __('Urgent') }} ⇈</option>
|
||||
<option value="">選擇優先級...</option>
|
||||
<option value="low" @selected(old('priority', $issue->priority) === 'low')>低 ↓</option>
|
||||
<option value="medium" @selected(old('priority', $issue->priority) === 'medium')>中 →</option>
|
||||
<option value="high" @selected(old('priority', $issue->priority) === 'high')>高 ↑</option>
|
||||
<option value="urgent" @selected(old('priority', $issue->priority) === 'urgent')>緊急 ⇈</option>
|
||||
</select>
|
||||
@error('priority')<p class="mt-1 text-sm text-red-600 dark:text-red-400">{{ $message }}</p>@enderror
|
||||
</div>
|
||||
@@ -71,11 +71,11 @@
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="assigned_to_user_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Assign To') }}
|
||||
指派給
|
||||
</label>
|
||||
<select name="assigned_to_user_id" id="assigned_to_user_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('Unassigned') }}</option>
|
||||
<option value="">未指派</option>
|
||||
@foreach($users as $user)
|
||||
<option value="{{ $user->id }}" @selected(old('assigned_to_user_id', $issue->assigned_to_user_id) == $user->id)>{{ $user->name }}</option>
|
||||
@endforeach
|
||||
@@ -84,11 +84,11 @@
|
||||
|
||||
<div>
|
||||
<label for="reviewer_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Reviewer') }}
|
||||
審查者
|
||||
</label>
|
||||
<select name="reviewer_id" id="reviewer_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('None') }}</option>
|
||||
<option value="">無</option>
|
||||
@foreach($users as $user)
|
||||
<option value="{{ $user->id }}" @selected(old('reviewer_id', $issue->reviewer_id) == $user->id)>{{ $user->name }}</option>
|
||||
@endforeach
|
||||
@@ -100,7 +100,7 @@
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<label for="due_date" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Due Date') }}
|
||||
截止日期
|
||||
</label>
|
||||
<input type="date" name="due_date" id="due_date" value="{{ old('due_date', $issue->due_date?->format('Y-m-d')) }}"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<div>
|
||||
<label for="estimated_hours" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Estimated Hours') }}
|
||||
預估時數
|
||||
</label>
|
||||
<input type="number" name="estimated_hours" id="estimated_hours" value="{{ old('estimated_hours', $issue->estimated_hours) }}" step="0.5" min="0"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
@@ -119,11 +119,11 @@
|
||||
<!-- Member (for member requests) -->
|
||||
<div>
|
||||
<label for="member_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Related Member') }}
|
||||
相關會員
|
||||
</label>
|
||||
<select name="member_id" id="member_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('None') }}</option>
|
||||
<option value="">無</option>
|
||||
@foreach($members as $member)
|
||||
<option value="{{ $member->id }}" @selected(old('member_id', $issue->member_id) == $member->id)>{{ $member->full_name }}</option>
|
||||
@endforeach
|
||||
@@ -133,11 +133,11 @@
|
||||
<!-- Parent Issue (for sub-tasks) -->
|
||||
<div>
|
||||
<label for="parent_issue_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ __('Parent Issue') }}
|
||||
父任務
|
||||
</label>
|
||||
<select name="parent_issue_id" id="parent_issue_id"
|
||||
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('None (top-level issue)') }}</option>
|
||||
<option value="">無(頂層任務)</option>
|
||||
@foreach($openIssues as $parentIssue)
|
||||
<option value="{{ $parentIssue->id }}" @selected(old('parent_issue_id', $issue->parent_issue_id) == $parentIssue->id)>
|
||||
{{ $parentIssue->issue_number }} - {{ $parentIssue->title }}
|
||||
@@ -149,7 +149,7 @@
|
||||
<!-- Labels -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
{{ __('Labels') }}
|
||||
標籤
|
||||
</label>
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
||||
@foreach($labels as $label)
|
||||
@@ -170,11 +170,11 @@
|
||||
<div class="flex items-center justify-end gap-x-4 border-t border-gray-200 pt-6 dark:border-gray-700">
|
||||
<a href="{{ route('admin.issues.show', $issue) }}"
|
||||
class="rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-600">
|
||||
{{ __('Cancel') }}
|
||||
取消
|
||||
</a>
|
||||
<button type="submit"
|
||||
class="inline-flex justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-indigo-500 dark:hover:bg-indigo-400 dark:focus:ring-offset-gray-800">
|
||||
{{ __('Update Issue') }}
|
||||
更新任務
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
|
||||
{{ __('Tasks') }} (任務追蹤)
|
||||
任務管理 (任務追蹤)
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
<!-- Header -->
|
||||
<div class="sm:flex sm:items-center sm:justify-between mb-6">
|
||||
<div>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">{{ __('Task Tracker') }}</h3>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">{{ __('Manage work items, tasks, and member requests') }}</p>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100">任務追蹤器</h3>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">管理工作項目、任務和會員請求</p>
|
||||
</div>
|
||||
<div class="mt-4 sm:mt-0">
|
||||
<a href="{{ route('admin.issues.create') }}" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:bg-indigo-500 dark:hover:bg-indigo-400 dark:focus:ring-offset-gray-800">
|
||||
<svg class="-ml-0.5 mr-1.5 h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"/></svg>
|
||||
{{ __('Create Task') }}
|
||||
新增任務
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,19 +37,19 @@
|
||||
<!-- Summary Stats -->
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-4 mb-6">
|
||||
<div class="bg-blue-50 dark:bg-blue-900/30 rounded-lg p-4 border-l-4 border-blue-400">
|
||||
<dt class="text-sm font-medium text-blue-800 dark:text-blue-200">{{ __('Total Open') }}</dt>
|
||||
<dt class="text-sm font-medium text-blue-800 dark:text-blue-200">總開啟數</dt>
|
||||
<dd class="mt-1 text-2xl font-semibold text-blue-900 dark:text-blue-100">{{ $stats['total_open'] }}</dd>
|
||||
</div>
|
||||
<div class="bg-purple-50 dark:bg-purple-900/30 rounded-lg p-4 border-l-4 border-purple-400">
|
||||
<dt class="text-sm font-medium text-purple-800 dark:text-purple-200">{{ __('Assigned to Me') }}</dt>
|
||||
<dt class="text-sm font-medium text-purple-800 dark:text-purple-200">指派給我</dt>
|
||||
<dd class="mt-1 text-2xl font-semibold text-purple-900 dark:text-purple-100">{{ $stats['assigned_to_me'] }}</dd>
|
||||
</div>
|
||||
<div class="bg-red-50 dark:bg-red-900/30 rounded-lg p-4 border-l-4 border-red-400">
|
||||
<dt class="text-sm font-medium text-red-800 dark:text-red-200">{{ __('Overdue') }}</dt>
|
||||
<dt class="text-sm font-medium text-red-800 dark:text-red-200">逾期</dt>
|
||||
<dd class="mt-1 text-2xl font-semibold text-red-900 dark:text-red-100">{{ $stats['overdue'] }}</dd>
|
||||
</div>
|
||||
<div class="bg-orange-50 dark:bg-orange-900/30 rounded-lg p-4 border-l-4 border-orange-400">
|
||||
<dt class="text-sm font-medium text-orange-800 dark:text-orange-200">{{ __('High Priority') }}</dt>
|
||||
<dt class="text-sm font-medium text-orange-800 dark:text-orange-200">高優先級</dt>
|
||||
<dd class="mt-1 text-2xl font-semibold text-orange-900 dark:text-orange-100">{{ $stats['high_priority'] }}</dd>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,40 +58,40 @@
|
||||
<form method="GET" class="mb-6 space-y-4" role="search">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-4">
|
||||
<div>
|
||||
<label for="issue_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Type') }}</label>
|
||||
<label for="issue_type" class="block text-sm font-medium text-gray-700 dark:text-gray-300">類型</label>
|
||||
<select name="issue_type" id="issue_type" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('All Types') }}</option>
|
||||
<option value="work_item" @selected(request('issue_type') === 'work_item')>{{ __('Work Item') }}</option>
|
||||
<option value="project_task" @selected(request('issue_type') === 'project_task')>{{ __('Project Task') }}</option>
|
||||
<option value="maintenance" @selected(request('issue_type') === 'maintenance')>{{ __('Maintenance') }}</option>
|
||||
<option value="member_request" @selected(request('issue_type') === 'member_request')>{{ __('Member Request') }}</option>
|
||||
<option value="">所有類型</option>
|
||||
<option value="work_item" @selected(request('issue_type') === 'work_item')>工作項目</option>
|
||||
<option value="project_task" @selected(request('issue_type') === 'project_task')>專案任務</option>
|
||||
<option value="maintenance" @selected(request('issue_type') === 'maintenance')>維護</option>
|
||||
<option value="member_request" @selected(request('issue_type') === 'member_request')>會員請求</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Status') }}</label>
|
||||
<label for="status" class="block text-sm font-medium text-gray-700 dark:text-gray-300">狀態</label>
|
||||
<select name="status" id="status" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('All Statuses') }}</option>
|
||||
<option value="new" @selected(request('status') === 'new')>{{ __('New') }}</option>
|
||||
<option value="assigned" @selected(request('status') === 'assigned')>{{ __('Assigned') }}</option>
|
||||
<option value="in_progress" @selected(request('status') === 'in_progress')>{{ __('In Progress') }}</option>
|
||||
<option value="review" @selected(request('status') === 'review')>{{ __('Review') }}</option>
|
||||
<option value="closed" @selected(request('status') === 'closed')>{{ __('Closed') }}</option>
|
||||
<option value="">所有狀態</option>
|
||||
<option value="new" @selected(request('status') === 'new')>新</option>
|
||||
<option value="assigned" @selected(request('status') === 'assigned')>已指派</option>
|
||||
<option value="in_progress" @selected(request('status') === 'in_progress')>進行中</option>
|
||||
<option value="review" @selected(request('status') === 'review')>審查</option>
|
||||
<option value="closed" @selected(request('status') === 'closed')>已結案</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="priority" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Priority') }}</label>
|
||||
<label for="priority" class="block text-sm font-medium text-gray-700 dark:text-gray-300">優先級</label>
|
||||
<select name="priority" id="priority" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('All Priorities') }}</option>
|
||||
<option value="low" @selected(request('priority') === 'low')>{{ __('Low') }}</option>
|
||||
<option value="medium" @selected(request('priority') === 'medium')>{{ __('Medium') }}</option>
|
||||
<option value="high" @selected(request('priority') === 'high')>{{ __('High') }}</option>
|
||||
<option value="urgent" @selected(request('priority') === 'urgent')>{{ __('Urgent') }}</option>
|
||||
<option value="">所有優先級</option>
|
||||
<option value="low" @selected(request('priority') === 'low')>低</option>
|
||||
<option value="medium" @selected(request('priority') === 'medium')>中</option>
|
||||
<option value="high" @selected(request('priority') === 'high')>高</option>
|
||||
<option value="urgent" @selected(request('priority') === 'urgent')>緊急</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="assigned_to" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Assignee') }}</label>
|
||||
<label for="assigned_to" class="block text-sm font-medium text-gray-700 dark:text-gray-300">指派對象</label>
|
||||
<select name="assigned_to" id="assigned_to" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('All Assignees') }}</option>
|
||||
<option value="">所有指派對象</option>
|
||||
@foreach($users as $user)
|
||||
<option value="{{ $user->id }}" @selected(request('assigned_to') == $user->id)>{{ $user->name }}</option>
|
||||
@endforeach
|
||||
@@ -100,14 +100,14 @@
|
||||
</div>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-1">
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Search') }}</label>
|
||||
<input type="text" name="search" id="search" value="{{ request('search') }}" placeholder="{{ __('Task number, title, or description...') }}" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300">搜尋</label>
|
||||
<input type="text" name="search" id="search" value="{{ request('search') }}" placeholder="任務編號、標題或描述..." class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
</div>
|
||||
<div class="flex items-end gap-2">
|
||||
<button type="submit" class="inline-flex justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-600">{{ __('Filter') }}</button>
|
||||
<button type="submit" class="inline-flex justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-600">篩選</button>
|
||||
<label class="inline-flex items-center">
|
||||
<input type="checkbox" name="show_closed" value="1" @checked(request('show_closed') === '1') class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600">
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">{{ __('Show closed') }}</span>
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">顯示已結案</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,16 +116,16 @@
|
||||
<!-- Issues Table -->
|
||||
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg dark:ring-gray-700">
|
||||
<table class="min-w-full divide-y divide-gray-300 dark:divide-gray-600">
|
||||
<caption class="sr-only">{{ __('List of tasks with their current status and assignment') }}</caption>
|
||||
<caption class="sr-only">任務列表及其目前狀態與指派</caption>
|
||||
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||
<tr>
|
||||
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Task') }}</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Type') }}</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Status') }}</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Priority') }}</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Assignee') }}</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">{{ __('Due Date') }}</th>
|
||||
<th scope="col" class="relative py-3.5 pl-3 pr-4"><span class="sr-only">{{ __('Actions') }}</span></th>
|
||||
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">任務</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">類型</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">狀態</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">優先級</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">指派對象</th>
|
||||
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">截止日期</th>
|
||||
<th scope="col" class="relative py-3.5 pl-3 pr-4"><span class="sr-only">操作</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-800">
|
||||
@@ -163,7 +163,7 @@
|
||||
<span class="{{ $issue->is_overdue ? 'text-red-600 dark:text-red-400 font-semibold' : '' }}">
|
||||
{{ $issue->due_date->format('Y-m-d') }}
|
||||
@if($issue->is_overdue)
|
||||
<span class="text-xs">({{ __('Overdue') }})</span>
|
||||
<span class="text-xs">(逾期)</span>
|
||||
@endif
|
||||
</span>
|
||||
@else
|
||||
@@ -171,16 +171,16 @@
|
||||
@endif
|
||||
</td>
|
||||
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium">
|
||||
<a href="{{ route('admin.issues.show', $issue) }}" class="text-indigo-600 hover:text-indigo-900 dark:text-indigo-400 dark:hover:text-indigo-300">{{ __('View') }}</a>
|
||||
<a href="{{ route('admin.issues.show', $issue) }}" class="text-indigo-600 hover:text-indigo-900 dark:text-indigo-400 dark:hover:text-indigo-300">檢視</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="px-3 py-8 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
<p>{{ __('No tasks found') }}</p>
|
||||
<p>找不到任務</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ route('admin.issues.create') }}" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 dark:bg-indigo-500 dark:hover:bg-indigo-400">
|
||||
+ {{ __('Create First Task') }}
|
||||
+ 新增第一個任務
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -31,23 +31,23 @@
|
||||
<div class="flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span>{{ $issue->issue_type_label }}</span>
|
||||
<span>"</span>
|
||||
<span>{{ __('Created by') }} {{ $issue->creator->name }}</span>
|
||||
<span>建立者 {{ $issue->creator->name }}</span>
|
||||
<span>"</span>
|
||||
<span>{{ $issue->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 sm:mt-0 flex gap-2">
|
||||
@if(!$issue->isClosed() || Auth::user()->is_admin)
|
||||
@if(!$issue->isClosed() || Auth::user()->hasRole('admin'))
|
||||
<a href="{{ route('admin.issues.edit', $issue) }}" class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600">
|
||||
{{ __('Edit') }}
|
||||
編輯
|
||||
</a>
|
||||
@endif
|
||||
@if(Auth::user()->is_admin)
|
||||
<form method="POST" action="{{ route('admin.issues.destroy', $issue) }}" onsubmit="return confirm('{{ __('Are you sure?') }}')">
|
||||
@if(Auth::user()->hasRole('admin'))
|
||||
<form method="POST" action="{{ route('admin.issues.destroy', $issue) }}" onsubmit="return confirm('您確定嗎?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 dark:bg-red-500 dark:hover:bg-red-400">
|
||||
{{ __('Delete') }}
|
||||
刪除
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
@@ -68,55 +68,55 @@
|
||||
|
||||
<!-- Description -->
|
||||
<div class="prose dark:prose-invert max-w-none mb-6">
|
||||
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">{{ __('Description') }}</h4>
|
||||
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">描述</h4>
|
||||
<div class="text-gray-700 dark:text-gray-300 whitespace-pre-wrap">{{ $issue->description ?: __('No description provided') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Details Grid -->
|
||||
<dl class="grid grid-cols-1 gap-x-4 gap-y-6 sm:grid-cols-2 border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Assigned To') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">指派對象</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">{{ $issue->assignee?->name ?? __('Unassigned') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Reviewer') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">審查者</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">{{ $issue->reviewer?->name ?? __('None') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Due Date') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">截止日期</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
||||
@if($issue->due_date)
|
||||
<span class="{{ $issue->is_overdue ? 'text-red-600 dark:text-red-400 font-semibold' : '' }}">
|
||||
{{ $issue->due_date->format('Y-m-d') }}
|
||||
@if($issue->is_overdue)
|
||||
({{ __('Overdue by :days days', ['days' => abs($issue->days_until_due)]) }})
|
||||
(逾期 {{ abs($issue->days_until_due) }} 天)
|
||||
@elseif($issue->days_until_due !== null && $issue->days_until_due >= 0)
|
||||
({{ __(':days days left', ['days' => $issue->days_until_due]) }})
|
||||
({{ $issue->days_until_due }} 天剩餘)
|
||||
@endif
|
||||
</span>
|
||||
@else
|
||||
<span class="text-gray-400">{{ __('No due date') }}</span>
|
||||
<span class="text-gray-400">無截止日期</span>
|
||||
@endif
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Time Tracking') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">時間追蹤</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
||||
{{ number_format($issue->actual_hours, 1) }}h
|
||||
@if($issue->estimated_hours)
|
||||
/ {{ number_format($issue->estimated_hours, 1) }}h {{ __('estimated') }}
|
||||
/ {{ number_format($issue->estimated_hours, 1) }}h 預估
|
||||
@endif
|
||||
</dd>
|
||||
</div>
|
||||
@if($issue->member)
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Related Member') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">相關會員</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">{{ $issue->member->full_name }}</dd>
|
||||
</div>
|
||||
@endif
|
||||
@if($issue->parentIssue)
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ __('Parent Issue') }}</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">父任務</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
||||
<a href="{{ route('admin.issues.show', $issue->parentIssue) }}" class="text-indigo-600 hover:underline dark:text-indigo-400">
|
||||
{{ $issue->parentIssue->issue_number }} - {{ $issue->parentIssue->title }}
|
||||
@@ -129,7 +129,7 @@
|
||||
<!-- Sub-tasks -->
|
||||
@if($issue->subTasks->count() > 0)
|
||||
<div class="mt-6 border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">{{ __('Sub-tasks') }} ({{ $issue->subTasks->count() }})</h4>
|
||||
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">子任務 ({{ $issue->subTasks->count() }})</h4>
|
||||
<ul class="space-y-2">
|
||||
@foreach($issue->subTasks as $subTask)
|
||||
<li class="flex items-center gap-2">
|
||||
@@ -150,21 +150,21 @@
|
||||
<!-- Workflow Actions -->
|
||||
@if(!$issue->isClosed())
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">{{ __('Actions') }}</h3>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">操作</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<!-- Update Status -->
|
||||
<form method="POST" action="{{ route('admin.issues.update-status', $issue) }}" class="inline-flex gap-2">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<select name="status" class="rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="new" @selected($issue->status === 'new')>{{ __('New') }}</option>
|
||||
<option value="assigned" @selected($issue->status === 'assigned')>{{ __('Assigned') }}</option>
|
||||
<option value="in_progress" @selected($issue->status === 'in_progress')>{{ __('In Progress') }}</option>
|
||||
<option value="review" @selected($issue->status === 'review')>{{ __('Review') }}</option>
|
||||
<option value="closed" @selected($issue->status === 'closed')>{{ __('Closed') }}</option>
|
||||
<option value="new" @selected($issue->status === 'new')>新</option>
|
||||
<option value="assigned" @selected($issue->status === 'assigned')>已指派</option>
|
||||
<option value="in_progress" @selected($issue->status === 'in_progress')>進行中</option>
|
||||
<option value="review" @selected($issue->status === 'review')>審查</option>
|
||||
<option value="closed" @selected($issue->status === 'closed')>已結案</option>
|
||||
</select>
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 dark:bg-indigo-500 dark:hover:bg-indigo-400">
|
||||
{{ __('Update Status') }}
|
||||
更新狀態
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -172,13 +172,13 @@
|
||||
<form method="POST" action="{{ route('admin.issues.assign', $issue) }}" class="inline-flex gap-2">
|
||||
@csrf
|
||||
<select name="assigned_to_user_id" class="rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('Unassigned') }}</option>
|
||||
<option value="">未指派</option>
|
||||
@foreach($users as $user)
|
||||
<option value="{{ $user->id }}" @selected($issue->assigned_to_user_id == $user->id)>{{ $user->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 dark:bg-gray-700 dark:text-gray-100 dark:ring-gray-600">
|
||||
{{ __('Assign') }}
|
||||
指派
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -188,7 +188,7 @@
|
||||
<!-- Comments -->
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">
|
||||
{{ __('Comments') }} ({{ $issue->comments->count() }})
|
||||
留言 ({{ $issue->comments->count() }})
|
||||
</h3>
|
||||
|
||||
<!-- Comments List -->
|
||||
@@ -199,13 +199,13 @@
|
||||
<span class="font-medium text-sm text-gray-900 dark:text-gray-100">{{ $comment->user->name }}</span>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ $comment->created_at->diffForHumans() }}</span>
|
||||
@if($comment->is_internal)
|
||||
<span class="text-xs bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 px-2 py-0.5 rounded">{{ __('Internal') }}</span>
|
||||
<span class="text-xs bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200 px-2 py-0.5 rounded">內部</span>
|
||||
@endif
|
||||
</div>
|
||||
<p class="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap">{{ $comment->comment_text }}</p>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">{{ __('No comments yet') }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">尚無留言</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
@@ -214,14 +214,14 @@
|
||||
@csrf
|
||||
<textarea name="comment_text" rows="3" required
|
||||
class="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100 mb-2"
|
||||
placeholder="{{ __('Add a comment...') }}"></textarea>
|
||||
placeholder="新增留言..."></textarea>
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="inline-flex items-center">
|
||||
<input type="checkbox" name="is_internal" value="1" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600">
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">{{ __('Internal comment') }}</span>
|
||||
<span class="ml-2 text-sm text-gray-700 dark:text-gray-300">內部留言</span>
|
||||
</label>
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 dark:bg-indigo-500">
|
||||
{{ __('Add Comment') }}
|
||||
新增留言
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -230,7 +230,7 @@
|
||||
<!-- Attachments -->
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">
|
||||
{{ __('Attachments') }} ({{ $issue->attachments->count() }})
|
||||
附件 ({{ $issue->attachments->count() }})
|
||||
</h3>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
@@ -246,18 +246,18 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<a href="{{ route('admin.issues.attachments.download', $attachment) }}" class="text-indigo-600 hover:text-indigo-900 dark:text-indigo-400 text-sm">{{ __('Download') }}</a>
|
||||
@if(Auth::user()->is_admin)
|
||||
<form method="POST" action="{{ route('admin.issues.attachments.destroy', $attachment) }}" onsubmit="return confirm('{{ __('Delete this attachment?') }}')">
|
||||
<a href="{{ route('admin.issues.attachments.download', $attachment) }}" class="text-indigo-600 hover:text-indigo-900 dark:text-indigo-400 text-sm">下載</a>
|
||||
@if(Auth::user()->hasRole('admin'))
|
||||
<form method="POST" action="{{ route('admin.issues.attachments.destroy', $attachment) }}" onsubmit="return confirm('刪除此附件?')">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="text-red-600 hover:text-red-900 dark:text-red-400 text-sm">{{ __('Delete') }}</button>
|
||||
<button type="submit" class="text-red-600 hover:text-red-900 dark:text-red-400 text-sm">刪除</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">{{ __('No attachments') }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">無附件</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
@@ -267,17 +267,17 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="file" name="file" required class="block w-full text-sm text-gray-900 dark:text-gray-100 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 dark:file:bg-indigo-900 dark:file:text-indigo-200">
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 dark:bg-indigo-500">
|
||||
{{ __('Upload') }}
|
||||
上傳
|
||||
</button>
|
||||
</div>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ __('Max size: 10MB') }}</p>
|
||||
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">最大大小:10MB</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Time Logs -->
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">
|
||||
{{ __('Time Tracking') }} ({{ number_format($issue->total_time_logged, 1) }}h total)
|
||||
時間追蹤 ({{ number_format($issue->total_time_logged, 1) }}h total)
|
||||
</h3>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
@@ -289,21 +289,21 @@
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">{{ __('No time logged yet') }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center py-4">尚未記錄時間</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<!-- Log Time Form -->
|
||||
<form method="POST" action="{{ route('admin.issues.time-logs.store', $issue) }}" class="border-t border-gray-200 dark:border-gray-700 pt-4 grid grid-cols-2 gap-2">
|
||||
@csrf
|
||||
<input type="number" name="hours" step="0.25" min="0.25" placeholder="{{ __('Hours') }}" required
|
||||
<input type="number" name="hours" step="0.25" min="0.25" placeholder="時數" required
|
||||
class="rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<input type="date" name="logged_at" value="{{ now()->format('Y-m-d') }}" required
|
||||
class="rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<input type="text" name="description" placeholder="{{ __('What did you do?') }}"
|
||||
<input type="text" name="description" placeholder="您做了什麼?"
|
||||
class="col-span-2 rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<button type="submit" class="col-span-2 inline-flex justify-center items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 dark:bg-indigo-500">
|
||||
{{ __('Log Time') }}
|
||||
記錄時間
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -313,11 +313,11 @@
|
||||
<div class="space-y-6">
|
||||
<!-- Timeline -->
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">{{ __('Progress') }}</h3>
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">進度</h3>
|
||||
<x-issue.timeline :issue="$issue" />
|
||||
<div class="mt-4">
|
||||
<div class="flex justify-between text-sm mb-1">
|
||||
<span class="text-gray-700 dark:text-gray-300">{{ __('Completion') }}</span>
|
||||
<span class="text-gray-700 dark:text-gray-300">完成度</span>
|
||||
<span class="font-medium text-gray-900 dark:text-gray-100">{{ $issue->progress_percentage }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
||||
@@ -329,7 +329,7 @@
|
||||
<!-- Watchers -->
|
||||
<div class="bg-white shadow sm:rounded-lg dark:bg-gray-800 px-4 py-5 sm:p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-4">
|
||||
{{ __('Watchers') }} ({{ $issue->watchers->count() }})
|
||||
觀察者 ({{ $issue->watchers->count() }})
|
||||
</h3>
|
||||
|
||||
<ul class="space-y-2 mb-4">
|
||||
@@ -341,7 +341,7 @@
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<input type="hidden" name="user_id" value="{{ $watcher->id }}">
|
||||
<button type="submit" class="text-xs text-red-600 hover:text-red-900 dark:text-red-400">{{ __('Remove') }}</button>
|
||||
<button type="submit" class="text-xs text-red-600 hover:text-red-900 dark:text-red-400">移除</button>
|
||||
</form>
|
||||
@endif
|
||||
</li>
|
||||
@@ -353,13 +353,13 @@
|
||||
@csrf
|
||||
<div class="flex gap-2">
|
||||
<select name="user_id" required class="flex-1 rounded-md border-gray-300 text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-gray-100">
|
||||
<option value="">{{ __('Add watcher...') }}</option>
|
||||
<option value="">新增觀察者...</option>
|
||||
@foreach($users->whereNotIn('id', $issue->watchers->pluck('id')) as $user)
|
||||
<option value="{{ $user->id }}">{{ $user->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 dark:bg-indigo-500">
|
||||
{{ __('Add') }}
|
||||
新增
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user