prompt-management.blade.php 13 KB

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