prompt-management.blade.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <x-filament-panels::page>
  2. <div class="flex flex-col gap-y-6">
  3. {{-- 统计信息 --}}
  4. <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
  5. <div class="bg-white rounded-lg border border-gray-200 p-4">
  6. <div class="text-sm font-medium text-gray-500">总提示词</div>
  7. <div class="mt-2 text-2xl font-semibold text-gray-900">{{ $this->getPrompts()['meta']['total'] ?? 0 }}</div>
  8. </div>
  9. </div>
  10. {{-- 筛选器 --}}
  11. <div class="bg-white rounded-lg border border-gray-200 p-4">
  12. <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
  13. {{-- 类型筛选 --}}
  14. <div>
  15. <label class="block text-sm font-medium text-gray-700 mb-2">提示词类型</label>
  16. <select
  17. wire:model.live="selectedType"
  18. class="w-full rounded-lg border-gray-300 text-sm"
  19. >
  20. <option value="">全部类型</option>
  21. <option value="题目生成">题目生成</option>
  22. <option value="掌握度评估">掌握度评估</option>
  23. <option value="技能熟练度">技能熟练度</option>
  24. <option value="质量审核">质量审核</option>
  25. </select>
  26. </div>
  27. {{-- 搜索 --}}
  28. <div class="md:col-span-2">
  29. <label class="block text-sm font-medium text-gray-700 mb-2">搜索提示词</label>
  30. <input
  31. type="text"
  32. wire:model.live.debounce.300ms="search"
  33. placeholder="搜索提示词名称或描述..."
  34. class="w-full rounded-lg border-gray-300 text-sm"
  35. />
  36. </div>
  37. </div>
  38. </div>
  39. {{-- 提示词列表 --}}
  40. <div class="bg-white rounded-lg border border-gray-200">
  41. <div class="overflow-x-auto">
  42. <table class="min-w-full divide-y divide-gray-200">
  43. <thead class="bg-gray-50">
  44. <tr>
  45. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">模板名称</th>
  46. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">类型</th>
  47. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">描述</th>
  48. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
  49. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">更新时间</th>
  50. <th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
  51. </tr>
  52. </thead>
  53. <tbody class="bg-white divide-y divide-gray-200">
  54. @forelse($this->getPrompts()['data'] as $prompt)
  55. <tr class="hover:bg-gray-50">
  56. <td class="px-6 py-4 whitespace-nowrap">
  57. <div class="text-sm font-medium text-gray-900">{{ $prompt['template_name'] }}</div>
  58. <div class="text-xs text-gray-500">v{{ $prompt['version'] ?? 1 }}</div>
  59. </td>
  60. <td class="px-6 py-4 whitespace-nowrap">
  61. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
  62. {{ $prompt['template_type'] }}
  63. </span>
  64. </td>
  65. <td class="px-6 py-4">
  66. @php
  67. $description = $prompt['description'] ?? '';
  68. $normalizedDescription = is_array($description)
  69. ? collect($description)->map(fn ($value, $key) => is_string($value) ? "{$key}: {$value}" : $key)->implode(', ')
  70. : (string) $description;
  71. @endphp
  72. <div class="text-sm text-gray-900">{{ Str::limit($normalizedDescription, 50) }}</div>
  73. </td>
  74. <td class="px-6 py-4 whitespace-nowrap">
  75. @if($prompt['is_active'] === 'yes' || $prompt['is_active'] === true)
  76. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  77. 启用
  78. </span>
  79. @else
  80. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800">
  81. 禁用
  82. </span>
  83. @endif
  84. </td>
  85. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  86. {{ \Carbon\Carbon::parse($prompt['updated_at'])->diffForHumans() }}
  87. </td>
  88. <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
  89. <div class="flex justify-end gap-2">
  90. <button
  91. wire:click="editPrompt({{ json_encode($prompt) }})"
  92. class="text-blue-600 hover:text-blue-900"
  93. >
  94. 编辑
  95. </button>
  96. <button
  97. wire:click="duplicatePrompt({{ json_encode($prompt) }})"
  98. class="text-green-600 hover:text-green-900"
  99. >
  100. 复制
  101. </button>
  102. <button
  103. wire:click="togglePrompt('{{ $prompt['template_name'] }}', {{ $prompt['is_active'] === 'yes' || $prompt['is_active'] === true }})"
  104. class="text-amber-600 hover:text-amber-900"
  105. >
  106. {{ $prompt['is_active'] === 'yes' || $prompt['is_active'] === true ? '禁用' : '启用' }}
  107. </button>
  108. <button
  109. wire:click="deletePrompt('{{ $prompt['template_name'] }}')"
  110. class="text-red-600 hover:text-red-900"
  111. onclick="return confirm('确定要删除这个提示词吗?此操作不可恢复。')"
  112. >
  113. 删除
  114. </button>
  115. </div>
  116. </td>
  117. </tr>
  118. @empty
  119. <tr>
  120. <td colspan="6" class="px-6 py-12 text-center text-gray-500">
  121. <div class="flex flex-col items-center">
  122. <svg class="w-12 h-12 text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  123. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
  124. </svg>
  125. <p class="text-lg font-medium">暂无提示词</p>
  126. <p class="text-sm">点击"新建提示词"开始创建</p>
  127. </div>
  128. </td>
  129. </tr>
  130. @endforelse
  131. </tbody>
  132. </table>
  133. </div>
  134. {{-- 分页 --}}
  135. @if(($this->getPrompts()['meta']['total_pages'] ?? 1) > 1)
  136. <div class="border-t border-gray-200 bg-white px-6 py-3 flex items-center justify-between">
  137. <div class="text-sm text-gray-700">
  138. 显示第 {{ (($this->getPrompts()['meta']['page'] ?? 1) - 1) * ($this->getPrompts()['meta']['per_page'] ?? 10) + 1 }} 到
  139. {{ min(($this->getPrompts()['meta']['page'] ?? 1) * ($this->getPrompts()['meta']['per_page'] ?? 10), $this->getPrompts()['meta']['total'] ?? 0) }} 条,
  140. 共 {{ $this->getPrompts()['meta']['total'] ?? 0 }} 条记录
  141. </div>
  142. <div class="flex gap-2">
  143. <button
  144. wire:click="previousPage"
  145. @if(($this->getPrompts()['meta']['page'] ?? 1) <= 1) disabled @endif
  146. class="px-3 py-1 text-sm border rounded {{ ($this->getPrompts()['meta']['page'] ?? 1) <= 1 ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-white hover:bg-gray-50' }}"
  147. >
  148. 上一页
  149. </button>
  150. @for($i = 1; $i <= ($this->getPrompts()['meta']['total_pages'] ?? 1); $i++)
  151. @if($i == ($this->getPrompts()['meta']['page'] ?? 1))
  152. <button
  153. class="px-3 py-1 text-sm border rounded bg-blue-50 text-blue-600 border-blue-300"
  154. >
  155. {{ $i }}
  156. </button>
  157. @else
  158. <button
  159. wire:click="gotoPage({{ $i }})"
  160. class="px-3 py-1 text-sm border rounded bg-white hover:bg-gray-50"
  161. >
  162. {{ $i }}
  163. </button>
  164. @endif
  165. @endfor
  166. <button
  167. wire:click="nextPage"
  168. @if(($this->getPrompts()['meta']['page'] ?? 1) >= ($this->getPrompts()['meta']['total_pages'] ?? 1)) disabled @endif
  169. class="px-3 py-1 text-sm border rounded {{ ($this->getPrompts()['meta']['page'] ?? 1) >= ($this->getPrompts()['meta']['total_pages'] ?? 1) ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-white hover:bg-gray-50' }}"
  170. >
  171. 下一页
  172. </button>
  173. </div>
  174. </div>
  175. @endif
  176. </div>
  177. </div>
  178. </x-filament-panels::page>