Initial commit: 风影 OA 全栈源码(API/Web/Flutter/IM)
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
const KEYS = ['ccDaily', 'ccWeekly', 'ccMonthly'] as const;
|
||||
|
||||
function rolesOf(emp: { users: { roles: { role: { code: string } }[] }[] }) {
|
||||
return [...new Set(emp.users.flatMap((u) => u.roles.map((r) => r.role.code)))];
|
||||
}
|
||||
|
||||
function isDirector(emp: { title?: string | null; jobRole?: string | null; users: { roles: { role: { code: string } }[] }[] }) {
|
||||
if (/总监/.test(`${emp.title || ''}${emp.jobRole || ''}`)) return true;
|
||||
return rolesOf(emp).some((r) => r.endsWith('_director') || r === 'biz_director' || r === 'owner');
|
||||
}
|
||||
|
||||
function parseIds(raw?: string | null) {
|
||||
if (!raw) return [];
|
||||
return [...new Set(raw.split(/[,,、\s]+/).filter((s) => UUID_RE.test(s)))];
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const depts = await prisma.department.findMany({ where: { tenantId: '1' }, select: { id: true, parentId: true } });
|
||||
const byId = new Map(depts.map((d) => [d.id, d]));
|
||||
const people = await prisma.employee.findMany({
|
||||
where: { tenantId: '1' },
|
||||
include: { users: { select: { roles: { select: { role: { select: { code: true } } } } } } },
|
||||
});
|
||||
const byDept = new Map<string, typeof people>();
|
||||
for (const e of people) {
|
||||
const list = byDept.get(e.departmentId) || [];
|
||||
list.push(e);
|
||||
byDept.set(e.departmentId, list);
|
||||
}
|
||||
|
||||
function scopeDeptIds(start: string, selfId: string) {
|
||||
const scope: string[] = [];
|
||||
const seen = new Set<string>();
|
||||
let cur: string | null | undefined = start;
|
||||
while (cur && !seen.has(cur)) {
|
||||
seen.add(cur);
|
||||
scope.push(cur);
|
||||
const hasDir = (byDept.get(cur) || []).some((e) => e.id !== selfId && isDirector(e));
|
||||
if (hasDir) break;
|
||||
cur = byId.get(cur)?.parentId;
|
||||
}
|
||||
return new Set(scope);
|
||||
}
|
||||
|
||||
let n = 0;
|
||||
for (const emp of people) {
|
||||
const scope = scopeDeptIds(emp.departmentId, emp.id);
|
||||
const dirs = people.filter((d) => scope.has(d.departmentId) && d.id !== emp.id && d.id !== emp.managerId && isDirector(d));
|
||||
const dirIds = dirs.map((d) => d.id);
|
||||
const allowed = new Set(dirIds);
|
||||
const data: Partial<Record<(typeof KEYS)[number], string | null>> = {};
|
||||
for (const key of KEYS) {
|
||||
const cur = parseIds(emp[key]);
|
||||
let next = cur.filter((id) => allowed.has(id));
|
||||
if (!next.length && dirIds.length && cur.some((id) => id === emp.managerId || !allowed.has(id))) {
|
||||
next = dirIds;
|
||||
}
|
||||
const joined = next.length ? next.join(',') : null;
|
||||
if (joined !== (emp[key] || null)) data[key] = joined;
|
||||
}
|
||||
if (!Object.keys(data).length) continue;
|
||||
await prisma.employee.update({ where: { id: emp.id }, data });
|
||||
n += 1;
|
||||
console.log(`${emp.name}: ${JSON.stringify(data)}`);
|
||||
}
|
||||
console.log(`updated ${n} / ${people.length} employee cc fields`);
|
||||
}
|
||||
|
||||
main()
|
||||
.then(async () => prisma.$disconnect())
|
||||
.catch(async (e) => {
|
||||
console.error(e);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user