index.html 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Your Electron App</title>
  5. <style>
  6. #nav {
  7. /* 导航栏样式 */
  8. }
  9. #content {
  10. /* 内容区样式 */
  11. }
  12. #level-list {
  13. width: 200px;
  14. float: left;
  15. }
  16. #level-details {
  17. margin-left: 210px;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <div id="nav">
  23. <button id="levels">关卡</button>
  24. <button id="examples">实例</button>
  25. <button id="templates">模板</button>
  26. </div>
  27. <div id="content">
  28. <!-- 动态内容 -->
  29. </div>
  30. <script>
  31. var levels = null;
  32. var instances = null;
  33. var templateFNs = null;
  34. function getInstanceByName(name) {
  35. for (let i = 0; i < instances.length; i++) {
  36. if (instances[i].lvinst == name) {
  37. return instances[i];
  38. }
  39. }
  40. return null;
  41. }
  42. function getTemplateByName(name) {
  43. for (let i = 0; i < templateFNs.length; i++) {
  44. if (templateFNs[i] == name) {
  45. return templateFNs[i];
  46. }
  47. }
  48. return null;
  49. }
  50. function getAllLvIdsByInstName(name) {
  51. // 返回所有用到了该实例的关卡的id
  52. const ids = [];
  53. for (let i = 0; i < levels.length; i++) {
  54. if (levels[i].lvinst == name) {
  55. ids.push(levels[i].lvid);
  56. }
  57. }
  58. return ids;
  59. }
  60. function saveInst(div, inst) {
  61. // 从 div中获取实例信息
  62. const instName = div.querySelector('#instid-in-inst-detail').textContent.split(':')[1].trim();
  63. var inst = null;
  64. for (let i = 0; i < instances.length; i++) {
  65. if (instances[i].lvinst == instName) {
  66. inst = instances[i];
  67. break;
  68. }
  69. }
  70. if (inst == null) {
  71. alert('实例不存在');
  72. return;
  73. }
  74. inst['template'] = div.querySelector('#template-select').value;
  75. for (let i = 1; i <= 10; i++) {
  76. const tileCnt = div.querySelector('#try' + i + '_tileCnt').value;
  77. const seed = div.querySelector('#try' + i + '_seed').value;
  78. const param_template = div.querySelector('#try' + i + '_param_template').value;
  79. const trynParams = tileCnt + '|' + seed + '|' + param_template;
  80. inst['try' + i + '(tileCnt|seed|param_template)'] = trynParams;
  81. }
  82. window.electron.send('save2csv', '../../conf/levelInstInfo.csv', instances);
  83. }
  84. function showInstanceInfoAt(div, inst) {
  85. // 将其显示在页面上,其中template应该是一个下拉框
  86. // try1-10应该是一个表格, 表格的头部应该是:尝试次数,瓦片数,种子,参数模板,表格里面的每个值是可以编辑的
  87. div.innerHTML = `
  88. <h2 id='instid-in-inst-detail'>实例名: ${inst.lvinst}</h2>
  89. `;
  90. // 显示所有用到了该实例的关卡
  91. const lvIds = getAllLvIdsByInstName(inst.lvinst);
  92. div.innerHTML += `
  93. <p>用到了该实例的关卡: ${lvIds}</p>
  94. `;
  95. // 加入 template 下拉框
  96. div.innerHTML += `
  97. <p id='tempid-in-inst-detail'>模板名称: </p>
  98. `;
  99. const templateSelect = document.createElement('select');
  100. templateSelect.id = 'template-select';
  101. templateFNs.forEach(fn => {
  102. const option = document.createElement('option');
  103. option.value = fn;
  104. option.textContent = fn;
  105. if (fn == inst.template) {
  106. option.selected = true;
  107. }
  108. templateSelect.appendChild(option);
  109. });
  110. div.appendChild(templateSelect);
  111. // 加入表格
  112. const table = document.createElement('table');
  113. const thead = document.createElement('thead');
  114. const tbody = document.createElement('tbody');
  115. const tr = document.createElement('tr');
  116. const th1 = document.createElement('th');
  117. const th2 = document.createElement('th');
  118. const th3 = document.createElement('th');
  119. const th4 = document.createElement('th');
  120. th1.textContent = '尝试次数';
  121. th2.textContent = '瓦片数';
  122. th3.textContent = '种子';
  123. th4.textContent = '参数模板';
  124. tr.appendChild(th1);
  125. tr.appendChild(th2);
  126. tr.appendChild(th3);
  127. tr.appendChild(th4);
  128. thead.appendChild(tr);
  129. table.appendChild(thead);
  130. table.appendChild(tbody);
  131. div.appendChild(table);
  132. // 加入表格内容
  133. for (let i = 1; i <= 10; i++) {
  134. var trynParams = inst['try' + i + '(tileCnt|seed|param_template)'].split('|');
  135. const tr = document.createElement('tr');
  136. const td1 = document.createElement('td');
  137. const td2 = document.createElement('td');
  138. const td3 = document.createElement('td');
  139. const td4 = document.createElement('td');
  140. const input1 = document.createElement('input');
  141. const input2 = document.createElement('input');
  142. const input3 = document.createElement('input');
  143. const input4 = document.createElement('input');
  144. input1.type = 'text';
  145. input1.value = trynParams[0];
  146. input1.id = 'try' + i + '_tileCnt';
  147. input2.type = 'text';
  148. input2.value = trynParams[1];
  149. input2.id = 'try' + i + '_seed';
  150. input3.type = 'text';
  151. input3.value = trynParams[2];
  152. input3.id = 'try' + i + '_param_template';
  153. td1.textContent = i;
  154. td2.appendChild(input1);
  155. td3.appendChild(input2);
  156. td4.appendChild(input3);
  157. tr.appendChild(td1);
  158. tr.appendChild(td2);
  159. tr.appendChild(td3);
  160. tr.appendChild(td4);
  161. tbody.appendChild(tr);
  162. }
  163. // 增加一个按钮,点击后可以保存
  164. const saveButton = document.createElement('button');
  165. saveButton.id = 'save-instance-button';
  166. saveButton.textContent = '保存';
  167. div.appendChild(saveButton);
  168. saveButton.addEventListener('click', () => {
  169. // 保存实例信息
  170. saveInst(div, inst);
  171. });
  172. }
  173. function showTemplateInfoAt(div, templateInfo) {
  174. }
  175. function initData() {
  176. // 读取关卡信息并填充到页面
  177. if (levels == null) {
  178. window.electron.send('parse-csv', '../../conf/levelInfo.csv')
  179. window.electron.receive('csv-data', (data) => {
  180. if (levels == null) {
  181. levels = data;
  182. window.electron.send('parse-csv', '../../conf/levelInstInfo.csv')
  183. } else {
  184. if (instances == null) {
  185. instances = data
  186. }
  187. }
  188. });
  189. }
  190. if (templateFNs == null) {
  191. window.electron.send('get-file-list', '../../tf_templates')
  192. window.electron.receive('file-list-error', (data) => {
  193. console.error('Error reading directory: ', err);
  194. });
  195. window.electron.receive('file-list-data', (data) => {
  196. // 过滤掉非 .json 后缀的文件
  197. templateFNs = [];
  198. for (let i = 0; i < data.length; i++) {
  199. if (data[i].endsWith('.json')) {
  200. // 去掉后缀
  201. const name = data[i].substring(0, data[i].length - 5);
  202. templateFNs.push(name);
  203. }
  204. }
  205. });
  206. }
  207. //
  208. }
  209. // 创建一个新实例,并将其关联到指定的关卡中
  210. function addNewInst(level) {
  211. const instDetails = document.getElementById('instance-details');
  212. // 获取实例名称
  213. window.electron.send('open-newinst-prompt', 'some data');
  214. window.electron.receive('prompt-newinst-reply', (event, arg) => {
  215. const instName = arg;
  216. // 检查是否已经存在
  217. for (let i = 0; i < instances.length; i++) {
  218. if (instances[i].lvinst == instName) {
  219. alert('实例已经存在');
  220. return;
  221. }
  222. }
  223. // 不存在则加入
  224. const inst = {
  225. lvinst: instName,
  226. template: '',
  227. 'try1(tileCnt|seed|param_template)': '0|0|0',
  228. 'try2(tileCnt|seed|param_template)': '0|0|0',
  229. 'try3(tileCnt|seed|param_template)': '0|0|0',
  230. 'try4(tileCnt|seed|param_template)': '0|0|0',
  231. 'try5(tileCnt|seed|param_template)': '0|0|0',
  232. 'try6(tileCnt|seed|param_template)': '0|0|0',
  233. 'try7(tileCnt|seed|param_template)': '0|0|0',
  234. 'try8(tileCnt|seed|param_template)': '0|0|0',
  235. 'try9(tileCnt|seed|param_template)': '0|0|0',
  236. 'try10(tileCnt|seed|param_template)': '0|0|0'
  237. };
  238. instances.push(inst);
  239. showInstanceInfoAt(instDetails, inst);
  240. });
  241. }
  242. function saveLvInfo() {
  243. const lvDetails = document.getElementById('level-details');
  244. // 保存关卡的详细信息
  245. const lvid = lvDetails.querySelector('#lvid-in-lvdetails').textContent.split(':')[1].trim();
  246. const instid = lvDetails.querySelector('#instid-in-lvdetails').textContent.split(':')[1].trim();
  247. const type = lvDetails.querySelector('#type-select-in-lvdetails').value;
  248. const ddaType = lvDetails.querySelector('#ddatype-in-lvdetails').textContent.split(':')[1].trim();
  249. const ddaPara = lvDetails.querySelector('#ddapara-in-lvdetails').textContent.split(':')[1].trim();
  250. var lv = null;
  251. for (let i = 0; i < levels.length; i++) {
  252. if (levels[i].lvid == lvid) {
  253. lv = levels[i];
  254. break;
  255. }
  256. }
  257. lv['lvinst'] = instid;
  258. lv['type(normal=0,hard=1,superHard=2)'] = type;
  259. lv['dda_type'] = ddaType;
  260. lv['dda_para'] = ddaPara;
  261. // 保存到文件
  262. window.electron.send('save2csv', '../../conf/levelInfo.csv', levels);
  263. }
  264. function fillLvInfo() {
  265. // 读取关卡信息并填充到页面
  266. if (levels != null) {
  267. const levelList = document.getElementById('level-list');
  268. const levelDetails = document.getElementById('level-details');
  269. const instDetails = document.getElementById('instance-details');
  270. const templateDetails = document.getElementById('tempalte-details');
  271. // 将levels里面的信息填充到页面
  272. levels.forEach(level => {
  273. const listItem = document.createElement('li');
  274. listItem.textContent = level.lvid;
  275. listItem.addEventListener('click', () => {
  276. // 将选中的关卡id条目的背景颜色设置为蓝色
  277. Array.from(levelList.children).forEach(node => {
  278. if (node.textContent == level.lvid) {
  279. node.style.backgroundColor = 'lightblue';
  280. } else {
  281. node.style.backgroundColor = 'white';
  282. }
  283. });
  284. levelDetails.innerHTML = `
  285. <h2 id='lvid-in-lvdetails'>关卡ID: ${level.lvid}</h2>
  286. <p id='instid-in-lvdetails'>关卡实例名称: ${level.lvinst}</p>`
  287. //
  288. if (level.lvinst == '') {
  289. // 实例不存在,
  290. // 显示一个下来列表,选择实例
  291. const instSelect = document.createElement('select');
  292. instSelect.id = 'inst-select';
  293. instances.forEach(inst => {
  294. const option = document.createElement('option');
  295. option.value = inst.lvinst;
  296. option.textContent = inst.lvinst;
  297. instSelect.appendChild(option);
  298. });
  299. levelDetails.appendChild(instSelect);
  300. }
  301. // 加入一个按钮,点击后可以创建实例
  302. const createInstButton = document.createElement('button');
  303. createInstButton.id = 'create-instance-button';
  304. createInstButton.textContent = '创建新的实例';
  305. levelDetails.appendChild(createInstButton);
  306. // createInstButton.addEventListener('click', () => {
  307. // addNewInst(level);
  308. // });
  309. console.log(createInstButton.onclick);
  310. // 增加一个下拉框,选择类型:normal,hard,super-hard
  311. const type = level['type(normal=0,hard=1,superHard=2)'];
  312. const typeSelect = document.createElement('select');
  313. typeSelect.id = 'type-select-in-lvdetails';
  314. const normalOption = document.createElement('option');
  315. normalOption.value = '0';
  316. normalOption.textContent = 'normal';
  317. normalOption.selected = type == '0';
  318. const hardOption = document.createElement('option');
  319. hardOption.value = '1';
  320. hardOption.textContent = 'hard';
  321. hardOption.selected = type == '1';
  322. const superHardOption = document.createElement('option');
  323. superHardOption.value = '2';
  324. superHardOption.textContent = 'super-hard';
  325. superHardOption.selected = type == '2';
  326. typeSelect.appendChild(normalOption);
  327. typeSelect.appendChild(hardOption);
  328. typeSelect.appendChild(superHardOption);
  329. const p = document.createElement('p');
  330. p.appendChild(document.createTextNode('关卡难度级别:'));
  331. levelDetails.appendChild(p);
  332. levelDetails.appendChild(typeSelect);
  333. // 显示dda类型和参数
  334. const ddatype = document.createElement('p');
  335. ddatype.id = 'ddatype-in-lvdetails';
  336. ddatype.textContent = 'DDA类型: ' + level.dda_type;
  337. levelDetails.appendChild(ddatype);
  338. const ddapara = document.createElement('p');
  339. ddapara.id = 'ddapara-in-lvdetails';
  340. ddapara.textContent = 'DDA参数: ' + level.dda_para;
  341. levelDetails.appendChild(ddapara);
  342. // 增加一个按钮,点击后可以保存
  343. const saveButton = document.createElement('button');
  344. saveButton.id = 'save-lv-button';
  345. saveButton.textContent = '保存';
  346. levelDetails.appendChild(saveButton);
  347. levelDetails.addEventListener('click', (event) => {
  348. if (event.target.id === 'create-instance-button') {
  349. addNewInst(level);
  350. } else if (event.target.id === 'save-lv-button') {
  351. saveLvInfo();
  352. }
  353. });
  354. // 显示实例信息
  355. const inst = getInstanceByName(level.lvinst);
  356. if (inst != null) {
  357. showInstanceInfoAt(instDetails, inst);
  358. // 显示模板信息
  359. const template = getTemplateByName(inst.template);
  360. if (template != null) {
  361. showTemplateInfoAt(templateDetails, getTemplateByName(inst.template));
  362. }
  363. } else {
  364. instDetails.innerHTML = `
  365. <h2>实例名: Error:未定义</h2>
  366. `
  367. }
  368. });
  369. levelList.appendChild(listItem);
  370. });
  371. }
  372. }
  373. function fillInstanceInfo() {
  374. // 读取关卡信息并填充到页面
  375. if (instances != null) {
  376. const lst = document.getElementById('instance-list');
  377. const details = document.getElementById('instance-details');
  378. // 将levels里面的信息填充到页面
  379. instances.forEach(inst => {
  380. const listItem = document.createElement('li');
  381. listItem.textContent = inst.lvinst;
  382. listItem.addEventListener('click', () => {
  383. showInstanceInfoAt(details, inst)
  384. });
  385. lst.appendChild(listItem);
  386. });
  387. }
  388. }
  389. function fillTemplateInfo() {
  390. if (templateFNs != null) {
  391. const lst = document.getElementById('template-list');
  392. const details = document.getElementById('template-details');
  393. // 将levels里面的信息填充到页面
  394. templateFNs.forEach(fn => {
  395. const listItem = document.createElement('li');
  396. listItem.textContent = fn;
  397. listItem.addEventListener('click', () => {
  398. // 放入截图
  399. });
  400. lst.appendChild(listItem);
  401. });
  402. }
  403. }
  404. document.getElementById('levels').addEventListener('click', function() {
  405. fetch('level.html')
  406. .then(response => response.text())
  407. .then(data => {
  408. document.getElementById('content').innerHTML = data;
  409. fillLvInfo();
  410. // 绑定新增关卡按钮
  411. document.getElementById('add-level-button').addEventListener('click', function() {
  412. window.electron.send('open-newlv-prompt', 'some data')
  413. window.electron.receive('prompt-newlv-reply', (event, arg) => {
  414. const lvid = arg;
  415. // 检查是否已经存在
  416. for (let i = 0; i < levels.length; i++) {
  417. if (levels[i].lvid == lvid) {
  418. alert('关卡id已经存在');
  419. return;
  420. }
  421. }
  422. // 不存在则加入
  423. const level = {
  424. lvid: lvid,
  425. lvinst: '',
  426. type: 0,
  427. dda_type: '0',
  428. dda_para: '0|10000'
  429. };
  430. levels.push(level);
  431. // 刷新页面
  432. fillLvInfo();
  433. // 选中该关卡
  434. const levelList = document.getElementById('level-list');
  435. levelList.childNodes.forEach(node => {
  436. if (node.textContent == lvid) {
  437. node.click();
  438. }
  439. });
  440. })
  441. });
  442. })
  443. .catch(error => {
  444. console.error('Error loading the levels content:', error);
  445. });
  446. });
  447. document.getElementById('examples').addEventListener('click', function() {
  448. fetch('instance.html')
  449. .then(response => response.text())
  450. .then(data => {
  451. document.getElementById('content').innerHTML = data;
  452. fillInstanceInfo();
  453. })
  454. .catch(error => {
  455. console.error('Error loading the intance content:', error);
  456. });
  457. });
  458. document.getElementById('templates').addEventListener('click', function() {
  459. fetch('template.html')
  460. .then(response => response.text())
  461. .then(data => {
  462. document.getElementById('content').innerHTML = data;
  463. fillTemplateInfo();
  464. })
  465. .catch(error => {
  466. console.error('Error loading the intance content:', error);
  467. });
  468. });
  469. // 初始化数据
  470. initData();
  471. </script>
  472. </body>
  473. </html>