accountingweb-api and ttc-api: initial with modified .env
Signed-off-by: supphakitd <67319010028@technictrang.ac.th>
This commit is contained in:
@@ -2,9 +2,9 @@
|
|||||||
PJ_NAME=exthernal-wepaccounting-api
|
PJ_NAME=exthernal-wepaccounting-api
|
||||||
|
|
||||||
# database
|
# database
|
||||||
PG_HOST=localhost
|
PG_HOST=10.9.0.0
|
||||||
PG_USER=postgres
|
PG_USER=postgres
|
||||||
PG_PASS=123456
|
PG_PASS=ttc@2026
|
||||||
PG_DB=ttc
|
PG_DB=ttc
|
||||||
PG_PORT=5432
|
PG_PORT=5432
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ SMTP_USER=lalisakuty@gmail.com
|
|||||||
SMTP_PASS=lurl pckw qugk tzob
|
SMTP_PASS=lurl pckw qugk tzob
|
||||||
|
|
||||||
# REDIS
|
# REDIS
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=10.9.0.0x
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
OTP_TTL_SECONDS=300
|
OTP_TTL_SECONDS=300
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import { sendError } from '../utils/response.js'
|
|||||||
import { GeneralService } from '../share/generalservice.js';
|
import { GeneralService } from '../share/generalservice.js';
|
||||||
import { trim_all_array } from '../utils/trim.js'
|
import { trim_all_array } from '../utils/trim.js'
|
||||||
import { verifyToken, generateToken } from '../utils/token.js'
|
import { verifyToken, generateToken } from '../utils/token.js'
|
||||||
|
import { Interface } from '../interfaces/Interface.js';
|
||||||
|
|
||||||
export class accountingAdd {
|
export class accountingAdd {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.generalService = new GeneralService();
|
this.generalService = new GeneralService();
|
||||||
this.accountingAddService = new AccountingAddService();
|
this.accountingAddService = new AccountingAddService();
|
||||||
|
this.Interface = new Interface();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onNavigate(req, res) {
|
async onNavigate(req, res) {
|
||||||
@@ -22,20 +24,43 @@ export class accountingAdd {
|
|||||||
async onAccountingAdd(req, res, database) {
|
async onAccountingAdd(req, res, database) {
|
||||||
let idx = -1
|
let idx = -1
|
||||||
let aryResult = []
|
let aryResult = []
|
||||||
|
let latSeq = []
|
||||||
try {
|
try {
|
||||||
let token = req.body.request.token;
|
let token = req.headers.authorization?.split(' ')[1];
|
||||||
const decoded = verifyToken(token);
|
const decoded = verifyToken(token);
|
||||||
|
|
||||||
let num = req.body.request.actnum;
|
let actnum = req.body.request.actnum;
|
||||||
database = decoded.organization
|
database = decoded.organization;
|
||||||
|
|
||||||
aryResult = await this.accountingAddService.getAccountingAdd(database, num);
|
aryResult = await this.accountingAddService.getAccountingAdd(database, actnum);
|
||||||
|
latSeq = await this.accountingAddService.getLatestAccountingSeq(database);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
idx = 1;
|
idx = 1;
|
||||||
} finally {
|
} finally {
|
||||||
if (idx === 1) return sendError('เกิดข้อผิดพลาดไม่คาดคิดเกิดขึ้น', 'Unexpected error');
|
if (idx === 1) return sendError('เกิดข้อผิดพลาดไม่คาดคิดเกิดขึ้น', 'Unexpected error');
|
||||||
if (!aryResult) return sendError('ไม่พบการมีอยู่ของข้อมูล', 'Cannot Find Any Data');
|
// if (!aryResult) return sendError('ไม่พบการมีอยู่ของข้อมูล', 'Cannot Find Any Data');
|
||||||
return aryResult
|
|
||||||
|
if (aryResult == 0) {
|
||||||
|
let prommis = await this.makeArySave(req, latSeq[0].actseq);
|
||||||
|
return prommis
|
||||||
|
} else {
|
||||||
|
return sendError('คีย์หลักซ้ำในระบบ', 'Duplicate Primary Key');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async makeArySave(req, seq) {
|
||||||
|
let arysave = {
|
||||||
|
methods: 'post',
|
||||||
|
actseq: seq + 1,
|
||||||
|
actnum: req.body.request.actnum,
|
||||||
|
actacpdtm: req.body.request.actacpdtm,
|
||||||
|
actcat: req.body.request.actcat,
|
||||||
|
actqty: req.body.request.actqty,
|
||||||
|
actcmt: req.body.request.actcmt,
|
||||||
|
acttyp: req.body.request.acttyp
|
||||||
|
}
|
||||||
|
return this.Interface.saveInterface('actmst', arysave, req);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,17 @@ export class reportController {
|
|||||||
totalIncome: totalIncome.toFixed(2),
|
totalIncome: totalIncome.toFixed(2),
|
||||||
totalExpense: totalExpense.toFixed(2),
|
totalExpense: totalExpense.toFixed(2),
|
||||||
netProfit: netProfit.toFixed(2),
|
netProfit: netProfit.toFixed(2),
|
||||||
profitRate: profitRate.toFixed(2) + ' %',
|
|
||||||
adjustedProfitRate: adjustedProfitRate.toFixed(2) + ' %',
|
|
||||||
period: '30 วัน'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ✅ 3.5) Create actdata table with required fields grouped by actnum
|
||||||
|
var actdata = data.map(row => ({
|
||||||
|
actnam: row.actnam,
|
||||||
|
actcat: row.actcat,
|
||||||
|
actqty: row.actqty,
|
||||||
|
actcmt: row.actcmt,
|
||||||
|
actacpdtm: row.actacpdtm
|
||||||
|
}));
|
||||||
|
|
||||||
// ✅ 4) ดึงสีจาก dtlmst (แนะนำให้เรียกจาก service เพิ่ม)
|
// ✅ 4) ดึงสีจาก dtlmst (แนะนำให้เรียกจาก service เพิ่ม)
|
||||||
// ตัวอย่างสมมติ: คุณไป query มาจาก service ก่อนหน้าแล้วได้เป็น object แบบนี้
|
// ตัวอย่างสมมติ: คุณไป query มาจาก service ก่อนหน้าแล้วได้เป็น object แบบนี้
|
||||||
// key = ชื่อหมวด (actcatnam หรือ code), value = color
|
// key = ชื่อหมวด (actcatnam หรือ code), value = color
|
||||||
@@ -127,8 +133,9 @@ export class reportController {
|
|||||||
console.error('calculate summary/pie error:', err);
|
console.error('calculate summary/pie error:', err);
|
||||||
}
|
}
|
||||||
let arydiy = {
|
let arydiy = {
|
||||||
|
actdata,
|
||||||
summary,
|
summary,
|
||||||
pie
|
pie,
|
||||||
}
|
}
|
||||||
|
|
||||||
return arydiy;
|
return arydiy;
|
||||||
|
|||||||
@@ -6,15 +6,29 @@ export class AccountingAddService {
|
|||||||
this.generalService = new GeneralService()
|
this.generalService = new GeneralService()
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAccountingAdd(database, name) {
|
async getAccountingAdd(database, number) {
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT
|
SELECT
|
||||||
actseq,
|
actseq,
|
||||||
actnam
|
actnum
|
||||||
FROM ${database}.actmst
|
FROM ${database}.actmst
|
||||||
WHERE actnam = $1
|
WHERE actnum = $1
|
||||||
`
|
`
|
||||||
const params = [name]
|
|
||||||
|
const params = [number]
|
||||||
|
const result = await this.generalService.executeQueryParam(database, sql, params);
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLatestAccountingSeq(database) {
|
||||||
|
const sql = `
|
||||||
|
SELECT
|
||||||
|
actseq
|
||||||
|
FROM ${database}.actmst
|
||||||
|
WHERE actseq=(SELECT max(actseq) FROM ${database}.actmst)
|
||||||
|
`
|
||||||
|
|
||||||
|
const params = []
|
||||||
const result = await this.generalService.executeQueryParam(database, sql, params);
|
const result = await this.generalService.executeQueryParam(database, sql, params);
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export class AccountingSumService {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async getCategoryColorMap(database) {
|
async getCategoryColorMap(database) {
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT dtlcod, dtlnam, dtlmsc as dtlclr
|
SELECT dtlcod, dtlnam, dtlmsc as dtlclr
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ export class ReportService {
|
|||||||
async getReportController(database, number) {
|
async getReportController(database, number) {
|
||||||
const sql = `
|
const sql = `
|
||||||
SELECT
|
SELECT
|
||||||
|
${database}.translatedtl('ACTTYP', acttyp) AS actnam,
|
||||||
acttyp,
|
acttyp,
|
||||||
actcat,
|
${database}.translatedtl_multi(ARRAY['ACTCAT_INC','ACTCAT_EXP'], actcat) AS actcat,
|
||||||
actqty,
|
actqty,
|
||||||
actcmt,
|
actcmt,
|
||||||
actacpdtm
|
actacpdtm
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#project
|
#project
|
||||||
PJ_NAME=exthernal-mobile-api
|
PJ_NAME=exthernal-login-api
|
||||||
|
|
||||||
# database
|
# database
|
||||||
PG_HOST=localhost
|
PG_HOST=10.9.0.0
|
||||||
PG_USER=postgres
|
PG_USER=postgres
|
||||||
PG_PASS=123456
|
PG_PASS=ttc@2026
|
||||||
PG_DB=ttc
|
PG_DB=ttc
|
||||||
PG_PORT=5432
|
PG_PORT=5432
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ SMTP_USER=lalisakuty@gmail.com
|
|||||||
SMTP_PASS=lurl pckw qugk tzob
|
SMTP_PASS=lurl pckw qugk tzob
|
||||||
|
|
||||||
# REDIS
|
# REDIS
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=10.9.0.0
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
OTP_TTL_SECONDS=300
|
OTP_TTL_SECONDS=300
|
||||||
|
|
||||||
|
|||||||
159
exthernal-ttc-api/src/controllers/reportController.js
Normal file
159
exthernal-ttc-api/src/controllers/reportController.js
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import { ReportService } from '../services/reportService.js'
|
||||||
|
import { sendError } from '../utils/response.js'
|
||||||
|
// import { OftenError } from '../utils/oftenError.js'
|
||||||
|
import { GeneralService } from '../share/generalservice.js';
|
||||||
|
import { trim_all_array } from '../utils/trim.js'
|
||||||
|
import { verifyToken, generateToken } from '../utils/token.js'
|
||||||
|
import { Interface } from '../interfaces/Interface.js';
|
||||||
|
|
||||||
|
export class reportController {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.generalService = new GeneralService();
|
||||||
|
this.reportService = new ReportService();
|
||||||
|
this.Interface = new Interface();
|
||||||
|
}
|
||||||
|
|
||||||
|
async onNavigate(req, res) {
|
||||||
|
this.generalService.devhint(1, 'reportController.js', 'onNavigate() start');
|
||||||
|
let organization = req.body.organization;
|
||||||
|
const prommis = await this.onReportController(req, res, organization);
|
||||||
|
return prommis;
|
||||||
|
}
|
||||||
|
|
||||||
|
async onReportController(req, res, database) {
|
||||||
|
let idx = -1
|
||||||
|
let aryResult = []
|
||||||
|
try {
|
||||||
|
let token = req.headers.authorization?.split(' ')[1];
|
||||||
|
const decoded = verifyToken(token);
|
||||||
|
|
||||||
|
let acpTime = req.body.request.acpTime;
|
||||||
|
let expTime = req.body.request.expTime;
|
||||||
|
database = decoded.organization;
|
||||||
|
|
||||||
|
aryResult = await this.reportService.getReportController(database, acpTime, expTime);
|
||||||
|
} catch (error) {
|
||||||
|
idx = 1;
|
||||||
|
} finally {
|
||||||
|
if (idx === 1) return sendError('เกิดข้อผิดพลาดไม่คาดคิดเกิดขึ้น', 'Unexpected error');
|
||||||
|
if (!aryResult) return sendError('ไม่พบการมีอยู่ของข้อมูล', 'Cannot Find Any Data');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// ✅ 1) เตรียม data สำหรับใช้คำนวณ
|
||||||
|
// ถ้า service คืนมาเป็น { code, message, data: [...] }
|
||||||
|
const data = Array.isArray(aryResult)
|
||||||
|
? aryResult
|
||||||
|
: Array.isArray(aryResult.data)
|
||||||
|
? aryResult.data
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// ถ้าไม่มีข้อมูลก็ไม่ต้องคำนวณ
|
||||||
|
if (!data.length) {
|
||||||
|
return aryResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) แยก Budget Type
|
||||||
|
const developStudentList = data.filter(i => i.trnbdgcod === '29');
|
||||||
|
const incomeList = data.filter(i => i.trnbdgcod === '33');
|
||||||
|
const incomeBachelorList = data.filter(i => i.trnbdgcod === '38');
|
||||||
|
const budgetCollegeList = data.filter(i => i.trnbdgcod === '24');
|
||||||
|
const budgetTeachingList = data.filter(i => i.trnbdgcod === '30');
|
||||||
|
const shortBudgetList = data.filter(i => i.trnbdgcod === '25');
|
||||||
|
|
||||||
|
// const totalIncome = incomeList.reduce((sum, i) => sum + parseFloat(i.actqty || 0), 0);
|
||||||
|
// const totalExpense = expenseList.reduce((sum, e) => sum + parseFloat(e.actqty || 0), 0);
|
||||||
|
|
||||||
|
// const netProfit = totalIncome - totalExpense;
|
||||||
|
// const profitRate = totalIncome > 0 ? (netProfit / totalIncome) * 100 : 0;
|
||||||
|
// const adjustedProfitRate = profitRate + 1.9;
|
||||||
|
|
||||||
|
// ✅ 3) แนบ summary (เหมือนที่เราทำไปก่อนหน้า)
|
||||||
|
var summary = {
|
||||||
|
// DEBUG
|
||||||
|
developStudentList: developStudentList,
|
||||||
|
incomeList: incomeList,
|
||||||
|
incomeBachelorList: incomeBachelorList,
|
||||||
|
budgetCollegeList: budgetCollegeList,
|
||||||
|
budgetTeachingList: budgetTeachingList,
|
||||||
|
shortBudgetList: shortBudgetList,
|
||||||
|
|
||||||
|
// totalIncome: totalIncome.toFixed(2),
|
||||||
|
// totalExpense: totalExpense.toFixed(2),
|
||||||
|
// netProfit: netProfit.toFixed(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
// ✅ 3.5) Create actdata table with required fields grouped by actnum
|
||||||
|
var trndata = data.map(row => ({
|
||||||
|
trnprjnam: row.trnprjnam,
|
||||||
|
trnexpbdg: row.trnexpbdg,
|
||||||
|
trnbdgnam: row.trnbdgnam,
|
||||||
|
// trnbdgcod: row.trnbdgcod, // DEBUG
|
||||||
|
trncomsttnam: row.trncomsttnam,
|
||||||
|
// trncomstt: row.trncomstt, // DEBUG
|
||||||
|
trnacpdtm: row.trnacpdtm
|
||||||
|
}));
|
||||||
|
|
||||||
|
// // ✅ 4) ดึงสีจาก dtlmst (แนะนำให้เรียกจาก service เพิ่ม)
|
||||||
|
// // ตัวอย่างสมมติ: คุณไป query มาจาก service ก่อนหน้าแล้วได้เป็น object แบบนี้
|
||||||
|
// // key = ชื่อหมวด (actcatnam หรือ code), value = color
|
||||||
|
// const categoryColorMap = await this.reportService.getCategoryColorMap(database);
|
||||||
|
// // ตัวอย่างที่คาดหวังจาก service:
|
||||||
|
// // { 'ค่าอาหาร': '#FF6384', 'ค่าเดินทาง': '#36A2EB', 'ขายสินค้า': '#4BC0C0', ... }
|
||||||
|
|
||||||
|
// // ✅ 5) สรุปยอดตามหมวด แล้วคำนวณ % สำหรับ expense
|
||||||
|
// const expenseAgg = {};
|
||||||
|
// expenseList.forEach(row => {
|
||||||
|
// const key = row.actcat; // หรือใช้รหัส category ถ้ามี เช่น row.actcatcod
|
||||||
|
// const amount = parseFloat(row.actqty || 0);
|
||||||
|
// expenseAgg[key] = (expenseAgg[key] || 0) + amount;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const incomeAgg = {};
|
||||||
|
// incomeList.forEach(row => {
|
||||||
|
// const key = row.actcat;
|
||||||
|
// const amount = parseFloat(row.actqty || 0);
|
||||||
|
// incomeAgg[key] = (incomeAgg[key] || 0) + amount;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const expensePie = Object.entries(expenseAgg).map(([cat, value]) => {
|
||||||
|
// const percent = totalExpense > 0 ? (value / totalExpense) * 100 : 0;
|
||||||
|
// const color = categoryColorMap[cat] || '#CCCCCC'; // fallback สี default
|
||||||
|
// return {
|
||||||
|
// label: cat,
|
||||||
|
// value: value.toFixed(2),
|
||||||
|
// percent: percent.toFixed(2),
|
||||||
|
// color
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const incomePie = Object.entries(incomeAgg).map(([cat, value]) => {
|
||||||
|
// const percent = totalIncome > 0 ? (value / totalIncome) * 100 : 0;
|
||||||
|
// const color = categoryColorMap[cat] || '#CCCCCC';
|
||||||
|
// return {
|
||||||
|
// label: cat,
|
||||||
|
// value: value.toFixed(2),
|
||||||
|
// percent: percent.toFixed(2),
|
||||||
|
// color
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // ✅ 6) แนบข้อมูล pie chart เข้า aryResult
|
||||||
|
// var pie = {
|
||||||
|
// expense: expensePie,
|
||||||
|
// income: incomePie
|
||||||
|
// };
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('calculate summary/pie error:', err);
|
||||||
|
}
|
||||||
|
let arydiy = {
|
||||||
|
trndata,
|
||||||
|
summary,
|
||||||
|
// pie,
|
||||||
|
}
|
||||||
|
|
||||||
|
return arydiy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import { budgetSearch } from '../controllers/budgetSearchController.js'
|
|||||||
import { budgetAdd } from '../controllers/budgetAddController.js'
|
import { budgetAdd } from '../controllers/budgetAddController.js'
|
||||||
import { projectSearch } from '../controllers/projectSearchController.js'
|
import { projectSearch } from '../controllers/projectSearchController.js'
|
||||||
import { budgetExpense } from '../controllers/budgetExpenseController.js'
|
import { budgetExpense } from '../controllers/budgetExpenseController.js'
|
||||||
|
import { reportController } from '../controllers/ReportController.js'
|
||||||
|
|
||||||
// import { authMiddleware } from '../middlewares/auth.js'
|
// import { authMiddleware } from '../middlewares/auth.js'
|
||||||
// import { sendResponse } from '../utils/response.js'
|
// import { sendResponse } from '../utils/response.js'
|
||||||
@@ -13,6 +14,7 @@ const controller_projectSearch_post = new projectSearch()
|
|||||||
const controller_budgetSearch_post = new budgetSearch()
|
const controller_budgetSearch_post = new budgetSearch()
|
||||||
const controller_budgetAdd_post = new budgetAdd()
|
const controller_budgetAdd_post = new budgetAdd()
|
||||||
const controller_budgetSetup_post = new budgetExpense()
|
const controller_budgetSetup_post = new budgetExpense()
|
||||||
|
const controller_report_post = new reportController()
|
||||||
|
|
||||||
// router.post('/budgetSetup', async (req, res) => {
|
// router.post('/budgetSetup', async (req, res) => {
|
||||||
// const result = await controller_budgetSetup_post.onNavigate(req, res)
|
// const result = await controller_budgetSetup_post.onNavigate(req, res)
|
||||||
@@ -39,5 +41,9 @@ router.post('/budgetexpense', async (req, res) => {
|
|||||||
if (result) return res.json(result)
|
if (result) return res.json(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.post('/report', async (req, res) => {
|
||||||
|
const result = await controller_report_post.onNavigate(req, res)
|
||||||
|
if (result) return res.json(result)
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
45
exthernal-ttc-api/src/services/reportService.js
Normal file
45
exthernal-ttc-api/src/services/reportService.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { GeneralService } from '../share/generalservice.js'
|
||||||
|
|
||||||
|
export class ReportService {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.generalService = new GeneralService()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getReportController(database, acpTime, expTime) {
|
||||||
|
// trnprjseq,
|
||||||
|
const sql = `
|
||||||
|
SELECT
|
||||||
|
trnprjnam,
|
||||||
|
trnexpbdg,
|
||||||
|
${database}.translatebdg(trnbdgcod) AS trnbdgnam,
|
||||||
|
trnbdgcod,
|
||||||
|
${database}.translatedtl('COMSTT', trncomstt) AS trncomsttnam,
|
||||||
|
trncomstt,
|
||||||
|
trnacpdtm
|
||||||
|
FROM ${database}.trnmst
|
||||||
|
WHERE trnacpdtm BETWEEN $1 AND $2;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const params = [acpTime, expTime];
|
||||||
|
const result = await this.generalService.executeQueryParam(database, sql, params);
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCategoryColorMap(database) {
|
||||||
|
const sql = `
|
||||||
|
SELECT dtlcod, dtlnam, dtlmsc as dtlclr
|
||||||
|
FROM ${database}.dtlmst
|
||||||
|
WHERE dtltblcod IN ('ACTCAT_INC', 'ACTCAT_EXP')
|
||||||
|
`;
|
||||||
|
const params = [];
|
||||||
|
const rows = await this.generalService.executeQueryParam(database, sql, params);
|
||||||
|
|
||||||
|
const map = {};
|
||||||
|
rows.forEach(r => {
|
||||||
|
map[r.dtlnam] = r.dtlclr;
|
||||||
|
});
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user