1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
| /**
| * 能耗台账 10 月补充生成器(模板快照 -> 补录 SQL)
| *
| * 目标库:36.213.150.237:10000/mom-hm
| * 依据:9 月已有的每日台账模板(8 区域 × 水/电/汽)
| *
| * 规则(已与用户确认):
| * - 范围:2026-10-01 ~ 2026-10-14(不含 15 日)
| * - 沿用 9 月模板:工作日 21 条/天(水/电/汽),节假日 16 条/天(仅水/电,无蒸汽)
| * - 节假日:10/1–10/7(国庆)+ 10/11(周日),用量约为工作日的 30%
| * - 保留库里已有的 10/8、10/9、10/12、10/14 四条零散记录(不删除、不覆盖)
| * - 单价沿用:水 5.2 / 电 0.83 / 汽 248(元/能源单位)
| * - 金额 = 用量 × 单价,四舍五入到分
| */
| import fs from 'node:fs';
| import path from 'node:path';
| import { fileURLToPath } from 'node:url';
|
| const DIR = path.dirname(fileURLToPath(import.meta.url));
| const BIZ = 'energy-record-fill-20261015';
|
| const UNIT = { WATER: 5.2, ELECTRICITY: 0.83, STEAM: 248 };
|
| // 日报模板:[区域, 产品类别, 用途, 能源类型, 工作日基准用量, 录入人, 创建人]
| const TPL = [
| ['燕窝生产区', '燕窝', '蒸煮提取', 'WATER', 12.5, '李万娟', '244'],
| ['燕窝生产区', '燕窝', '蒸煮提取', 'ELECTRICITY', 520, '李万娟', '244'],
| ['燕窝生产区', '燕窝', '蒸煮提取', 'STEAM', 1.85, '李万娟', '244'],
| ['原浆生产区', '滋补品原浆', '蒸煮提取', 'WATER', 17.5, '李万娟', '244'],
| ['原浆生产区', '滋补品原浆', '蒸煮提取', 'ELECTRICITY', 640, '李万娟', '244'],
| ['原浆生产区', '滋补品原浆', '蒸煮提取', 'STEAM', 2.45, '李万娟', '244'],
| ['清洗区', '燕窝', '原料清洗', 'WATER', 22.0, '李万娟', '244'],
| ['清洗区', '燕窝', '设备清洗 / CIP', 'ELECTRICITY', 145, '李万娟', '244'],
| ['清洗区', '燕窝', '设备清洗 / CIP', 'STEAM', 0.72, '李万娟', '244'],
| ['灭菌区', '燕窝', '灭菌', 'WATER', 6.2, '李万娟', '244'],
| ['灭菌区', '燕窝', '灭菌', 'ELECTRICITY', 300, '李万娟', '244'],
| ['灭菌区', '燕窝', '灭菌', 'STEAM', 1.22, '李万娟', '244'],
| ['灌装包装区', '燕窝', '灌装包装', 'WATER', 5.0, '李万娟', '244'],
| ['灌装包装区', '燕窝', '灌装包装', 'ELECTRICITY', 420, '李万娟', '244'],
| ['灌装包装区', '燕窝', '灌装包装', 'STEAM', 0.58, '李万娟', '244'],
| ['动力站', '公用能耗', '制冷', 'WATER', 27.5, '赵磊', '243'],
| ['动力站', '公用能耗', '制冷', 'ELECTRICITY', 1950, '赵磊', '243'],
| ['仓储区', '公用能耗', '日常用能', 'WATER', 1.2, '赵磊', '243'],
| ['仓储区', '公用能耗', '制冷', 'ELECTRICITY', 380, '赵磊', '243'],
| ['办公生活区', '公用能耗', '日常用能', 'WATER', 9.5, '赵磊', '243'],
| ['办公生活区', '公用能耗', '日常用能', 'ELECTRICITY', 300, '赵磊', '243'],
| ];
|
| const HOLIDAYS = new Set([
| '2026-10-01', '2026-10-02', '2026-10-03', '2026-10-04',
| '2026-10-05', '2026-10-06', '2026-10-07', '2026-10-11',
| ]);
|
| const DATES = [];
| for (let d = 1; d <= 14; d++) DATES.push(`2026-10-${String(d).padStart(2, '0')}`);
|
| const HOLIDAY_SCALE = 0.30;
|
| // 确定性伪随机(mulberry32),按日期+行序播种,保证重跑结果一致
| function rng(seed) {
| let a = seed >>> 0;
| return () => {
| a |= 0; a = (a + 0x6D2B79F5) | 0;
| let t = Math.imul(a ^ (a >>> 15), 1 | a);
| t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
| return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
| };
| }
| const dayNum = (s) => Number(s.slice(8, 10));
| const round = (v, n) => Number(v.toFixed(n));
|
| const q = (v) => `'${String(v).replaceAll("'", "''")}'`;
| const rows = [];
|
| for (const date of DATES) {
| const holiday = HOLIDAYS.has(date);
| const tpl = holiday ? TPL.filter((r) => r[3] !== 'STEAM') : TPL;
| tpl.forEach(([area, category, purpose, type, base, recorder, creator], idx) => {
| const rand = rng(dayNum(date) * 1000 + idx)();
| const jitter = 0.85 + 0.30 * rand; // ±约15%
| const scale = holiday ? HOLIDAY_SCALE : 1;
| const quantity = round(base * scale * jitter, 3);
| const unitPrice = UNIT[type];
| const amount = round(quantity * unitPrice, 2);
| rows.push({
| date, type, area, category, purpose, quantity, unitPrice, amount, recorder, creator, holiday,
| });
| });
| }
|
| const out = [];
| out.push(`-- 能耗台账 10 月补充 | 目标库 mom-hm | ${BIZ}`);
| out.push('-- 范围 2026-10-01 ~ 2026-10-14;节假日(10/1-10/7、10/11)仅水/电、用量约 3 成。');
| out.push('-- 回滚:DELETE FROM mes_energy_record WHERE record_date BETWEEN \'2026-10-01\' AND \'2026-10-14\';');
| out.push('-- (注意:会同时删掉 10/8、10/9、10/12、10/14 原有的 4 条记录,需事先备份。)');
| out.push('START TRANSACTION;');
| out.push(`\n-- mes_energy_record : ${rows.length} 行`);
| const vals = rows.map((r) =>
| `(${q(r.date)},${q(r.type)},${q(r.area)},${q(r.category)},${q(r.purpose)},${r.quantity.toFixed(3)},${r.unitPrice.toFixed(4)},${r.amount.toFixed(2)},${q(r.recorder)},'',${q(r.date + ' 17:30:00')},${q(r.creator)},${q(r.date + ' 17:30:00')},b'0')`,
| );
| for (let i = 0; i < vals.length; i += 200) {
| out.push(
| `INSERT INTO mes_energy_record (record_date,energy_type,usage_area,product_category,usage_purpose,quantity,unit_price,amount,recorder,remark,create_time,creator,update_time,deleted) VALUES\n${vals.slice(i, i + 200).join(',\n')};`,
| );
| }
| out.push('\nCOMMIT;');
|
| fs.writeFileSync(path.join(DIR, 'energy-oct.sql'), out.join('\n'), 'utf8');
| fs.writeFileSync(path.join(DIR, 'energy-oct-plan.json'), JSON.stringify({ count: rows.length, rows }, null, 1), 'utf8');
|
| const byDate = {};
| for (const r of rows) byDate[r.date] = (byDate[r.date] ?? 0) + 1;
| console.log('total rows:', rows.length);
| console.log(byDate);
|
|