Remove backup/env files from tracking, update .gitignore

This commit is contained in:
stringadmin
2026-06-02 13:14:38 +08:00
parent 56955e32f7
commit 0f8f3825e1
8 changed files with 5 additions and 6367 deletions
-12
View File
@@ -1,12 +0,0 @@
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=omniai
PG_USER=omniai
PG_PASSWORD=bybyby@123
PG_POOL_MAX=10
PORT=3600
HOST=0.0.0.0
JWT_SECRET=499808ef76791e59ab1019f8fbb86d2b
DEFAULT_ADMIN_PASSWORD=bybyby@123BY
JWT_EXPIRES_IN=7d
CORS_ORIGINS=*
-17
View File
@@ -1,17 +0,0 @@
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=omniai
PG_USER=omniai
PG_PASSWORD=bybyby@123
PG_POOL_MAX=10
PORT=3600
HOST=0.0.0.0
JWT_SECRET=499808ef76791e59ab1019f8fbb86d2b
DEFAULT_ADMIN_PASSWORD=bybyby@123BY
JWT_EXPIRES_IN=7d
CORS_ORIGINS=*
STS_ACCESS_KEY_ID=LTAI5t7qL3iR9dchydHQ3cmT
STS_ACCESS_KEY_SECRET=ssywO1bUwu2pPZaq3KugXbaE0Za9gi
OSS_ROLE_ARN=acs:ram::1582660594690998:role/omniai-oss-role
OSS_BUCKET=stringtest
OSS_REGION=oss-cn-hangzhou
-17
View File
@@ -1,17 +0,0 @@
PG_HOST=localhost
PG_PORT=5432
PG_DATABASE=omniai
PG_USER=omniai
PG_PASSWORD=bybyby@123
PG_POOL_MAX=10
PORT=3600
HOST=0.0.0.0
JWT_SECRET=499808ef76791e59ab1019f8fbb86d2b
DEFAULT_ADMIN_PASSWORD=bybyby@123BY
JWT_EXPIRES_IN=7d
CORS_ORIGINS=*
STS_ACCESS_KEY_ID=LTAI5t7qL3iR9dchydHQ3cmT
STS_ACCESS_KEY_SECRET=ssywO1bUwu2pPZaq3KugXbaE0Za9gi
OSS_ROLE_ARN=acs:ram::1582660594690998:role/OmniAI-OSS-Upload
OSS_BUCKET=stringtest
OSS_REGION=oss-cn-hangzhou
+5
View File
@@ -8,3 +8,8 @@ config/internal-beta-codes.md
data/ data/
*.tmp *.tmp
.DS_Store .DS_Store
*.env.backup*
*.env.rolefix*
*.env.enterprise*
src/routes/ai.js.bak*
src/routes/enterprise.js.enterprise-usage-fix*
-1956
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,456 +0,0 @@
const {
requireAuth,
requireEnterpriseAdmin,
distributeCredits,
getEnterpriseFinancials,
getEnterpriseName,
pool,
getPeriodStart,
generateOrderNo,
clampPositiveInteger,
clampNonNegativeInteger,
} = require("./context");
function registerEnterpriseRoutes(router) {
// ── Enterprise: Dashboard & Financials ────────────────────────────────
router.get("/enterprise/dashboard", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const financials = await getEnterpriseFinancials(req.user.enterpriseId);
const {
rows: [countRow],
} = await pool.query(
"SELECT COUNT(*) AS count FROM users WHERE enterprise_id = $1 AND enabled = 1 AND is_enterprise_admin = 0",
[req.user.enterpriseId],
);
res.json({
enterpriseName: req.user.enterpriseName,
enterpriseCode: req.user.enterpriseCode,
balanceCents: financials.balanceCents,
activePackages: financials.activePackages,
subAccountCount: Number(countRow?.count || 0),
});
});
router.get("/enterprise/financials", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const financials = await getEnterpriseFinancials(req.user.enterpriseId);
res.json({
balanceCents: financials.balanceCents,
activePackages: financials.activePackages.map((p) => ({
id: p.id,
packageName: p.package_name,
remainingImage: p.remaining_image,
remainingVideo: p.remaining_video,
remainingText: p.remaining_text,
expiresAt: p.expires_at,
activatedAt: p.activated_at,
})),
recentTransactions: financials.recentTransactions.map((t) => ({
id: t.id,
type: t.type,
amountCents: t.amount_cents,
balanceAfterCents: t.balance_after_cents,
description: t.description,
createdAt: t.created_at,
})),
});
});
router.get("/enterprise/usage/summary", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const { period = "30d" } = req.query;
const periodStart = getPeriodStart(period);
const ledgerDateJoin = periodStart ? `AND cl.created_at >= ${periodStart}` : "";
const ledgerDateWhere = periodStart ? `AND created_at >= ${periodStart}` : "";
const recordsLimit = clampPositiveInteger(req.query.limit, 50, 200);
try {
const {
rows: [enterprise],
} = await pool.query(
"SELECT id, name, balance_cents FROM enterprises WHERE id = $1 AND enabled = 1 LIMIT 1",
[req.user.enterpriseId],
);
if (!enterprise) return res.status(404).json({ error: "企业不存在或已禁用" });
const { rows: members } = await pool.query(
`
SELECT
u.id AS user_id,
u.username,
COALESCE(em.role, CASE WHEN u.is_enterprise_admin = 1 THEN 'admin' ELSE 'employee' END) AS role,
COALESCE(SUM(CASE WHEN cl.status IN ('reserved', 'charged') THEN cl.amount_cents ELSE 0 END), 0) AS used_cents,
COUNT(CASE WHEN cl.status IN ('reserved', 'charged') THEN 1 END) AS task_count,
MAX(cl.created_at) AS last_used_at
FROM users u
LEFT JOIN enterprise_members em ON em.enterprise_id = u.enterprise_id AND em.user_id = u.id
LEFT JOIN credit_ledger cl ON cl.enterprise_id = u.enterprise_id AND cl.user_id = u.id ${ledgerDateJoin}
WHERE u.enterprise_id = $1 AND u.enabled = 1
GROUP BY u.id, u.username, role
ORDER BY used_cents DESC, u.id ASC
`,
[req.user.enterpriseId],
);
const { rows: modelBreakdown } = await pool.query(
`
SELECT
COALESCE(model, 'unknown') AS model,
COALESCE(SUM(amount_cents), 0) AS used_cents,
COUNT(*) AS task_count
FROM credit_ledger
WHERE enterprise_id = $1
AND status IN ('reserved', 'charged')
${ledgerDateWhere}
GROUP BY COALESCE(model, 'unknown')
ORDER BY used_cents DESC
LIMIT 50
`,
[req.user.enterpriseId],
);
const {
rows: [totalRow],
} = await pool.query(
`
SELECT COALESCE(SUM(amount_cents), 0) AS total_used_cents
FROM credit_ledger
WHERE enterprise_id = $1
AND status IN ('reserved', 'charged')
${ledgerDateWhere}
`,
[req.user.enterpriseId],
);
const { rows: records } = await pool.query(
`
SELECT cl.*, u.username
FROM credit_ledger cl
LEFT JOIN users u ON u.id = cl.user_id
WHERE cl.enterprise_id = $1
AND cl.status IN ('reserved', 'charged')
${periodStart ? `AND cl.created_at >= ${periodStart}` : ""}
ORDER BY cl.created_at DESC
LIMIT $2
`,
[req.user.enterpriseId, recordsLimit],
);
res.json({
enterpriseId: String(enterprise.id),
enterpriseName: enterprise.name,
balanceCents: Number(enterprise.balance_cents || 0),
totalUsedCents: Number(totalRow?.total_used_cents || 0),
members: members.map((row) => ({
userId: Number(row.user_id),
username: row.username,
role: row.role || "employee",
usedCents: Number(row.used_cents || 0),
taskCount: Number(row.task_count || 0),
lastUsedAt: row.last_used_at || null,
})),
modelBreakdown: modelBreakdown.map((row) => ({
model: row.model,
usedCents: Number(row.used_cents || 0),
taskCount: Number(row.task_count || 0),
})),
records: records.map((row) => ({
id: String(row.id),
userId: row.user_id == null ? "" : Number(row.user_id),
username: row.username || "",
model: row.model || "",
taskType: row.task_type,
resolution: row.resolution || null,
durationSeconds: row.duration_seconds == null ? null : Number(row.duration_seconds),
amountCents: Number(row.amount_cents || 0),
status: row.status,
createdAt: row.created_at,
})),
});
} catch (error) {
console.error("[enterprise/usage/summary] failed", error);
res.status(500).json({ error: "企业用量汇总加载失败" });
}
});
router.get("/enterprise/usage/records", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const limit = clampPositiveInteger(req.query.limit, 50, 200);
const offset = clampNonNegativeInteger(req.query.offset, 0, 100000);
const userId = req.query.userId || req.query.user_id;
const model = String(req.query.model || "").trim();
const dateFrom = req.query.from || req.query.date_from;
const dateTo = req.query.to || req.query.date_to;
const where = ["cl.enterprise_id = $1"];
const params = [req.user.enterpriseId];
if (userId) {
params.push(userId);
where.push(`cl.user_id = $${params.length}`);
}
if (model) {
params.push(model);
where.push(`cl.model = $${params.length}`);
}
if (dateFrom) {
params.push(`${dateFrom}T00:00:00.000Z`);
where.push(`cl.created_at >= $${params.length}`);
}
if (dateTo) {
params.push(`${dateTo}T23:59:59.999Z`);
where.push(`cl.created_at <= $${params.length}`);
}
const whereSql = `WHERE ${where.join(" AND ")}`;
try {
const {
rows: [countRow],
} = await pool.query(`SELECT COUNT(*) AS total FROM credit_ledger cl ${whereSql}`, params);
const { rows } = await pool.query(
`
SELECT cl.*, u.username
FROM credit_ledger cl
LEFT JOIN users u ON u.id = cl.user_id
${whereSql}
ORDER BY cl.created_at DESC
LIMIT $${params.length + 1}
OFFSET $${params.length + 2}
`,
[...params, limit, offset],
);
res.json({
items: rows.map((row) => ({
id: String(row.id),
userId: row.user_id == null ? "" : Number(row.user_id),
username: row.username || "",
model: row.model || "",
taskType: row.task_type,
resolution: row.resolution || null,
durationSeconds: row.duration_seconds == null ? null : Number(row.duration_seconds),
amountCents: Number(row.amount_cents || 0),
status: row.status,
createdAt: row.created_at,
})),
total: Number(countRow?.total || 0),
limit,
offset,
});
} catch (error) {
console.error("[enterprise/usage/records] failed", error);
res.status(500).json({ error: "企业用量记录加载失败" });
}
});
router.post("/enterprise/recharge", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const { amountCents, paymentMethod = "wechat" } = req.body;
if (!amountCents || amountCents <= 0)
return res.status(400).json({ error: "充值金额必须大于0" });
const orderNo = generateOrderNo();
const enterpriseName = await getEnterpriseName(req.user.enterpriseId);
try {
await pool.query(
`
INSERT INTO payment_orders (order_no, enterprise_id, enterprise_name, type, amount_cents, payment_method, status)
VALUES ($1, $2, $3, 'recharge', $4, $5, 'pending')
`,
[orderNo, req.user.enterpriseId, enterpriseName, Number(amountCents), paymentMethod],
);
res.json({ orderNo, amountCents, paymentMethod });
} catch (error) {
console.error("[enterprise/recharge] failed", error);
res.status(500).json({ error: "创建充值订单失败" });
}
});
router.post("/enterprise/distribute", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const { userId, amountCents, distributions } = req.body;
try {
if (distributions && Array.isArray(distributions)) {
for (const d of distributions) {
if (!d.userId || !d.amountCents || d.amountCents <= 0) {
return res
.status(400)
.json({ error: "每条分发记录必须包含有效的 userId 和 amountCents" });
}
await distributeCredits(req.user.enterpriseId, d.userId, d.amountCents, req.user.id);
}
res.json({ success: true, count: distributions.length });
} else if (userId && amountCents) {
if (amountCents <= 0) return res.status(400).json({ error: "分发积分必须大于0" });
const result = await distributeCredits(
req.user.enterpriseId,
userId,
amountCents,
req.user.id,
);
res.json({ success: true, ...result });
} else {
return res.status(400).json({ error: "缺少分发参数" });
}
} catch (error) {
console.error("[enterprise/distribute] failed", error);
res.status(400).json({ error: "分发参数处理失败" });
}
});
router.get(
"/enterprise/employee-consumption",
requireAuth,
requireEnterpriseAdmin,
async (req, res) => {
const { period = "30d" } = req.query;
const periodStart = getPeriodStart(period);
const whereClause = periodStart ? `AND acl.created_at >= ${periodStart}` : "";
const { rows } = await pool.query(
`
SELECT
u.id AS user_id,
u.username,
u.balance_cents AS current_balance_cents,
COUNT(acl.id) AS total_calls,
COALESCE(SUM(CASE WHEN acl.cost_estimate IS NOT NULL THEN CAST(ROUND((acl.cost_estimate * 100)::numeric) AS INTEGER) ELSE 0 END), 0) AS total_cost_cents,
MAX(acl.created_at) AS last_active
FROM users u
LEFT JOIN api_call_logs acl ON acl.user_id = u.id AND acl.status = 'success'
WHERE u.enterprise_id = $1 AND u.enabled = 1 AND u.is_enterprise_admin = 0 ${whereClause}
GROUP BY u.id, u.username, u.balance_cents
ORDER BY total_cost_cents DESC
`,
[req.user.enterpriseId],
);
res.json(
rows.map((r) => ({
userId: Number(r.user_id),
username: r.username,
currentBalanceCents: Number(r.current_balance_cents),
totalCalls: Number(r.total_calls),
totalCostCents: Number(r.total_cost_cents),
lastActive: r.last_active,
})),
);
},
);
router.post(
"/enterprise/purchase-package",
requireAuth,
requireEnterpriseAdmin,
async (req, res) => {
const { packageId, paymentMethod = "wechat" } = req.body;
if (!packageId) return res.status(400).json({ error: "缺少套餐ID" });
const {
rows: [pkg],
} = await pool.query("SELECT * FROM packages WHERE id = $1 AND enabled = 1", [packageId]);
if (!pkg) return res.status(404).json({ error: "套餐不存在或已下架" });
const orderNo = generateOrderNo();
const enterpriseName = await getEnterpriseName(req.user.enterpriseId);
try {
await pool.query(
`
INSERT INTO payment_orders (order_no, enterprise_id, enterprise_name, type, amount_cents, package_id, payment_method, status)
VALUES ($1, $2, $3, 'package', $4, $5, $6, 'pending')
`,
[
orderNo,
req.user.enterpriseId,
enterpriseName,
pkg.price_cents,
packageId,
paymentMethod,
],
);
res.json({ orderNo, amountCents: pkg.price_cents, packageId, paymentMethod });
} catch (error) {
console.error("[enterprise/purchase-package] failed", error);
res.status(500).json({ error: "创建套餐订单失败" });
}
},
);
// ── Enterprise: Invoices ──────────────────────────────────────────────
router.post(
"/enterprise/invoice-apply",
requireAuth,
requireEnterpriseAdmin,
async (req, res) => {
const { paymentOrderId, type = "general", title, taxNo } = req.body;
if (!title) return res.status(400).json({ error: "缺少发票抬头" });
let amountCents = 0;
if (paymentOrderId) {
const {
rows: [order],
} = await pool.query(
"SELECT * FROM payment_orders WHERE id = $1 AND enterprise_id = $2 AND status = $3",
[paymentOrderId, req.user.enterpriseId, "paid"],
);
if (!order) return res.status(404).json({ error: "支付订单不存在或未支付" });
amountCents = order.amount_cents;
}
const enterpriseName = await getEnterpriseName(req.user.enterpriseId);
try {
const {
rows: [row],
} = await pool.query(
`
INSERT INTO invoices (enterprise_id, enterprise_name, payment_order_id, type, title, tax_no, amount_cents, status)
VALUES ($1, $2, $3, $4, $5, $6, $7, 'pending')
RETURNING id
`,
[
req.user.enterpriseId,
enterpriseName,
paymentOrderId || null,
type,
title,
taxNo || null,
amountCents,
],
);
res.json({ id: row.id, success: true });
} catch (error) {
console.error("[enterprise/invoice-apply] failed", error);
res.status(500).json({ error: "申请发票失败" });
}
},
);
router.get("/enterprise/invoices", requireAuth, requireEnterpriseAdmin, async (req, res) => {
const { rows } = await pool.query(
"SELECT * FROM invoices WHERE enterprise_id = $1 ORDER BY id DESC",
[req.user.enterpriseId],
);
res.json(
rows.map((row) => ({
id: Number(row.id),
type: row.type,
title: row.title,
taxNo: row.tax_no,
amountCents: row.amount_cents,
status: row.status,
invoiceNo: row.invoice_no,
invoiceUrl: row.invoice_url,
issuedAt: row.issued_at,
createdAt: row.created_at,
})),
);
});
}
module.exports = {
registerEnterpriseRoutes,
};