stats-utils.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*---------------------------------------------参数配置---------------------------------------*/
  2. const CONSTANTS = {
  3. //审批列表
  4. KEY_APPROVAL_TASK: 'approval_task',
  5. // 余额统计
  6. KEY_CHANNEL_NAMES: 'channel_names', //上游的名字,通道分组用
  7. KEY_MERCHANT_NAMES: 'merchant_names', //下游的名字,机构分组用
  8. KEY_CHANNEL_FAST: 'channel_fast', //上下游余额统计:统计的快充通道
  9. KEY_CHANNEL_NORMAL: 'channel_normal', //上下游余额统计:统计的普充通道
  10. KEY_MERCHANT: 'merchant', //上下游余额统计:统计的机构
  11. KEY_DAILY_CHANNEL: 'daily_channel', //日对账单:统计的通道
  12. KEY_DAILY_MERCHANT: 'daily_merchant', //日对账单:统计的机构
  13. KEY_MONTHLY_CHANNEL: 'monthly_channel', //月对账单:统计的通道
  14. KEY_MONTHLY_MERCHANT: 'monthly_merchant', //月对账单:统计的机构
  15. //带票额度统计
  16. KEY_QUOTA_COMPANY: 'quota_company', //带票额度统计:主体
  17. KEY_QUOTA_MERCHANT: 'quota_merchant', //带票额度统计:机构
  18. KEY_QUOTA_CHANNEL: 'quota_channel', //带票额度统计:通道
  19. KEY_QUOTA_SUMMARY: 'quota_summary', //带票额度统计:综合
  20. KEY_QUOTA_CONDITION: 'quota_condition', //带票额度统计:条件
  21. };
  22. /*---------------------------------------------公共方法---------------------------------------*/
  23. function formatDecimals(number, digit= 2) {//格式化金额
  24. if (typeof number === 'string') {
  25. number = Number(number);
  26. }
  27. if (number === 0) {
  28. return '0';
  29. }
  30. return parseFloat(number).toFixed(digit);
  31. }
  32. function cnMoneyFormat(money) {
  33. let number_data = money;
  34. number_data = parseInt(number_data);
  35. let yi = 0; // 亿
  36. let wan = 0; // 万
  37. let qian = 0; // 千
  38. const qian_s = 1000; // 千
  39. const wan_s = 10000; // 万
  40. const yi_s = 100000000; // 亿
  41. // 取整
  42. function qz(data) {
  43. return Math.floor(data);
  44. }
  45. // 为 0 判断输出
  46. function data_if(data, amount) {
  47. return data === 0 ? '' : data + amount;
  48. }
  49. // 亿
  50. function yi_f(data) {
  51. yi = qz(data / yi_s);
  52. data = data - (yi * yi_s);
  53. return {
  54. data1: data_if(yi, '亿'),
  55. data2: data,
  56. };
  57. }
  58. // 万
  59. function wan_f(data) {
  60. wan = qz(data / wan_s);
  61. data = data - (wan * wan_s);
  62. return {
  63. data1: data_if(wan, '万'),
  64. data2: data,
  65. };
  66. }
  67. // 千
  68. function qian_f(data) {
  69. qian = qz(data / qian_s);
  70. data = data - (qian * qian_s);
  71. return {
  72. data1: data_if(qian, '千'),
  73. data2: data,
  74. };
  75. }
  76. yi = yi_f(number_data);
  77. number_data = yi.data2;
  78. wan = wan_f(number_data);
  79. number_data = wan.data2;
  80. qian = qian_f(number_data);
  81. number_data = qian.data2;
  82. let result = yi.data1 + wan.data1 + qian.data1 + number_data;
  83. let resultValue = result.substr(0, 1);
  84. if (resultValue === '0') {
  85. result = result.substr(1, result.length);
  86. }
  87. let resultVali = result.substr(0, 3);
  88. if (resultVali === 'NaN') {
  89. return '';
  90. } else {
  91. return result;
  92. }
  93. }
  94. function isValidKey(obj, key) {
  95. if (obj.hasOwnProperty(key)) {
  96. if (obj[key] !== null && obj[key] !== undefined && obj[key] !== '') {
  97. return true;
  98. }
  99. }
  100. return false;
  101. }
  102. function deepCloneData(obj) {//数据深拷贝
  103. if (obj === null || typeof obj !== 'object') {
  104. return obj;
  105. }
  106. let clone = Array.isArray(obj) ? [] : {};
  107. for (let key in obj) {
  108. if (obj.hasOwnProperty(key)) {
  109. clone[key] = deepCloneData(obj[key]);
  110. }
  111. }
  112. return clone;
  113. }
  114. function setEmptyFieldsToZero(obj, fields) {
  115. fields.forEach(field => {
  116. if (obj.hasOwnProperty(field) && obj[field] === '') {
  117. obj[field] = '0';
  118. }
  119. });
  120. }
  121. function handleInputd2(event) {//限制金额输入框
  122. let element = event.target;
  123. let value = element.textContent;
  124. let selection = window.getSelection();
  125. let range = selection.getRangeAt(0);
  126. let startOffset = range.startOffset;
  127. value = value.replace(/[^\d.-]/g, '');
  128. const parts = value.split('.');
  129. if (parts.length > 1) {
  130. parts[1] = parts[1].slice(0, 2);
  131. value = parts.join('.');
  132. }
  133. element.textContent = value;
  134. let newNode = element.childNodes[0] || element;
  135. range.setStart(newNode, Math.min(startOffset, value.length));
  136. range.setEnd(newNode, Math.min(startOffset, value.length));
  137. selection.removeAllRanges();
  138. selection.addRange(range);
  139. }
  140. function handleInputd4(event) {
  141. let element = event.target;
  142. let value = element.textContent;
  143. let selection = window.getSelection();
  144. let range = selection.getRangeAt(0);
  145. let startOffset = range.startOffset;
  146. value = value.replace(/[^\d.-]/g, '');
  147. const parts = value.split('.');
  148. if (parts.length > 1) {
  149. parts[1] = parts[1].slice(0, 4);
  150. value = parts.join('.');
  151. }
  152. element.textContent = value;
  153. let newNode = element.childNodes[0] || element;
  154. range.setStart(newNode, Math.min(startOffset, value.length));
  155. range.setEnd(newNode, Math.min(startOffset, value.length));
  156. selection.removeAllRanges();
  157. selection.addRange(range);
  158. }
  159. function handleInputNormal2(event) {
  160. let element = event.target;
  161. let value = element.value;
  162. let cursorPos = element.selectionStart;
  163. value = value.replace(/[^\d.-]/g, '');
  164. const parts = value.split('.');
  165. if (parts.length > 1) {
  166. parts[1] = parts[1].slice(0, 2);
  167. value = parts.join('.');
  168. }
  169. element.value = value;
  170. element.setSelectionRange(cursorPos, cursorPos);
  171. }
  172. function normalizeAmount(amount) {
  173. return amount.replace(/^0+(\d+)/, '$1').replace(/^0+$/, '0');
  174. }
  175. function formatDateTime(dateString) {
  176. const date = new Date(dateString);
  177. const year = date.getFullYear();
  178. const month = String(date.getMonth() + 1).padStart(2, '0');
  179. const day = String(date.getDate()).padStart(2, '0');
  180. const hours = String(date.getHours()).padStart(2, '0');
  181. const minutes = String(date.getMinutes()).padStart(2, '0');
  182. const seconds = String(date.getSeconds()).padStart(2, '0');
  183. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  184. }
  185. function isValidDate(dateString) { //校验日期是否合法
  186. const regex = /^\d{4}-\d{2}-\d{2}$/;
  187. if (!regex.test(dateString)) {
  188. return false;
  189. }
  190. const date = new Date(dateString);
  191. if (Number.isNaN(date.getTime())) {
  192. return false;
  193. }
  194. const [year, month, day] = dateString.split('-').map(Number);
  195. return date.getFullYear() === year && date.getMonth() + 1 === month && date.getDate() === day;
  196. }
  197. function getLastMonth() {
  198. const date = new Date();
  199. date.setMonth(date.getMonth() - 1);
  200. const year = date.getFullYear();
  201. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  202. return `${year}-${month}`;
  203. }
  204. function getCurrentMonth() {
  205. const currentDate = new Date();
  206. const year = currentDate.getFullYear();
  207. let month = currentDate.getMonth() + 1;
  208. month = month < 10 ? '0' + month : month;
  209. return year + '-' + month;
  210. }
  211. function isValidMonth(month) {
  212. const regex = /^\d{4}-(0[1-9]|1[0-2])$/;
  213. return regex.test(month);
  214. }
  215. function getNextMonth(baseMonth = '') {
  216. const date = new Date();
  217. if (baseMonth !== '') {
  218. const [year, monthStr] = baseMonth.split('-').map(Number);
  219. date.setFullYear(year, monthStr - 1, 1);
  220. }
  221. date.setMonth(date.getMonth() + 1);
  222. const year = date.getFullYear();
  223. const month = (date.getMonth() + 1).toString().padStart(2, '0');
  224. return `${year}-${month}`;
  225. }
  226. function getNextMonthFirstDay(month) {
  227. const [year, monthStr] = month.split('-').map(Number);
  228. const nextMonth = monthStr === 12 ? 1 : monthStr + 1;
  229. const nextYear = monthStr === 12 ? year + 1 : year;
  230. const nextMonthStr = nextMonth.toString().padStart(2, '0');
  231. return `${nextYear}-${nextMonthStr}-01`;
  232. }
  233. function getLastDateOfMonth(yearMonth) {
  234. const [year, month] = yearMonth.split('-').map(Number);
  235. const date = new Date(year, month, 0);
  236. const yearStr = date.getFullYear();
  237. const monthStr = date.getMonth() + 1;
  238. const dayStr = date.getDate();
  239. return `${yearStr}年${monthStr}月${dayStr}日`;
  240. }
  241. function chineseYearMonth(dateStr) {
  242. const parts = dateStr.split('-');
  243. if (parts.length < 2) {
  244. return dateStr;
  245. }
  246. const year = parts[0];
  247. const month = parseInt(parts[1], 10);
  248. return year + '年' + month + '月';
  249. }
  250. /*
  251. * 过滤json数组,仅保留需要的字段
  252. */
  253. function filterJsonFields(jsonArray, fieldsToKeep) {
  254. return jsonArray.map(item => {
  255. return fieldsToKeep.reduce((filteredItem, field) => {
  256. if (field in item) {
  257. filteredItem[field] = item[field];
  258. }
  259. return filteredItem;
  260. }, {});
  261. });
  262. }
  263. /**
  264. * 按指定字段进行排序,非字典序,将间隔开的元素排在一起
  265. * @param list
  266. * @param key
  267. * @returns {*[]}
  268. */
  269. function sortByName(list, key) {
  270. const dataMap = new Map();
  271. const result = [...list];
  272. for (let i = 0; i < result.length; i++) {
  273. const dataName = result[i][key];
  274. const sortKey = dataName.slice(0, 2);
  275. if (dataMap.has(sortKey)) {
  276. const firstIndex = dataMap.get(sortKey);
  277. if (i > firstIndex) {
  278. const [item] = result.splice(i, 1);
  279. result.splice(firstIndex + 1, 0, item);
  280. dataMap.set(sortKey, firstIndex + 1);
  281. i--;
  282. }
  283. } else {
  284. dataMap.set(sortKey, i);
  285. }
  286. }
  287. return result;
  288. }
  289. function isObjectEmpty(obj) {
  290. return Object.keys(obj).length === 0;
  291. }
  292. function showErr(error) {
  293. layer.alert(error, {
  294. icon: 2,
  295. title: '错误'
  296. });
  297. }
  298. function showWarning(error, callback) {
  299. layer.alert(error, {
  300. icon: 0,
  301. title: '注意',
  302. yes: function(index) {
  303. if (typeof callback === 'function') {
  304. callback();
  305. }
  306. layer.close(index);
  307. }
  308. });
  309. }
  310. function showSuccess(msg) {
  311. layer.msg(msg, {
  312. icon: 1,
  313. time: 2000
  314. });
  315. }
  316. function isNumeric(value) {
  317. return /^-?\d+(\.\d+)?$/.test(value);
  318. }
  319. /*---------------------------------------------请求---------------------------------------*/
  320. class BaseService {
  321. constructor(baseUrl) {
  322. this.baseUrl = baseUrl;
  323. }
  324. request(endpoint, method, data) {
  325. return new Promise((resolve, reject) => {
  326. $.ajax({
  327. url: this.baseUrl + endpoint,
  328. type: method,
  329. data: data,
  330. dataType: 'json',
  331. success: (response) => {
  332. try {
  333. const parsedResponse = JSON.parse(JSON.stringify(response));
  334. resolve(parsedResponse);
  335. } catch (e) {
  336. reject(new Error('请求解析失败: ' + response));
  337. }
  338. },
  339. error: (jqXHR, textStatus, errorThrown) => {
  340. reject(new Error('请求失败: ' + textStatus + ', ' + errorThrown));
  341. },
  342. });
  343. });
  344. }
  345. }
  346. /*------------------------------------------------------UI组件-------------------------------------------*/
  347. class ComponentBase {
  348. constructor(options) {
  349. this.el = document.querySelector(options.el);
  350. this.components = options.components || {};
  351. this.componentData = options.componentData || {};
  352. this.events = {};
  353. this.componentInstances = {};
  354. this.render();
  355. }
  356. render() {
  357. this.el.innerHTML = this.compile(this.el.innerHTML);
  358. }
  359. compile(template) {
  360. const componentNames = Object.keys(this.components);
  361. componentNames.forEach(name => {
  362. const regex = new RegExp(`<${name}([^>]*)>(.*?)<\/${name}>`, 'g');
  363. template = template.replace(regex, (match, attrs) => {
  364. const props = {};
  365. attrs.replace(/(\w+)="([^"]*)"/g, (match, key, value) => {
  366. if (CONSTANTS[value] !== undefined) {
  367. value = CONSTANTS[value];
  368. }
  369. props[key] = value;
  370. });
  371. const component = new this.components[name]({
  372. props: props,
  373. data: this.componentData[name] || {},
  374. parent: this
  375. });
  376. this.componentInstances[name] = component;
  377. return component.render();
  378. });
  379. });
  380. return template;
  381. }
  382. on(event, callback) {
  383. if (!this.events[event]) {
  384. this.events[event] = [];
  385. }
  386. this.events[event].push(callback);
  387. }
  388. emit(event, ...args) {
  389. if (this.events[event]) {
  390. this.events[event].forEach(callback => callback(...args));
  391. }
  392. }
  393. getComponent(name) {
  394. return this.componentInstances[name];
  395. }
  396. }
  397. class Component {
  398. constructor(options) {
  399. this.data = options.data || {};
  400. this.props = options.props || {};
  401. this.template = options.template || '';
  402. this.id = 'component-' + Math.random().toString(36).substr(2, 9);
  403. this.props['comp-id'] = this.id;
  404. }
  405. render() {
  406. let template = this.template;
  407. for (const key in this.props) {
  408. template = template.replace(new RegExp(`{{${key}}}`, 'g'), this.props[key]);
  409. }
  410. setTimeout(() => {
  411. this.bindEvents();
  412. this.mounted();
  413. }, 0);
  414. return template;
  415. }
  416. bindEvents() {
  417. const rootElement = document.querySelector(`#${this.id}`);
  418. if (!rootElement) {
  419. return;
  420. }
  421. this.unbindEvents();
  422. const supportedEvents = ['click', 'input', 'blur', 'change'];
  423. supportedEvents.forEach(eventType => {
  424. const elements = rootElement.querySelectorAll(`[v-on\\:${eventType}]`);
  425. elements.forEach(element => {
  426. const method = element.getAttribute(`v-on:${eventType}`);
  427. if (method && typeof this[method] === 'function') {
  428. const listener = this[method].bind(this);
  429. element.addEventListener(eventType, listener);
  430. if (!this.eventListeners[eventType]) {
  431. this.eventListeners[eventType] = [];
  432. }
  433. this.eventListeners[eventType].push({ element, listener });
  434. }
  435. });
  436. });
  437. }
  438. unbindEvents() {
  439. for (const eventType in this.eventListeners) {
  440. this.eventListeners[eventType].forEach(({ element, listener }) => {
  441. element.removeEventListener(eventType, listener);
  442. });
  443. }
  444. this.eventListeners = {};
  445. }
  446. mounted() {
  447. }
  448. }
  449. class LayuiTableBase {
  450. constructor(id) {
  451. this.tableId = id;
  452. }
  453. /*
  454. * 表格中可编辑列的处理
  455. */
  456. editEvent(editColumns = [], callback) {
  457. const tableItem = $('#' + this.tableId);
  458. const trs = tableItem.next('.layui-table-view').find('.layui-table-body tbody tr');
  459. trs.each(function (i, tr) {
  460. for (let col of editColumns) {
  461. const td = $(tr).find('td[data-field="' + col + '"]').not('.layui-hide');
  462. if (td.length > 0) {//合并隐藏的不处理
  463. const valDiv = td.find('div');
  464. valDiv.attr('contenteditable', true).css('background-color', 'lightblue');
  465. valDiv.off('input', handleInputd4)
  466. .off('keypress')
  467. .off('blur')
  468. .on('input', handleInputd4)
  469. .on('keypress', function (e) {
  470. if (e.keyCode === 13) {
  471. e.preventDefault();
  472. $(this).blur();
  473. }
  474. })
  475. .on('blur', function () {
  476. const val = valDiv.text().trim();
  477. if (!isNumeric(val)) {
  478. valDiv.html('0');
  479. }
  480. if (callback !== null && typeof callback === 'function') {
  481. const index = $(this).parent().parent().data('index');
  482. callback(index);
  483. }
  484. });
  485. }
  486. }
  487. });
  488. }
  489. switchEvent(switchColumns = [], callback) {
  490. const tableItem = $('#' + this.tableId);
  491. const trs = tableItem.next('.layui-table-view').find('.layui-table-body tbody tr');
  492. trs.each(function (i, tr) {
  493. for (let clo of switchColumns) {
  494. const td = $(tr).find('td[data-field="' + clo + '"]').not('.layui-hide');
  495. if (td.length > 0) {
  496. const buttons = td.find('.layui-btn');
  497. buttons.off('click').on('click', function (e) {
  498. e.preventDefault();
  499. e.stopPropagation();
  500. const currTr = $(this).closest('tr');
  501. const index = currTr.data('index');
  502. buttons.removeClass('selected').addClass('unselected');
  503. $(this).removeClass('unselected').addClass('selected');
  504. if (callback !== null && typeof callback === 'function') {
  505. callback(index);
  506. }
  507. });
  508. }
  509. }
  510. });
  511. }
  512. /*
  513. * 表格中金额字段样式,小于0的数值设置为红色
  514. */
  515. setValueClass(redColumns, boldColumns = []) {
  516. const trs = $('#' + this.tableId).next('.layui-table-view').find('.layui-table-body tbody tr');
  517. trs.each(function(i, tr) {
  518. for(let col of redColumns) {
  519. const td = $(tr).find('td[data-field="' + col + '"]').not('.layui-hide');
  520. if (td.length > 0) {//合并隐藏的不处理
  521. const valDiv = td.find('div');
  522. const val = valDiv.text().trim();
  523. if (parseFloat(val) < 0) {
  524. valDiv.addClass('negative-value');
  525. } else {
  526. valDiv.removeClass('negative-value');
  527. }
  528. }
  529. }
  530. for (let boldCol of boldColumns) {
  531. const boldTd = $(tr).find('td[data-field="' + boldCol + '"]').not('.layui-hide');
  532. if (boldTd.length > 0) {
  533. const boldDiv = boldTd.find('div');
  534. boldDiv.css('font-weight', 'bold');
  535. }
  536. }
  537. });
  538. }
  539. }
  540. /*------------------------------------------------------审批任务-------------------------------------------*/
  541. class TaskManager {
  542. constructor() {
  543. this.globalTaskList = [];
  544. this.currentTaskList = [];
  545. }
  546. async initializeGlobalTaskList() {
  547. this.globalTaskList = await this._fetchTasksFromBackend();
  548. this._updateCurrentTaskList();
  549. }
  550. async _fetchTasksFromBackend() {
  551. const response = await statsApi.getStatsSettings([CONSTANTS.KEY_APPROVAL_TASK]);
  552. let data = [];
  553. if (response.state === true) {
  554. data = response[CONSTANTS.KEY_APPROVAL_TASK];
  555. }
  556. return data.map(task => this._normalizeTask(task));
  557. }
  558. async _syncTaskWithBackend(task) {
  559. const response = await statsApi.setStatsSettings(CONSTANTS.KEY_APPROVAL_TASK, task);
  560. return response.state === true;
  561. }
  562. async _syncTaskListWithBackend() {
  563. try {
  564. this.globalTaskList = await this._fetchTasksFromBackend();
  565. this._updateCurrentTaskList();
  566. } catch (error) {
  567. console.error("Failed to sync tasks with backend:", error);
  568. }
  569. }
  570. _mergeTasks(taskList, newTask) {
  571. const taskId = newTask.id;
  572. const taskIndex = taskList.findIndex(task => task.id === taskId);
  573. if (taskIndex !== -1) {
  574. taskList[taskIndex] = { ...taskList[taskIndex], ...newTask };
  575. } else {
  576. taskList.push(newTask);
  577. }
  578. return taskList;
  579. }
  580. _normalizeTask(task) {
  581. return {
  582. id: task.id || this._generateUniqueId(),
  583. type: task.type || this.getTaskType(),
  584. time: task.time || new Date().toISOString(),
  585. data: task.data || {},
  586. status: task.status || 'pending',
  587. initiator: task.initiator || '',
  588. approver: task.approver || ''
  589. };
  590. }
  591. _generateUniqueId() {
  592. return 'xxxx-xxxx-4xxx-yxxx-xxxxxx'.replace(/[xy]/g, function(c) {
  593. let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
  594. return v.toString(16);
  595. });
  596. }
  597. getTaskType() {
  598. throw new Error("Subclasses must implement getTaskType()");
  599. }
  600. _updateCurrentTaskList() {
  601. const field = this.getTaskType();
  602. this.currentTaskList = this.globalTaskList.filter(task => task.type === field);
  603. this._sortCurrentTaskListByTime();
  604. }
  605. _sortCurrentTaskListByTime() {
  606. this.currentTaskList.sort((a, b) => new Date(a.time) - new Date(b.time));
  607. }
  608. async addTask(data = {}, initiator = '', approver = '') {
  609. const newTask = this._normalizeTask({ data, initiator, approver });
  610. const taskTmp = deepCloneData(this.globalTaskList);
  611. const updateTask = this._mergeTasks(taskTmp, newTask);
  612. if (await this._syncTaskWithBackend(updateTask)) {
  613. this.globalTaskList.push(newTask);
  614. this._updateCurrentTaskList();
  615. return true;
  616. }
  617. return false;
  618. }
  619. getPendingTasks() {
  620. return this.currentTaskList;
  621. }
  622. async executeTask(taskId, approvalHandler) {
  623. await this._syncTaskListWithBackend();
  624. const taskIndex = this.currentTaskList.findIndex(task => task.id === taskId);
  625. if (taskIndex === -1) {
  626. console.warn("Task already processed or not found.");
  627. return false;
  628. }
  629. const task = this.currentTaskList[taskIndex];
  630. await approvalHandler(task);
  631. this.currentTaskList.splice(taskIndex, 1);
  632. const globalIndex = this.globalTaskList.findIndex(t => t.id === taskId);
  633. if (globalIndex !== -1) {
  634. this.globalTaskList.splice(globalIndex, 1);
  635. }
  636. await this._syncTaskWithBackend(this.globalTaskList);
  637. return true;
  638. }
  639. async updateTask(taskId, updatedData) {
  640. const taskIndex = this.globalTaskList.findIndex(task => task.id === taskId);
  641. if (taskIndex === -1) {
  642. console.warn(`Task with ID ${taskId} not found.`);
  643. return false;
  644. }
  645. if (Object.keys(updatedData).length === 0) {
  646. this.globalTaskList.splice(taskIndex, 1);
  647. } else {
  648. this.globalTaskList[taskIndex].data = updatedData;
  649. }
  650. const updateSuccess = await this._syncTaskWithBackend(this.globalTaskList);
  651. if (updateSuccess) {
  652. this._updateCurrentTaskList();
  653. return true;
  654. } else {
  655. console.error(`Failed to update task ${taskId} in the backend.`);
  656. return false;
  657. }
  658. }
  659. }