-- ============================================================
-- 视图：viw_kg_edge_flow —— ERP「业务单据流转」知识图谱·流转边 (L2, ⭐最高价值)
-- 一条边 = 源单据 --生成--> 目标单据 (报价→订单→工单→领料→入库→送货→对账→发票→收款)
--
-- 边的来源：低代码平台把「生成下游单据」的按钮存成从表控件
--   gdsconfigformslave.sControlName LIKE 'BtnCopyTo.<目标动作>'
--   例：BtnCopyTo.ActDeliverGoods (中文=生成送货单)
--
-- 目标表单如何解析（与存储过程 Sp_Ai_AddCommonAfterNew 完全一致）：
--   该过程按 (源菜单 + 按钮中文名) 定位到这条 BtnCopyTo 从表控件，
--   直接取其 sActiveId 作为「目标菜单窗体 id」(= gdsmodule.sId)。
--   即：sControlName 里的 .ActXxx 只是标签，真正的目标存在 sActiveId。
--   过程随后 SELECT sChinese FROM gdsmodule WHERE sId = sActiveId 取目标名，
--   并 SELECT sTbName FROM gdsconfigformmaster WHERE sParentId=sActiveId AND bGrd=0 取目标表。
--   本视图照搬这套解析。
--
-- 只取「真正的边」，剔除配置噪声：
--   保留 BtnCopyTo.<Action>（携带 sActiveId 的主按钮）
--   剔除 .slave / .Detail（从表映射伴生行，无 sActiveId）、裸 BtnCopyTo（按钮容器）
--   剔除 sActiveId 指向本库不存在的菜单（跨租户/已删，约 8 行）
--
-- 节点粒度 = 菜单窗体 gdsmodule.sId（= 接口 sModelsId，也是 BtnCopyTo 的目标粒度）。
-- 端点富化的数据源 = 该菜单下 bGrd=0 的主表单 sTbName（与过程取表逻辑一致）。
--
-- 校验（本地库 xlyweberp_saas）：411 条边 / 405 对 (源,目标) / 51 条自环(补单·追加同单)
--   端点 401/405 命中 viw_ai_useful_forms（业务表单目录高度对齐）。
-- ============================================================
CREATE OR REPLACE VIEW viw_kg_edge_flow AS
SELECT
    CONCAT(e.src_id, '>', e.tgt_id, '>', e.action_code) AS sEdgeKey,      -- 稳定边键(源>目标>动作)
    e.src_id                     AS sSrcModuleId,   -- 源菜单窗体id (= 接口 sModelsId)
    src.sChinese                 AS sSrcName,        -- 源单据名称
    src.sModelType               AS sSrcModelType,   -- 源前端路由/业务域
    (SELECT f.sTbName FROM gdsconfigformmaster f
       WHERE f.sParentId = e.src_id AND f.bGrd = 0 AND IFNULL(f.sTbName,'') <> ''
       ORDER BY f.iOrder, f.iIncrement LIMIT 1)      AS sSrcDataSource,   -- 源主数据源(表/视图)
    e.btn                        AS sBtnLabel,       -- 业务动作(按钮中文名, 如 生成送货单)
    e.action_code                AS sActionCode,     -- 目标动作码(如 ActDeliverGoods)
    e.tgt_id                     AS sTgtModuleId,    -- 目标菜单窗体id (= sActiveId)
    tgt.sChinese                 AS sTgtName,        -- 目标单据名称
    tgt.sModelType               AS sTgtModelType,   -- 目标前端路由/业务域
    (SELECT f.sTbName FROM gdsconfigformmaster f
       WHERE f.sParentId = e.tgt_id AND f.bGrd = 0 AND IFNULL(f.sTbName,'') <> ''
       ORDER BY f.iOrder, f.iIncrement LIMIT 1)      AS sTgtDataSource,   -- 目标主数据源(表/视图)
    CAST(e.src_id = e.tgt_id AS UNSIGNED)            AS bSelfLoop,        -- 1=自环(补单/追加同单)
    CAST(EXISTS(SELECT 1 FROM viw_ai_useful_forms u WHERE u.sModuleId = e.src_id) AS UNSIGNED) AS bSrcUseful, -- 源命中业务表单目录
    CAST(EXISTS(SELECT 1 FROM viw_ai_useful_forms u WHERE u.sModuleId = e.tgt_id) AS UNSIGNED) AS bTgtUseful  -- 目标命中业务表单目录
FROM (
    SELECT DISTINCT
        m.sParentId                            AS src_id,      -- 主表单所属菜单 = 源
        s.sActiveId                            AS tgt_id,      -- BtnCopyTo 目标菜单
        s.sChinese                             AS btn,
        SUBSTRING_INDEX(s.sControlName, '.', -1) AS action_code
    FROM gdsconfigformslave s
    JOIN gdsconfigformmaster m ON s.sParentId = m.sId
    JOIN gdsmodule tgt0        ON s.sActiveId = tgt0.sId       -- 目标菜单须真实存在
    WHERE s.sControlName LIKE 'BtnCopyTo.%'
      AND s.sControlName NOT LIKE '%.slave'
      AND s.sControlName NOT LIKE '%.Detail'
      AND IFNULL(s.sActiveId, '') <> ''
) e
JOIN gdsmodule src ON e.src_id = src.sId                       -- 源菜单须真实存在
JOIN gdsmodule tgt ON e.tgt_id = tgt.sId;
