license_info_distribution.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. // 显示分发模态框的函数
  2. function showDistributeModal(item) {
  3. const modal = document.getElementById('DistributeModal');
  4. // 显示模态框
  5. modal.style.display = 'flex';
  6. let usersInfo;
  7. // 获取用户信息并填充第一个用户输入框
  8. fetch(`http://${serverIP}:${serverPort}/api/admin/distributeLicenseByUserInfo`, {
  9. method: 'GET',
  10. headers: {
  11. 'Authorization': `Bearer ${authToken}`, // 确保autoToken是您获取的用户授权令牌
  12. 'Content-Type': 'application/json'
  13. }
  14. })
  15. .then(response => {
  16. if (!response.ok) {
  17. throw new Error('Network response was not ok');
  18. }
  19. return response.json();
  20. })
  21. .then(data => {
  22. usersInfo = data.data; // 假设 data 是返回的用户信息数组或对象
  23. console.log('用户信息:', usersInfo); // 打印用户信息
  24. // 调用处理上半部分(邮箱输入框)的函数
  25. handleEmailSection(item,usersInfo);
  26. // 调用处理下半部分(用户输入框)的函数
  27. handleUserSection(item, usersInfo);
  28. })
  29. .catch(error => {
  30. console.error('获取用户信息失败:', error);
  31. });
  32. // 绑定关闭事件
  33. const closeModalBtn = document.querySelector('.DistributeModal-close');
  34. closeModalBtn.addEventListener('click', closeDistributeModal);
  35. // 点击模态框外部关闭
  36. window.addEventListener('click', (event) => {
  37. if (event.target === modal) {
  38. closeDistributeModal();
  39. }
  40. });
  41. }
  42. function handleEmailSection(item, usersInfo) {
  43. console.log('调用邮箱处理');
  44. console.log('handleEmailSection 用户信息:', usersInfo);
  45. const emailInputs = document.getElementById('DistributeModal-email-inputs');
  46. emailInputs.innerHTML = ''; // 清空之前添加的邮箱输入框
  47. // 设置复选框标签内容
  48. const salesEmailLabel = document.getElementById('salesEmailCheckbox').parentElement;
  49. salesEmailLabel.innerHTML = `
  50. <input type="checkbox" id="salesEmailCheckbox" class="DistributeModal-checkbox">
  51. <span class="DistributeModal-checkbox-custom"></span>
  52. 销售邮箱 (${item.SalesPerson}: ${item.SalesEmail})
  53. `;
  54. const supportEmailLabel = document.getElementById('supportEmailCheckbox').parentElement;
  55. supportEmailLabel.innerHTML = `
  56. <input type="checkbox" id="supportEmailCheckbox" class="DistributeModal-checkbox">
  57. <span class="DistributeModal-checkbox-custom"></span>
  58. 运维邮箱 (${item.SupportPerson}: ${item.SupportEmail})
  59. `;
  60. // 防止重复绑定事件,先移除任何现有的点击事件监听器
  61. const addEmailBtn = document.getElementById('DistributeModal-add-email-btn');
  62. addEmailBtn.replaceWith(addEmailBtn.cloneNode(true));
  63. const newAddEmailBtn = document.getElementById('DistributeModal-add-email-btn');
  64. // 绑定点击事件,动态添加邮箱输入框
  65. newAddEmailBtn.addEventListener('click', () => {
  66. const emailWrapper = document.createElement('div');
  67. emailWrapper.className = 'DistributeModal-email-input-wrapper';
  68. const newEmailInput = document.createElement('input');
  69. newEmailInput.type = 'email';
  70. newEmailInput.placeholder = '输入分发邮箱';
  71. newEmailInput.className = 'DistributeModal-email-input';
  72. // 创建删除按钮
  73. const removeEmailBtn = document.createElement('button');
  74. removeEmailBtn.className = 'DistributeModal-remove-email-btn';
  75. removeEmailBtn.innerHTML = '&times;';
  76. removeEmailBtn.addEventListener('click', () => {
  77. emailWrapper.remove();
  78. });
  79. // 将输入框和删除按钮加入到 emailWrapper 中
  80. emailWrapper.appendChild(newEmailInput);
  81. emailWrapper.appendChild(removeEmailBtn);
  82. // 将 emailWrapper 加入到 emailInputs 容器中
  83. emailInputs.appendChild(emailWrapper);
  84. });
  85. // 内部函数:检查是否存在重复项
  86. function findDuplicates(arr) {
  87. const seen = new Set();
  88. const duplicates = [];
  89. arr.forEach((email) => {
  90. if (seen.has(email)) {
  91. duplicates.push(email);
  92. } else {
  93. seen.add(email);
  94. }
  95. });
  96. return duplicates;
  97. }
  98. // 绑定确认按钮点击事件前,先解除已有事件监听器
  99. const emailConfirmBtn = document.getElementById('DistributeModal-email-confirm-btn');
  100. emailConfirmBtn.replaceWith(emailConfirmBtn.cloneNode(true));
  101. const newEmailConfirmBtn = document.getElementById('DistributeModal-email-confirm-btn');
  102. newEmailConfirmBtn.addEventListener('click', () => {
  103. // 收集邮箱信息
  104. let emails = Array.from(document.querySelectorAll('.DistributeModal-email-input'))
  105. .map(input => input.value.trim())
  106. .filter(email => email); // 过滤掉空邮箱
  107. // 检查是否勾选销售邮箱或运维邮箱
  108. const isSalesEmailChecked = document.getElementById('salesEmailCheckbox').checked;
  109. const isSupportEmailChecked = document.getElementById('supportEmailCheckbox').checked;
  110. if (isSalesEmailChecked) {
  111. emails.push(item.SalesEmail);
  112. }
  113. if (isSupportEmailChecked) {
  114. emails.push(item.SupportEmail);
  115. }
  116. // 检查是否存在重复的邮箱
  117. const duplicateEmails = findDuplicates(emails);
  118. if (duplicateEmails.length > 0) {
  119. alert(`以下邮箱重复:\n${duplicateEmails.join('\n')}`);
  120. } else {
  121. if (confirm("确认发送这些邮件吗?")) {
  122. distributeEmails(item, [...new Set(emails)], usersInfo); // 使用 Set 去重
  123. closeDistributeModal(); // 关闭模态框
  124. }
  125. }
  126. });
  127. }
  128. function handleUserSection(item, usersInfo) {
  129. console.log('handleUserSection 用户信息:', usersInfo); // 打印用户信息
  130. const userInputs = document.getElementById('DistributeModal-user-inputs');
  131. userInputs.innerHTML = ''; // 清空之前添加的用户选择框
  132. // 过滤掉 admin 账户
  133. const filteredUsersInfo = usersInfo.filter(user => user.Username !== 'admin');
  134. // 用于存储已经选择的用户
  135. let selectedUsersSet = new Set();
  136. // 绑定新增下拉框按钮
  137. const addSelectBtn = document.getElementById('distributeUser-add-select-btn');
  138. addSelectBtn.replaceWith(addSelectBtn.cloneNode(true)); // 防止重复绑定
  139. const newAddSelectBtn = document.getElementById('distributeUser-add-select-btn');
  140. // 函数:更新所有下拉框中的可选项
  141. const updateSelectOptions = () => {
  142. Array.from(document.querySelectorAll('.distributeUser-select')).forEach(select => {
  143. const currentValue = select.value; // 当前选中的值
  144. select.innerHTML = ''; // 清空选项
  145. // 添加默认的空选项(必须手动选择)
  146. const defaultOption = document.createElement('option');
  147. defaultOption.value = ''; // 设置为空值
  148. defaultOption.textContent = '请选择用户';
  149. select.appendChild(defaultOption);
  150. filteredUsersInfo.forEach(user => {
  151. if (!selectedUsersSet.has(user.UniqueID) || user.UniqueID === currentValue) {
  152. const option = document.createElement('option');
  153. option.value = user.UniqueID;
  154. option.setAttribute('data-username', user.Username);
  155. option.setAttribute('data-account', user.Account);
  156. option.textContent = `${user.Username} (${user.Account})`;
  157. // 如果是当前选中的值,保持选中状态
  158. if (user.UniqueID === currentValue) {
  159. option.selected = true;
  160. }
  161. select.appendChild(option);
  162. }
  163. });
  164. });
  165. };
  166. newAddSelectBtn.addEventListener('click', () => {
  167. const selectWrapper = document.createElement('div');
  168. selectWrapper.className = 'distributeUser-select-wrapper'; // Flexbox 容器
  169. const select = document.createElement('select');
  170. select.className = 'distributeUser-select'; // 设置下拉框样式
  171. // 添加一个默认的空选项
  172. const defaultOption = document.createElement('option');
  173. defaultOption.value = '';
  174. defaultOption.textContent = '请选择用户'; // 这个选项提示用户选择
  175. defaultOption.selected = true; // 默认选中这个选项
  176. select.appendChild(defaultOption);
  177. // 初始更新下拉框
  178. updateSelectOptions();
  179. // 监听下拉框的变化
  180. select.addEventListener('change', () => {
  181. const previousValue = select.dataset.previousValue;
  182. // 如果之前有选中,移除旧值
  183. if (previousValue) {
  184. selectedUsersSet.delete(previousValue);
  185. }
  186. // 如果有新的选择,添加到 set 中
  187. if (select.value) {
  188. selectedUsersSet.add(select.value);
  189. select.dataset.previousValue = select.value; // 保存当前值为下次移除准备
  190. }
  191. // 更新其他下拉框的选项
  192. updateSelectOptions();
  193. });
  194. // 创建删除按钮,使用与关闭邮件输入框相同的样式
  195. const removeSelectBtn = document.createElement('button');
  196. removeSelectBtn.className = 'DistributeModal-remove-email-btn'; // 使用关闭邮件输入框的按钮样式
  197. removeSelectBtn.innerHTML = '&times;';
  198. removeSelectBtn.addEventListener('click', () => {
  199. const previousValue = select.dataset.previousValue;
  200. if (previousValue) {
  201. selectedUsersSet.delete(previousValue); // 删除时从选中集中移除
  202. }
  203. selectWrapper.remove(); // 删除下拉框
  204. updateSelectOptions(); // 更新其他下拉框的选项
  205. });
  206. // 将下拉框和删除按钮加入到 selectWrapper 中
  207. selectWrapper.appendChild(select);
  208. selectWrapper.appendChild(removeSelectBtn);
  209. // 将 selectWrapper 加入到 userInputs 容器中
  210. userInputs.appendChild(selectWrapper);
  211. // 初始更新其他下拉框
  212. updateSelectOptions();
  213. });
  214. // 点击下半部分的确认按钮
  215. const userConfirmBtn = document.getElementById('distributeUser-confirm-btn');
  216. userConfirmBtn.addEventListener('click', () => {
  217. // 收集用户信息,收集每个下拉框选中的值及其额外数据
  218. const selectedUsers = Array.from(document.querySelectorAll('.distributeUser-select'))
  219. .map(select => {
  220. if (select.value) {
  221. const selectedUserInfo = {
  222. uniqueID: select.value,
  223. username: select.options[select.selectedIndex].getAttribute('data-username'),
  224. account: select.options[select.selectedIndex].getAttribute('data-account')
  225. };
  226. return selectedUserInfo; // 返回用户的所有信息
  227. }
  228. })
  229. .filter(user => user !== undefined); // 过滤掉未选择的空值
  230. // 分别提取 uniqueID, username 和 account 数组
  231. const uniqueIDArray = selectedUsers.map(user => user.uniqueID);
  232. const usernameArray = selectedUsers.map(user => user.username);
  233. const accountArray = selectedUsers.map(user => user.account);
  234. console.log("Unique IDs: ", uniqueIDArray);
  235. console.log("Usernames: ", usernameArray);
  236. console.log("Accounts: ", accountArray);
  237. // 执行用户分发逻辑,传递用户详细信息到 distributeLicense
  238. distributeUser(item, uniqueIDArray, usernameArray, accountArray);
  239. closeDistributeModal(); // 关闭模态框
  240. });
  241. }
  242. // 关闭分发模态框的函数
  243. function closeDistributeModal() {
  244. const modal = document.getElementById('DistributeModal');
  245. modal.style.display = 'none'; // 隐藏模态框
  246. // 清空邮箱和用户输入区域
  247. const emailInputs = document.getElementById('DistributeModal-email-inputs');
  248. emailInputs.innerHTML = ''; // 清空动态生成的邮箱输入框
  249. const userInputs = document.getElementById('DistributeModal-user-inputs');
  250. userInputs.innerHTML = ''; // 清空动态生成的用户选择框
  251. }
  252. function distributeEmails(item, emails, usersInfo) {
  253. console.log('分发 distributeEmails', { item, emails, usersInfo });
  254. // 将 emails 数组转为以逗号分隔的字符串
  255. const emailsString = emails.join(',');
  256. // 从 usersInfo 中获取 currentUserInfo
  257. //const currentUserInfo = usersInfo.find(user => user.role === 'currentUser'); // 假设 currentUser 标识当前用户
  258. if (!currentUserInfo) {
  259. console.error('无法获取当前用户信息');
  260. return;
  261. }
  262. // 构建要发送的数据
  263. const postData = {
  264. emails: emailsString,
  265. LicenseUniqueID: item.UniqueID, // item 中的 UniqueID
  266. Oa_request_id: item.oa_request_id, // item 中的 oa_request_id
  267. OperatorUniqueID: currentUserInfo.UniqueID // currentUserInfo 中的 UniqueID
  268. };
  269. console.log('即将发送的数据:', postData);
  270. showLoadingModal("正在分发邮箱中...");
  271. // 发送 POST 请求到 DistributeLicenseToEmail 接口
  272. fetch(`http://${serverIP}:${serverPort}/api/admin/DistributeLicenseToEmail`, {
  273. method: 'POST',
  274. headers: {
  275. 'Authorization': `Bearer ${authToken}`, // 使用 authToken
  276. 'Content-Type': 'application/json'
  277. },
  278. body: JSON.stringify(postData) // 将数据转为 JSON 格式
  279. })
  280. .then(response => {
  281. if (!response.ok) {
  282. // 如果 response 不成功,返回错误信息供 catch 处理
  283. return response.json().then(errData => {
  284. console.log("检查一致性不通过 : ",errData)
  285. throw new Error(errData.error || 'Network response was not ok');
  286. });
  287. }
  288. return response.json();
  289. })
  290. .then(data => {
  291. // 处理成功响应
  292. hideLoadingModal();
  293. console.log('邮件分发成功:', data);
  294. alert('邮件分发成功');
  295. })
  296. .catch(error => {
  297. // 处理错误
  298. hideLoadingModal();
  299. console.error('分发邮件失败:', error);
  300. alert('分发邮件失败: ' + error.message);
  301. location.reload();
  302. });
  303. }
  304. // 执行分发的逻辑
  305. function distributeUser(item, uniqueIDArray, usernameArray, accountArray) {
  306. // 构建要发送的数据对象
  307. const postData = {
  308. Oa_request_id: item.oa_request_id,
  309. LicenseUniqueID: item.UniqueID,
  310. OperatorUniqueID: currentUserInfo.UniqueID, // currentUserInfo 中的 UniqueID
  311. UserUniqueIDs: uniqueIDArray,
  312. UserNames: usernameArray,
  313. UserAccounts: accountArray
  314. };
  315. console.log('Sending user data:', postData);
  316. showLoadingModal("正在分发用户中...");
  317. // 发送 POST 请求到 DistributeLicenseToUser 接口
  318. fetch(`http://${serverIP}:${serverPort}/api/admin/DistributeLicenseToUser`, {
  319. method: 'POST',
  320. headers: {
  321. 'Content-Type': 'application/json',
  322. 'Authorization': `Bearer ${authToken}` // 使用适当的 authToken
  323. },
  324. body: JSON.stringify(postData) // 将数据转换为 JSON 字符串发送
  325. })
  326. .then(response => {
  327. hideLoadingModal(); // 隐藏 loading 模态框
  328. if (!response.ok) {
  329. // 返回错误信息作为 Promise,以便 catch 块捕获
  330. return response.json().then(errorData => {
  331. // 检查服务器是否返回了特定的错误信息并抛出错误
  332. const errorMessage = errorData.error || '网络响应不正确';
  333. throw new Error(errorMessage);
  334. });
  335. }
  336. return response.json();
  337. })
  338. .then(data => {
  339. console.log('分发成功:', data);
  340. alert('分发成功!');
  341. })
  342. .catch(error => {
  343. hideLoadingModal(); // 在失败时隐藏 loading 模态框
  344. console.error('分发失败:', error.message); // 打印具体的错误信息
  345. alert('分发失败: ' + error.message); // 将错误信息展示给用户
  346. });
  347. }
  348. //--------------分发历史模态框------------------------
  349. // function showDistributionHistory(selectedRowData) {
  350. // fetch('http://${serverIP}:${serverPort}/api/admin/GetlicenseRecord', {
  351. // method: 'POST',
  352. // headers: {
  353. // 'Authorization': `Bearer ${authToken}`,
  354. // 'Content-Type': 'application/json'
  355. // },
  356. // body: JSON.stringify({ uniqueID: selectedRowData.UniqueID, oa_request_id: selectedRowData.oa_request_id })
  357. // })
  358. // .then(response => response.json())
  359. // .then(data => {
  360. // const userDistributionContent = document.getElementById('distributionHistory-user-content');
  361. // const emailDistributionContent = document.getElementById('distributionHistory-email-content');
  362. // // 检查 license_record_to_user 是否是数组,如果不是则默认为空数组
  363. // const userRecords = Array.isArray(data?.data?.license_record_to_user) ? data.data.license_record_to_user : [];
  364. // // 如果 license_record_to_emails 是 null,则设置为空数组
  365. // const emailRecords = Array.isArray(data?.data?.license_record_to_emails) ? data.data.license_record_to_emails : [];
  366. // // 显示用户分发记录
  367. // userDistributionContent.innerHTML = userRecords.length > 0
  368. // ? userRecords.map(record => `<p>已转发给用户: ${record.user_account} 时间: ${formatDateTime(record.up_time)}</p>`).join('')
  369. // : '<p>没有用户分发记录。</p>';
  370. // // 显示邮箱分发记录
  371. // emailDistributionContent.innerHTML = emailRecords.length > 0
  372. // ? emailRecords.map(record => `<p>已发给邮箱: ${record.emails} 时间: ${formatDateTime(record.up_time)}</p>`).join('')
  373. // : '<p>没有邮箱分发记录。</p>';
  374. // // 显示模态框
  375. // document.getElementById('distributionHistory-modal').style.display = 'block';
  376. // })
  377. // .catch(error => {
  378. // console.error('Error fetching distribution history:', error);
  379. // });
  380. // // 关闭模态框 (点击关闭按钮)
  381. // document.querySelector('.distributionHistory-modal-close').addEventListener('click', () => {
  382. // document.getElementById('distributionHistory-modal').style.display = 'none';
  383. // });
  384. // // 点击模态框外部关闭模态框
  385. // window.addEventListener('click', function(event) {
  386. // const modal = document.getElementById('distributionHistory-modal');
  387. // if (event.target === modal) { // 检查点击的是否是模态框背景
  388. // modal.style.display = 'none'; // 关闭模态框
  389. // }
  390. // });
  391. // }
  392. function showDistributionHistory(selectedRowData) {
  393. fetch(`http://${serverIP}:${serverPort}/api/admin/GetlicenseRecord`, {
  394. method: 'POST',
  395. headers: {
  396. 'Authorization': `Bearer ${authToken}`,
  397. 'Content-Type': 'application/json'
  398. },
  399. body: JSON.stringify({ uniqueID: selectedRowData.UniqueID, oa_request_id: selectedRowData.oa_request_id })
  400. })
  401. .then(response => response.json())
  402. .then(data => {
  403. console.log("showDistributionHistory", data);
  404. // 提取用户记录和邮箱记录
  405. const userRecords = data.data.license_record_to_user || [];
  406. const emailRecords = data.data.license_record_to_emails || [];
  407. // 按时间排序,最新的记录在前
  408. userRecords.sort((a, b) => new Date(b.up_time) - new Date(a.up_time));
  409. emailRecords.sort((a, b) => new Date(b.up_time) - new Date(a.up_time));
  410. // 分组函数
  411. function groupBy(records, key) {
  412. return records.reduce((result, record) => {
  413. const date = new Date(record.up_time).toLocaleDateString();
  414. if (!result[date]) {
  415. result[date] = [];
  416. }
  417. result[date].push(record);
  418. return result;
  419. }, {});
  420. }
  421. // 分组用户记录和邮箱记录
  422. const groupedUserRecords = groupBy(userRecords, 'up_time');
  423. const groupedEmailRecords = groupBy(emailRecords, 'up_time');
  424. // 动态生成用户记录的 HTML
  425. const userContent = Object.keys(groupedUserRecords).length > 0 ?
  426. Object.keys(groupedUserRecords).map(date => {
  427. const records = groupedUserRecords[date];
  428. const recordContent = records.map(user => `
  429. <div class="distributionHistoryModal-record">
  430. <div>用户名: ${user.user_account}</div>
  431. </div>
  432. `).join('');
  433. return `
  434. <div class="distributionHistoryModal-group">
  435. <div class="distributionHistoryModal-group-title">${date}</div>
  436. ${recordContent}
  437. </div>
  438. `;
  439. }).join('') :
  440. '<div class="distributionHistoryModal-no-record">没有用户分发记录</div>';
  441. // 动态生成邮箱记录的 HTML
  442. const emailContent = Object.keys(groupedEmailRecords).length > 0 ?
  443. Object.keys(groupedEmailRecords).map(date => {
  444. const records = groupedEmailRecords[date];
  445. const recordContent = records.map(email => `
  446. <div class="distributionHistoryModal-record">
  447. <div>邮箱: ${email.emails}</div>
  448. </div>
  449. `).join('');
  450. return `
  451. <div class="distributionHistoryModal-group">
  452. <div class="distributionHistoryModal-group-title">${date}</div>
  453. ${recordContent}
  454. </div>
  455. `;
  456. }).join('') :
  457. '<div class="distributionHistoryModal-no-record">没有邮箱分发记录</div>';
  458. // 将内容插入到模态框中的对应 div
  459. document.getElementById('distributionHistory-user-content').innerHTML = userContent;
  460. document.getElementById('distributionHistory-email-content').innerHTML = emailContent;
  461. // 显示模态框
  462. document.getElementById('distributionHistory-modal').style.display = 'block';
  463. })
  464. .catch(error => {
  465. console.error('Error fetching distribution history:', error);
  466. });
  467. // 关闭模态框 (点击关闭按钮)
  468. document.querySelector('.distributionHistory-modal-close').addEventListener('click', () => {
  469. document.getElementById('distributionHistory-modal').style.display = 'none';
  470. });
  471. // 点击模态框外部关闭模态框
  472. window.addEventListener('click', function(event) {
  473. const modal = document.getElementById('distributionHistory-modal');
  474. if (event.target === modal) {
  475. modal.style.display = 'none';
  476. }
  477. });
  478. }
  479. function formatDateTime(dateString) {
  480. const date = new Date(dateString);
  481. // 获取 UTC 时间
  482. const year = date.getUTCFullYear();
  483. const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // 月份从0开始,所以+1
  484. const day = String(date.getUTCDate()).padStart(2, '0');
  485. const hours = String(date.getUTCHours()).padStart(2, '0');
  486. const minutes = String(date.getUTCMinutes()).padStart(2, '0');
  487. const seconds = String(date.getUTCSeconds()).padStart(2, '0');
  488. // 返回格式化后的字符串,格式为 YYYY-MM-DD HH:mm:ss
  489. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  490. }