index.blade.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. @extends('base.base')
  2. @section('base')
  3. <div class="main-panel">
  4. <div class="content-wrapper">
  5. <div class="row">
  6. <div class="col-12 grid-margin stretch-card">
  7. <div class="card">
  8. <div class="card-body">
  9. <h4 class="card-title">个控回报配置</h4>
  10. <p class="card-description">配置不同个控区间和倍率的权重调节</p>
  11. <!-- 游戏选择 -->
  12. <div class="form-group" style="margin-bottom: 20px;">
  13. <label for="game_select" style="font-weight: bold; margin-right: 10px;">选择游戏:</label>
  14. <select id="game_select" class="form-control" style="width: 300px; display: inline-block;" onchange="switchGame(this.value)">
  15. @foreach($games as $id => $name)
  16. <option value="{{ $id }}" {{ $id == $gameId ? 'selected' : '' }}>
  17. {{ $name }} (GameID: {{ $id }})
  18. </option>
  19. @endforeach
  20. </select>
  21. <span style="margin-left: 20px; color: #666;">
  22. 当前显示:<strong>{{ $games[$gameId] ?? 'Unknown' }}</strong> 的配置
  23. </span>
  24. </div>
  25. <style>
  26. .table-wrapper {
  27. max-height: calc(100vh - 250px);
  28. overflow-y: auto;
  29. position: relative;
  30. border: 1px solid #ddd;
  31. }
  32. .config-table {
  33. width: 100%;
  34. border-collapse: collapse;
  35. margin: 0;
  36. background: #fff;
  37. }
  38. .config-table th,
  39. .config-table td {
  40. border: 1px solid #ddd;
  41. padding: 8px;
  42. text-align: center;
  43. font-size: 14px;
  44. }
  45. .config-table thead {
  46. position: sticky;
  47. top: 0;
  48. z-index: 100;
  49. }
  50. .config-table th {
  51. background-color: #4CAF50;
  52. color: white;
  53. font-weight: bold;
  54. position: sticky;
  55. top: 0;
  56. box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.4);
  57. }
  58. .config-table tbody tr:nth-child(even) {
  59. background-color: #f9f9f9;
  60. }
  61. .config-table tbody tr:hover {
  62. background-color: #f0f0f0;
  63. }
  64. .config-table input[type="number"],
  65. .config-table input[type="text"] {
  66. width: 95%;
  67. padding: 5px;
  68. border: 1px solid transparent;
  69. border-radius: 3px;
  70. text-align: center;
  71. background: transparent;
  72. cursor: pointer;
  73. }
  74. .config-table input[type="number"]:focus,
  75. .config-table input[type="text"]:focus {
  76. border: 1px solid #4CAF50;
  77. background: #fff;
  78. outline: none;
  79. box-shadow: 0 0 5px rgba(76, 175, 80, 0.3);
  80. }
  81. .config-table input[type="number"]:read-only,
  82. .config-table input[type="text"]:read-only {
  83. cursor: pointer;
  84. }
  85. .config-table input[type="checkbox"] {
  86. width: 20px;
  87. height: 20px;
  88. cursor: pointer;
  89. }
  90. .editable-cell {
  91. cursor: pointer;
  92. position: relative;
  93. }
  94. .editable-cell:hover::after {
  95. content: '✎';
  96. position: absolute;
  97. right: 5px;
  98. top: 50%;
  99. transform: translateY(-50%);
  100. color: #4CAF50;
  101. font-size: 14px;
  102. }
  103. .group-header {
  104. background-color: #2196F3 !important;
  105. color: white !important;
  106. font-weight: bold;
  107. position: sticky;
  108. z-index: 50;
  109. }
  110. .field-label {
  111. color: #ccc;
  112. font-size: 11px;
  113. }
  114. /* 滚动条美化 */
  115. .table-wrapper::-webkit-scrollbar {
  116. width: 8px;
  117. }
  118. .table-wrapper::-webkit-scrollbar-track {
  119. background: #f1f1f1;
  120. border-radius: 4px;
  121. }
  122. .table-wrapper::-webkit-scrollbar-thumb {
  123. background: #888;
  124. border-radius: 4px;
  125. }
  126. .table-wrapper::-webkit-scrollbar-thumb:hover {
  127. background: #555;
  128. }
  129. </style>
  130. <form id="configForm">
  131. <div class="table-wrapper">
  132. <table class="config-table">
  133. <thead>
  134. <tr>
  135. <th>ID</th>
  136. <th>个控最小值<br><span class="field-label">(ZMin)</span></th>
  137. <th>个控最大值<br><span class="field-label">(ZMax)</span></th>
  138. <th>倍率最小<br><span class="field-label">(MultiMin)</span></th>
  139. <th>倍率最大<br><span class="field-label">(MultiMax)</span></th>
  140. <th>权重<br><span class="field-label">(Weight)</span></th>
  141. <th>个控调节<br><span class="field-label">(WeightAdjust)</span></th>
  142. </tr>
  143. </thead>
  144. <tbody>
  145. @if(count($configs) == 0)
  146. <tr>
  147. <td colspan="7" style="text-align: center; padding: 40px; color: #999;">
  148. <i class="mdi mdi-alert-circle" style="font-size: 48px;"></i>
  149. <p style="margin-top: 10px; font-size: 16px;">该游戏暂无配置数据</p>
  150. </td>
  151. </tr>
  152. @else
  153. @php
  154. $currentGroup = null;
  155. @endphp
  156. @foreach($configs as $config)
  157. @php
  158. $groupKey = $config->ZMin . '-' . $config->ZMax;
  159. $isNewGroup = ($groupKey !== $currentGroup);
  160. $currentGroup = $groupKey;
  161. @endphp
  162. @if($isNewGroup)
  163. <tr class="group-header">
  164. <td colspan="7">个控区间:{{ $config->ZMin }} - {{ $config->ZMax }}</td>
  165. </tr>
  166. @endif
  167. <tr>
  168. <td>{{ $config->ConfigID }}</td>
  169. <td>
  170. <input type="number"
  171. name="configs[{{ $config->ConfigID }}][ZMin]"
  172. value="{{ $config->ZMin }}"
  173. min="0"
  174. step="1">
  175. </td>
  176. <td>
  177. <input type="number"
  178. name="configs[{{ $config->ConfigID }}][ZMax]"
  179. value="{{ $config->ZMax }}"
  180. min="0"
  181. step="1">
  182. </td>
  183. <td>
  184. <input type="number"
  185. name="configs[{{ $config->ConfigID }}][MultiMin]"
  186. value="{{ number_format($config->MultiMin, 2, '.', '') }}"
  187. min="0"
  188. step="0.01">
  189. </td>
  190. <td>
  191. <input type="number"
  192. name="configs[{{ $config->ConfigID }}][MultiMax]"
  193. value="{{ number_format($config->MultiMax, 2, '.', '') }}"
  194. min="0"
  195. step="0.01">
  196. </td>
  197. <td>
  198. <input type="number"
  199. name="configs[{{ $config->ConfigID }}][Weight]"
  200. value="{{ $config->Weight }}"
  201. min="0"
  202. step="1">
  203. </td>
  204. <td>
  205. <input type="text"
  206. name="configs[{{ $config->ConfigID }}][WeightAdjust]"
  207. value="{{ $config->WeightAdjust }}"
  208. placeholder="如: 15000-300Z"
  209. style="width: 120px;">
  210. </td>
  211. </tr>
  212. @endforeach
  213. @endif
  214. </tbody>
  215. </table>
  216. </div>
  217. @if(count($configs) > 0)
  218. <div style="text-align: center; margin: 20px 0;">
  219. <button type="button" class="btn btn-primary btn-lg" onclick="saveConfig()">保存配置</button>
  220. </div>
  221. @endif
  222. </form>
  223. <script>
  224. // 切换游戏
  225. function switchGame(gameId) {
  226. // 检查是否有未保存的修改
  227. let hasUnsavedChanges = false;
  228. $('input[name^="configs"]').each(function() {
  229. const name = $(this).attr('name');
  230. const currentValue = $(this).val();
  231. if (originalData[name] && originalData[name] !== currentValue) {
  232. hasUnsavedChanges = true;
  233. return false; // break
  234. }
  235. });
  236. if (hasUnsavedChanges) {
  237. if (!confirm('有未保存的修改,确定要切换游戏吗?')) {
  238. // 恢复选择
  239. $('#game_select').val('{{ $gameId }}');
  240. return;
  241. }
  242. }
  243. // 切换到选择的游戏
  244. window.location.href = '/admin/game-some-config?game_id=' + gameId;
  245. }
  246. // 保存原始数据
  247. const originalData = {};
  248. $(document).ready(function() {
  249. // 记录所有字段的原始值
  250. $('input[name^="configs"]').each(function() {
  251. const name = $(this).attr('name');
  252. if ($(this).attr('type') === 'checkbox') {
  253. originalData[name] = $(this).prop('checked');
  254. } else {
  255. originalData[name] = $(this).val();
  256. // 设置为只读,点击后才能编辑
  257. $(this).attr('readonly', true);
  258. }
  259. });
  260. // 点击input时移除只读,进入编辑模式
  261. $('input[type="number"], input[type="text"]').on('click', function() {
  262. $(this).attr('readonly', false);
  263. $(this).select(); // 选中内容,方便修改
  264. });
  265. // 失去焦点时恢复只读
  266. $('input[type="number"], input[type="text"]').on('blur', function() {
  267. $(this).attr('readonly', true);
  268. });
  269. });
  270. function saveConfig() {
  271. // 收集有变动的数据
  272. const changedData = {};
  273. let hasChanges = false;
  274. $('input[name^="configs"]').each(function() {
  275. const name = $(this).attr('name');
  276. let currentValue;
  277. if ($(this).attr('type') === 'checkbox') {
  278. currentValue = $(this).prop('checked');
  279. } else {
  280. currentValue = $(this).val();
  281. }
  282. // 只添加有变动的字段
  283. if (originalData[name] !== currentValue) {
  284. changedData[name] = currentValue;
  285. hasChanges = true;
  286. }
  287. });
  288. if (!hasChanges) {
  289. layer.msg('没有数据被修改', {icon: 0});
  290. return;
  291. }
  292. // 构建只包含变动数据的表单
  293. const formData = $.param(changedData);
  294. layer.msg('正在保存 ' + Object.keys(changedData).length + ' 个变动...', {icon: 16, time: 0, shade: 0.3});
  295. $.ajax({
  296. url: '/admin/game-some-config/update',
  297. type: 'POST',
  298. data: formData,
  299. dataType: 'json',
  300. success: function(res) {
  301. layer.closeAll();
  302. if (res.code === 200) {
  303. layer.msg('配置更新成功!', {icon: 1});
  304. setTimeout(function() {
  305. location.reload();
  306. }, 1000);
  307. } else {
  308. layer.msg('更新失败: ' + (res.msg || '未知错误'), {icon: 2});
  309. }
  310. },
  311. error: function(xhr) {
  312. layer.closeAll();
  313. layer.msg('请求失败: ' + xhr.statusText, {icon: 2});
  314. }
  315. });
  316. }
  317. </script>
  318. </div>
  319. </div>
  320. </div>
  321. </div>
  322. </div>
  323. </div>
  324. @endsection