You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
10 KiB

import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcryptjs';
const prisma = new PrismaClient();
async function main() {
const tenant = await prisma.tenant.upsert({
where: { code: 'default' },
update: {},
create: { name: '默认租户', code: 'default' },
});
const china = await prisma.region.upsert({
where: { code: '100000' },
update: {},
create: { code: '100000', name: '全国', level: 0, longitude: 104.195397, latitude: 35.86166 },
});
const province = await prisma.region.upsert({
where: { code: '110000' },
update: {},
create: { code: '110000', name: '北京市', level: 1, parentId: china.id, longitude: 116.407526, latitude: 39.90403 },
});
const city = await prisma.region.upsert({
where: { code: '110100' },
update: {},
create: { code: '110100', name: '北京市', level: 2, parentId: province.id, longitude: 116.407526, latitude: 39.90403 },
});
const district = await prisma.region.upsert({
where: { code: '110101' },
update: {},
create: { code: '110101', name: '东城区', level: 3, parentId: city.id, longitude: 116.416357, latitude: 39.928353 },
});
const shanghai = await prisma.region.upsert({
where: { code: '310000' },
update: {},
create: { code: '310000', name: '上海市', level: 1, parentId: china.id, longitude: 121.473701, latitude: 31.230416 },
});
const shanghaiCity = await prisma.region.upsert({
where: { code: '310100' },
update: {},
create: { code: '310100', name: '上海市', level: 2, parentId: shanghai.id, longitude: 121.473701, latitude: 31.230416 },
});
const pudong = await prisma.region.upsert({
where: { code: '310115' },
update: {},
create: { code: '310115', name: '浦东新区', level: 3, parentId: shanghaiCity.id, longitude: 121.544346, latitude: 31.221461 },
});
const guangdong = await prisma.region.upsert({
where: { code: '440000' },
update: {},
create: { code: '440000', name: '广东省', level: 1, parentId: china.id, longitude: 113.266887, latitude: 23.133306 },
});
const guangzhou = await prisma.region.upsert({
where: { code: '440100' },
update: {},
create: { code: '440100', name: '广州市', level: 2, parentId: guangdong.id, longitude: 113.264385, latitude: 23.129112 },
});
const tianhe = await prisma.region.upsert({
where: { code: '440106' },
update: {},
create: { code: '440106', name: '天河区', level: 3, parentId: guangzhou.id, longitude: 113.361597, latitude: 23.124817 },
});
const zhejiang = await prisma.region.upsert({
where: { code: '330000' },
update: {},
create: { code: '330000', name: '浙江省', level: 1, parentId: china.id, longitude: 120.152575, latitude: 30.266619 },
});
const hangzhou = await prisma.region.upsert({
where: { code: '330100' },
update: {},
create: { code: '330100', name: '杭州市', level: 2, parentId: zhejiang.id, longitude: 120.15507, latitude: 30.274085 },
});
const xihu = await prisma.region.upsert({
where: { code: '330106' },
update: {},
create: { code: '330106', name: '西湖区', level: 3, parentId: hangzhou.id, longitude: 120.130396, latitude: 30.259242 },
});
const permissions = [
['tenants:manage', '租户管理', 'MENU', '/system/tenants'],
['dashboard:view', '数据看板', 'MENU', '/dashboard'],
['map:view', '地图监控', 'MENU', '/map'],
['lamps:manage', '路灯管理', 'MENU', '/lamps'],
['alarms:manage', '报警管理', 'MENU', '/alarms'],
['system:manage', '系统管理', 'MENU', '/system/users'],
] as const;
for (const [code, name, type, path] of permissions) {
await prisma.permission.upsert({
where: { code },
update: {},
create: { code, name, type, path },
});
}
let platformRole = await prisma.role.findFirst({ where: { tenantId: null, code: 'platform_super_admin' } });
if (!platformRole) {
platformRole = await prisma.role.create({
data: {
name: '平台超级管理员',
code: 'platform_super_admin',
description: '仅用于平台租户管理,不在页面中配置',
},
});
}
const tenantManagePermission = await prisma.permission.findUnique({ where: { code: 'tenants:manage' } });
if (tenantManagePermission) {
await prisma.rolePermission.createMany({
data: [{ roleId: platformRole.id, permissionId: tenantManagePermission.id }],
skipDuplicates: true,
});
}
let platformAdmin = await prisma.user.findFirst({ where: { tenantId: null, username: 'admin' } });
if (!platformAdmin) {
platformAdmin = await prisma.user.create({
data: {
username: 'admin',
passwordHash: await bcrypt.hash('admin123456', 10),
name: '平台超级管理员',
roles: { create: [{ roleId: platformRole.id }] },
},
});
}
let role = await prisma.role.findFirst({ where: { tenantId: tenant.id, code: { in: ['tenant_admin', 'super_admin'] } } });
if (role) {
role = await prisma.role.update({
where: { id: role.id },
data: { name: '租户管理员', code: 'tenant_admin', description: '租户初始化管理员角色' },
});
} else {
role = await prisma.role.create({
data: { name: '租户管理员', code: 'tenant_admin', description: '租户初始化管理员角色', tenantId: tenant.id },
});
}
const allPermissions = await prisma.permission.findMany({ where: { code: { not: 'tenants:manage' } } });
await prisma.rolePermission.createMany({
data: allPermissions.map((permission) => ({ roleId: role.id, permissionId: permission.id })),
skipDuplicates: true,
});
await prisma.roleRegionScope.createMany({
data: [{ roleId: role.id, regionId: china.id }],
skipDuplicates: true,
});
let admin = await prisma.user.findFirst({ where: { tenantId: tenant.id, username: 'admin' } });
if (admin) {
admin = await prisma.user.update({
where: { id: admin.id },
data: { name: '系统管理员' },
});
} else {
admin = await prisma.user.create({
data: {
username: 'admin',
passwordHash: await bcrypt.hash('admin123456', 10),
name: '系统管理员',
tenantId: tenant.id,
roles: { create: [{ roleId: role.id }] },
regionScopes: { create: [{ regionId: china.id }] },
},
});
}
const sampleLamps = [
['BJ-DC-0001', '东城区智慧路灯 A01', district.id, '北京市东城区东长安街', 116.416357, 39.928353, '单灯', 'NORMAL', 'ONLINE'],
['BJ-DC-0002', '东城区智慧路灯 A02', district.id, '北京市东城区王府井大街', 116.411568, 39.908823, '单灯', 'FAULT', 'ONLINE'],
['BJ-DC-0003', '东城区智慧路灯 A03', district.id, '北京市东城区朝阳门内大街', 116.433235, 39.924463, '单灯', 'MAINTENANCE', 'OFFLINE'],
['SH-PD-0001', '浦东新区智慧路灯 P01', pudong.id, '上海市浦东新区世纪大道', 121.544346, 31.221461, '单灯', 'NORMAL', 'ONLINE'],
['SH-PD-0002', '浦东新区智慧路灯 P02', pudong.id, '上海市浦东新区陆家嘴环路', 121.502833, 31.239101, '单灯', 'FAULT', 'ONLINE'],
['GZ-TH-0001', '天河区智慧路灯 T01', tianhe.id, '广州市天河区体育西路', 113.321478, 23.132191, '单灯', 'NORMAL', 'ONLINE'],
['GZ-TH-0002', '天河区智慧路灯 T02', tianhe.id, '广州市天河区珠江新城', 113.32459, 23.119962, '单灯', 'OFFLINE', 'OFFLINE'],
['HZ-XH-0001', '西湖区智慧路灯 X01', xihu.id, '杭州市西湖区文三路', 120.130396, 30.279242, '单灯', 'NORMAL', 'ONLINE'],
['HZ-XH-0002', '西湖区智慧路灯 X02', xihu.id, '杭州市西湖区曙光路', 120.14321, 30.26311, '单灯', 'FAULT', 'ONLINE'],
] as const;
const lampMap = new Map<string, { id: string; regionId: string }>();
for (const [code, name, regionId, address, longitude, latitude, deviceType, status, onlineStatus] of sampleLamps) {
const lamp = await prisma.streetLamp.upsert({
where: { code },
update: { name, regionId, address, longitude, latitude, deviceType, status, onlineStatus },
create: {
code,
name,
tenantId: tenant.id,
regionId,
address,
longitude,
latitude,
deviceType,
status,
onlineStatus,
lastReportedAt: onlineStatus === 'ONLINE' ? new Date(Date.now() - Math.random() * 1000 * 60 * 45) : undefined,
},
});
lampMap.set(code, { id: lamp.id, regionId: lamp.regionId });
}
const sampleAlarms = [
['sample-alarm-001', 'BJ-DC-0001', 'POWER_FAILURE', '路灯断电报警', '设备供电异常,请尽快排查配电箱。', 'HIGH', 'OPEN', 18],
['sample-alarm-002', 'BJ-DC-0002', 'LAMP_FAULT', '灯具故障报警', '灯具电流异常,疑似光源损坏。', 'MEDIUM', 'PROCESSING', 65],
['sample-alarm-003', 'SH-PD-0002', 'DOOR_OPEN', '灯杆箱门开启', '箱门异常开启,存在安全风险。', 'CRITICAL', 'OPEN', 12],
['sample-alarm-004', 'GZ-TH-0002', 'OFFLINE', '设备离线报警', '设备超过 30 分钟未上报数据。', 'HIGH', 'OPEN', 42],
['sample-alarm-005', 'HZ-XH-0002', 'VOLTAGE_ABNORMAL', '电压异常报警', '输入电压波动超过阈值。', 'MEDIUM', 'PROCESSING', 95],
['sample-alarm-006', 'SH-PD-0001', 'BRIGHTNESS_LOW', '亮度不足报警', '夜间亮度低于策略要求。', 'LOW', 'RESOLVED', 240],
] as const;
for (const [sourceAlarmId, lampCode, type, title, description, level, status, minutesAgo] of sampleAlarms) {
const lamp = lampMap.get(lampCode);
if (!lamp) {
continue;
}
await prisma.alarm.upsert({
where: { sourceAlarmId },
update: { status },
create: {
sourceAlarmId,
tenantId: tenant.id,
lampId: lamp.id,
regionId: lamp.regionId,
type,
title,
description,
level,
status,
occurredAt: new Date(Date.now() - minutesAgo * 60 * 1000),
recoveredAt: status === 'RESOLVED' ? new Date(Date.now() - 60 * 60 * 1000) : undefined,
events: { create: [{ eventType: 'CREATED', payload: { seededBy: platformAdmin.username, tenantAdmin: admin.username } }] },
},
});
}
}
main()
.then(async () => prisma.$disconnect())
.catch(async (error) => {
console.error(error);
await prisma.$disconnect();
process.exit(1);
});