buff_selection_step2_logic.md 12 KB

BUFF 选品第二步:利润判断与选中饰品落库

1. 目标与前置

  • 前置:第一步已得到「初始化要筛选的饰品 ID 集合」,并已做应用层乱序(见 buff_selection_filter_logic.md)。
  • 第二步:按乱序后的 ID 顺序,逐个判断每个饰品是否满足利润要求;满足则写入 buff_selection_request_item,并参与「每日选品条数」与「本次选品数量」限制,直到达到用户配置的选品数量或所有 ID 处理完毕。

2. 单饰品判断流程(概要)

对每个饰品 ID 依次执行:

  1. 取当前在售最低价格(视图一条即可)。
  2. 先做第二步兜底:再次校验 BUFF 价格区间(buffPriceMin/buffPriceMax),不满足直接不入选并记日志。
  3. 按 assistantLevel 做智能选品判断(low/standard/high)。
  4. 取该饰品的磨损区间列表(最小磨损值、最大磨损值、区间底价),按最小磨损值升序。
  5. 从前往后筛出正常磨损区间:随最小磨损值递增,区间底价必须单调不升;一旦某区间底价高于前一个,则该区间及之后全部舍弃。
  6. 用比较价 = 当前在售最低价格 × (1 + 用户利润率) 与上述正常区间的区间底价比较,只保留区间底价 > 比较价的区间;若存在至少一个满足的区间,则该饰品被选中。
  7. 被选中时:从视图取展示与链接字段,按规则算价格(人民币)、价格(美元)和区间,写入 buff_selection_request_item。
  8. 选品日志:每判断完一个饰品,向 buff_selection_request_log 写入一条记录,记录该饰品的判断结果、判断时间等,供前端展示「后台在逐个判断」的过程感(详见第 9 节)。

3. 单饰品判断(详细)

3.1 获取饰品最低价

SELECT DISTINCT `当前在售最低价格`
FROM buff_goods_filtered_view
WHERE `BUFF饰品ID` = :goods_id;

得到该饰品的当前在售最低价格(下称「最低价」)。

3.2 第二步兜底:BUFF 价格区间复核

  • 虽然第一步已按 buffPriceMin/buffPriceMax 过滤候选 ID,但第二步仍会在单饰品判断时再次校验当前在售最低价格:
    • 低于 buffPriceMin:直接判定不入选并记录原因。
    • 高于 buffPriceMax:直接判定不入选并记录原因。
  • 该复核用于防止候选集因脏数据或边界变化混入异常项。

3.3 智能选品助手判断(assistantLevel)

  • low:不做均价波动判断,直接进入后续计算。
  • standard:读取 7天在售最低价格平均价,并校验是否在以下区间内:
    • 上界:当前在售最低价格 * (1 + buff_ai_standard_range_max_increase_ratio)
    • 下界:当前在售最低价格 * (1 - buff_ai_standard_range_max_decrease_ratio)
  • high:读取 30天在售最低价格平均价,并校验是否在以下区间内:
    • 上界:当前在售最低价格 * (1 + buff_ai_high_range_max_increase_ratio)
    • 下界:当前在售最低价格 * (1 - buff_ai_high_range_max_decrease_ratio)
  • 若均价缺失或不在区间内,直接判定不入选并记录原因。

配置项来源:system_config,app_name = 'backend-selection'。

3.4 获取磨损区间并排序

SELECT `最小磨损值`, `最大磨损值`, `区间底价`
FROM buff_goods_filtered_view
WHERE `BUFF饰品ID` = :goods_id
ORDER BY `最小磨损值` ASC;

得到多行:每行一个磨损区间(最小磨损值、最大磨损值、区间底价),按最小磨损值升序。

3.5 正常磨损区间(区间底价单调不升)

  • 按最小磨损值升序依次看区间底价。
  • 要求:随最小磨损值增大,区间底价单调不升(可等于或下降)。
  • 从第一个区间开始,若某区间的区间底价高于前一个区间的区间底价,则该区间及其后所有区间视为「异常」,全部舍弃;只保留前面连续满足单调不升的那一段,称为正常磨损区间。

示例(最小磨损值升序):

区间 区间底价
0.00-0.01 215
0.01-0.02 210
0.02-0.03 178
0.03-0.04 200
0.04-0.05 130
  • 215 → 210 → 178 为降序,保留。
  • 0.03-0.04 的 200 > 178,违反单调不升,故 0.03-0.04 及 0.04-0.05 均舍弃。
  • 正常磨损区间仅为:0.00-0.01(215)、0.01-0.02(210)、0.02-0.03(178)。

3.6 利润比较与「满足要求的区间」

  • 比较价 = 最低价 × (1 + 用户设置的利润率)。
    例:最低价 175,利润率 10% → 比较价 = 175 × 1.1 = 192.5。
  • 用比较价与正常磨损区间的区间底价比较:只保留区间底价 > 比较价的区间;一旦某区间底价 ≤ 比较价,该区间及后续正常区间均不再保留(因为后面价格更低,也不满足「有利润」)。
  • 若最终至少剩一个区间,则该饰品被选中;否则不入选。

接上例(正常区间 215、210、178,比较价 192.5):

  • 0.00-0.01:215 > 192.5,保留。
  • 0.01-0.02:210 > 192.5,保留。
  • 0.02-0.03:178 < 192.5,不保留,且其后不再看。
  • 满足要求的区间:0.00-0.01、0.01-0.02。

4. 选中饰品的落库数据(buff_selection_request_item)

当某饰品被选中时,写入明细表的数据来源与计算方式如下。

字段说明 来源/计算方式
饰品 ID buff_goods_filtered_view.BUFF饰品ID
饰品名称 buff_goods_filtered_view.BUFF饰品名称
饰品图片 URL buff_goods_filtered_view.饰品图片URL地址
饰品 Steam 链接 buff_goods_filtered_view.饰品STEAM链接
价格(人民币) 比较价 × (1 + 扫货价格系数)。系数由智能扫货助手等级决定:低→buff_sweep_price_factor_min,标准→buff_sweep_price_factor_mid,高→buff_sweep_price_factor_max(来自 system_config)。
价格(美元) 先算 价格(人民币)/ Steam 卡价汇率,保留 2 位小数,再 +0.01。
区间 满足要求的区间:取这些区间的最小磨损值的最小值 到 最大磨损值的最大值。例:仅 0.00-0.01、0.01-0.02 满足 → 区间为「0.00-0.02」。
选品时间 写入时的服务器时间(即明细行的 created_at)。
  • 上述「比较价」即 最低价 × (1 + 用户利润率)。
  • Steam 卡价汇率来自用户选品配置(如 steamCardRatio)。

5. 智能扫货助手与扫货价格系数

  • 在「BUFF选品」界面增加选项智能扫货助手:低 / 标准 / 高,默认「低」;该选项需写入用户选品配置(buff_selection_config.config_json),例如字段名:assistantLevel 或 sweepAssistantLevel,值与第一步「智能选品助手」一致时可复用同一字段(low/standard/high)。
  • 扫货价格系数从 system_config 读取(app_name = 'backend-selection'):
选项 config_key 用途
低 buff_sweep_price_factor_min 价格(人民币)= 比较价 × (1 + 该值)
标准 buff_sweep_price_factor_mid 同上
高 buff_sweep_price_factor_max 同上

6. 选品结束条件与系统限制

6.1 本次选品何时结束

满足其一即结束本次选品请求:

  • 达到用户配置的选品数量:已入选的饰品条数 = 用户在界面上配置的「选品数量」;
  • 第一步的饰品 ID 全部处理完:尚未达到选品数量,但乱序后的 ID 列表已遍历完毕。

6.2 系统限制(system_config)

  • 每日选品次数:buff_selection_daily_times_limit_per_user(如 3),即每个用户每天最多发起 N 次选品(按请求单条数计)。
  • 每日选品条数:buff_selection_daily_items_limit_per_user(如 900),即每个用户每天累计入选的饰品条数上限(跨多次选品累计);超过后当日不再接受新选品或不再写入新明细,以产品规则为准。

选品逻辑需在创建/执行选品前校验上述两项,不满足则直接拒绝并提示。


7. 表结构说明

  • buff_selection_request:已具备 user_id、config_id、status、created_at/updated_at 等,满足需求,无需改动。config_id 关联本次使用的 buff_selection_config,可拿到选品数量、利润率、Steam 卡价、智能扫货助手等级等。
  • buff_selection_request_item:在原有 id、request_id、user_id、goods_id、created_at 基础上,通过迁移 20260228_buff_selection_request_item_columns.sql 增加:goods_name、icon_url、steam_link、price_cny、price_usd、wear_range,用于列表展示与扫货。
  • buff_selection_request_log:选品日志表,见第 9 节。

8. 第二步流程小结

  1. 输入:第一步得到的饰品 ID 列表(已乱序)、用户选品配置(含利润率、选品数量、Steam 卡价、智能扫货助手等级)、本请求单与用户当日已选次数/条数(用于校验限制)。
  2. 校验:当日选品次数、当日选品条数是否已达上限;若达上限则拒绝并提示。
  3. 按 ID 顺序逐个处理:
    • 取最低价,并做 BUFF 价格区间兜底复核;
    • 按 assistantLevel 做智能选品判断(7天/30天均价区间);
    • 取磨损区间(按最小磨损值升序);
    • 求正常磨损区间(区间底价单调不升);
    • 比较价 = 最低价 × (1 + 利润率);在正常区间中保留区间底价 > 比较价的区间;
    • 若存在满足要求的区间,则从视图取名称、图片、Steam 链接,算价格(人民币)、价格(美元)、区间,写入 buff_selection_request_item;
    • 无论是否入选,均向 buff_selection_request_log 写入一条日志(见第 9 节)。
  4. 当已入选数量 = 用户配置的选品数量,或所有 ID 已处理完,或执行中达到当日条数上限时,本单选品结束,更新请求单状态为 completed(或 failed/cancelled,若中途异常或用户停止)。

9. 选品日志(buff_selection_request_log)

9.1 用途

  • 记录第二步中对每个饰品的判断结果与判断时间,不追求精细,主要用于前端展示,让用户感知「后台在逐个判断饰品、满足则入选」。
  • 前端可按 request_id 分页或滚动拉取日志,按 sequence_no 或 created_at 排序展示。

9.2 表结构(迁移 20260228_buff_selection_request_log.sql)

字段 类型 说明
id bigint, PK 主键
request_id bigint, NOT NULL 选品请求单 ID
user_id int, NOT NULL 用户 ID,按用户隔离
goods_id varchar(64), NOT NULL BUFF 饰品 ID
goods_name varchar(256), NULL 饰品名称,便于日志展示
sequence_no int, NOT NULL 判断序号:本次选品中第几个被判断(从 1 递增)
result varchar(20), NOT NULL 判断结果:selected-已入选,not_selected-未入选
message varchar(256), NULL 简短说明,如「无满足利润的磨损区间」「已入选」等,可为空
created_at datetime 判断时间

索引:request_id、idx_request_sequence、idx_request_created,便于按请求单查日志并排序。

9.3 写入时机与内容

  • 时机:每判断完一个饰品(无论是否入选)后,立即插入一条日志。
  • 内容建议:
    • result = 'selected':该饰品已入选并写入 buff_selection_request_item;message 可填「已入选」或为空。
    • result = 'not_selected':未入选;message 可填简短原因,如「当前在售最低价低于设置下限」「7天均价不在智能选品标准范围」「无满足利润的磨损区间」等。
  • goods_name 可从 buff_goods_filtered_view 取当前名称,便于前端展示;可为空。
  • sequence_no 为本次选品中该饰品的判断顺序号(从 1 递增),便于前端展示「第 N 个判断」。