diff --git a/_docs/sql/alter_plan_api_permission.sql b/_docs/sql/alter_plan_api_permission.sql index 2aeb535..cb992a0 100644 --- a/_docs/sql/alter_plan_api_permission.sql +++ b/_docs/sql/alter_plan_api_permission.sql @@ -1,8 +1,14 @@ --- biz_plans 新增:可访问接口列表 + 每月API调用次数上限 -ALTER TABLE `biz_plans` - ADD COLUMN `allowed_apis` JSON DEFAULT NULL COMMENT '可访问的接口路径列表,null=不限制' AFTER `enabled_features`, - ADD COLUMN `api_call_quota` INT NOT NULL DEFAULT 0 COMMENT '每月API总调用次数上限,0=不限制' AFTER `allowed_apis`; +-- 在「与后端 app 相同」的 MySQL 库中执行(否则会一直报 Unknown column)。 +-- 可重复执行:若列已存在会报错,可忽略对应语句或改用 scripts/migrate_biz_plan_api_columns.js --- biz_usage_monthly 新增:当月API调用总次数 +SET NAMES utf8mb4; + +-- biz_plans(分两条,方便只缺其中一列时单独执行) +ALTER TABLE `biz_plans` + ADD COLUMN `allowed_apis` JSON DEFAULT NULL COMMENT '可访问的接口路径列表,null=不限制'; +ALTER TABLE `biz_plans` + ADD COLUMN `api_call_quota` INT NOT NULL DEFAULT 0 COMMENT '每月API总调用次数上限,0=不限制'; + +-- biz_usage_monthly ALTER TABLE `biz_usage_monthly` - ADD COLUMN `api_call_count` INT NOT NULL DEFAULT 0 COMMENT '当月API转发总调用次数' AFTER `active_user_count`; + ADD COLUMN `api_call_count` INT NOT NULL DEFAULT 0 COMMENT '当月API转发总调用次数'; diff --git a/admin/src/views/subscription/usage.vue b/admin/src/views/subscription/usage.vue index 60aaf6d..ab6bda9 100644 --- a/admin/src/views/subscription/usage.vue +++ b/admin/src/views/subscription/usage.vue @@ -79,6 +79,7 @@ + @@ -122,6 +123,7 @@ export default { { title: 'friend', key: 'friend_count', minWidth: 72 }, { title: 'sns', key: 'sns_count', minWidth: 72 }, { title: 'active_user', key: 'active_user_count', minWidth: 100 }, + { title: 'api_calls', key: 'api_call_count', minWidth: 88 }, { title: '操作', key: 'a', @@ -178,6 +180,7 @@ export default { friend_count: 0, sns_count: 0, active_user_count: 0, + api_call_count: 0, } } this.modal = true diff --git a/api/model/biz_api_call_log.js b/api/model/biz_api_call_log.js index b7e2daa..c87a0e2 100644 --- a/api/model/biz_api_call_log.js +++ b/api/model/biz_api_call_log.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_api_call_log = db.define( "biz_api_call_log", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + user_id: { type: Sequelize.BIGINT.UNSIGNED, allowNull: false, diff --git a/api/model/biz_api_token.js b/api/model/biz_api_token.js index da42fc0..a6df43d 100644 --- a/api/model/biz_api_token.js +++ b/api/model/biz_api_token.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_api_token = db.define( "biz_api_token", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + user_id: { type: Sequelize.BIGINT.UNSIGNED, allowNull: false, diff --git a/api/model/biz_audit_log.js b/api/model/biz_audit_log.js index 29a67b6..02ee526 100644 --- a/api/model/biz_audit_log.js +++ b/api/model/biz_audit_log.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_audit_log = db.define( "biz_audit_log", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + admin_user_id: { type: Sequelize.BIGINT.UNSIGNED, allowNull: true, diff --git a/api/model/biz_plan.js b/api/model/biz_plan.js index 22ed382..ff8b958 100644 --- a/api/model/biz_plan.js +++ b/api/model/biz_plan.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_plan = db.define( "biz_plan", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + plan_code: { type: Sequelize.STRING(64), allowNull: false, @@ -64,6 +60,6 @@ module.exports = (db) => { comment: "套餐", } ); - // biz_plan.sync({ alter: true }); + // biz_plan.sync({ alter: true }); return biz_plan; }; diff --git a/api/model/biz_subscription.js b/api/model/biz_subscription.js index aa0920e..6c35a4c 100644 --- a/api/model/biz_subscription.js +++ b/api/model/biz_subscription.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_subscription = db.define( "biz_subscription", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + user_id: { type: Sequelize.BIGINT.UNSIGNED, allowNull: false, diff --git a/api/model/biz_usage_monthly.js b/api/model/biz_usage_monthly.js index 362e1e3..56b9a17 100644 --- a/api/model/biz_usage_monthly.js +++ b/api/model/biz_usage_monthly.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_usage_monthly = db.define( "biz_usage_monthly", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + user_id: { type: Sequelize.BIGINT.UNSIGNED, allowNull: false, diff --git a/api/model/biz_user.js b/api/model/biz_user.js index d85bec6..18fbcfb 100644 --- a/api/model/biz_user.js +++ b/api/model/biz_user.js @@ -4,11 +4,7 @@ module.exports = (db) => { const biz_user = db.define( "biz_user", { - id: { - type: Sequelize.BIGINT.UNSIGNED, - primaryKey: true, - autoIncrement: true, - }, + name: { type: Sequelize.STRING(100), allowNull: false, diff --git a/package.json b/package.json index 12ab027..d447c16 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,8 @@ "load": "node __tests__/loadtest-both.js", "api": " nodemon ./app.js ", "serve": "cd ./admin&&npm run dev -- --port 9001 ", - "build": "cd ./admin&&npm run build " + "build": "cd ./admin&&npm run build ", + "migrate:plan_api": "node scripts/migrate_biz_plan_api_columns.js" }, "license": "MIT" } diff --git a/scripts/migrate_biz_plan_api_columns.js b/scripts/migrate_biz_plan_api_columns.js new file mode 100644 index 0000000..826bb40 --- /dev/null +++ b/scripts/migrate_biz_plan_api_columns.js @@ -0,0 +1,73 @@ +/** + * 为 biz_plans / biz_usage_monthly 补齐套餐 API 权限相关字段(可重复执行) + */ +const mysql = require("mysql2/promise"); +const config = require("../config/config"); + +async function column_exists(conn, schema, table, column) { + const [rows] = await conn.query( + `SELECT COUNT(*) AS c FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND COLUMN_NAME = ?`, + [schema, table, column] + ); + return Number(rows[0].c) > 0; +} + +async function table_exists(conn, schema, table) { + const [rows] = await conn.query( + `SELECT COUNT(*) AS c FROM information_schema.TABLES + WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, + [schema, table] + ); + return Number(rows[0].c) > 0; +} + +async function main() { + const db = config.db; + if (!db || !db.database) { + throw new Error("config.db.database 未配置"); + } + const conn = await mysql.createConnection({ + host: db.host, + port: db.port || 3306, + user: db.username, + password: db.password, + database: db.database, + }); + const schema = db.database; + try { + if (!(await table_exists(conn, schema, "biz_plans"))) { + console.warn("跳过 biz_plans:当前库中不存在该表(请确认连接的是已部署订阅模块的库)"); + } else if (!(await column_exists(conn, schema, "biz_plans", "allowed_apis"))) { + await conn.query( + "ALTER TABLE `biz_plans` ADD COLUMN `allowed_apis` JSON DEFAULT NULL COMMENT '可访问的接口路径列表,null=不限制'" + ); + console.log("已添加 biz_plans.allowed_apis"); + } + if ( + (await table_exists(conn, schema, "biz_plans")) && + !(await column_exists(conn, schema, "biz_plans", "api_call_quota")) + ) { + await conn.query( + "ALTER TABLE `biz_plans` ADD COLUMN `api_call_quota` INT NOT NULL DEFAULT 0 COMMENT '每月API总调用次数上限,0=不限制'" + ); + console.log("已添加 biz_plans.api_call_quota"); + } + if (!(await table_exists(conn, schema, "biz_usage_monthly"))) { + console.warn("跳过 biz_usage_monthly:当前库中不存在该表"); + } else if (!(await column_exists(conn, schema, "biz_usage_monthly", "api_call_count"))) { + await conn.query( + "ALTER TABLE `biz_usage_monthly` ADD COLUMN `api_call_count` INT NOT NULL DEFAULT 0 COMMENT '当月API转发总调用次数'" + ); + console.log("已添加 biz_usage_monthly.api_call_count"); + } + console.log("字段检查完成"); + } finally { + await conn.end(); + } +} + +main().catch((e) => { + console.error(e); + process.exit(1); +});