<template>
  <div class="budget-source-field">
    <!-- 提交用隐藏字段 -->
    <input :name="fieldName" type="hidden" :value="normalizedValue" />

    <!-- 当前展示文本（有值时展示） -->
    <span v-if="hasValue && displayText" class="budget-source-label" :title="displayText">
      {{ displayText }}
    </span>
    <span
      v-else-if="hasValue && budgetDataId"
      class="budget-source-label budget-source-label--muted"
      :title="`预算ID: ${budgetDataId}`"
    >
      预算ID: {{ budgetDataId }}
    </span>
    <span
      v-else-if="hasValue"
      class="budget-source-label budget-source-label--muted"
      :title="normalizedValue"
    >
      {{ normalizedValue }}
    </span>

    <el-button type="primary" size="small" @click="openDialog">选取</el-button>
    <el-button v-if="hasValue" size="small" @click="clearValue">清除</el-button>

    <el-dialog
      title="选择预算来源"
      :visible.sync="dialogVisible"
      width="1300px"
      :close-on-click-modal="false"
      append-to-body
      @open="onDialogOpen"
      @close="onDialogClose"
    >
      <div style="margin-bottom: 12px">
        <el-select
          v-model="yearId"
          placeholder="请选择年份"
          filterable
          style="width: 100%"
          :loading="yearLoading"
          @change="onYearChange"
        >
          <el-option
            v-for="y in yearOptions"
            :key="String(y.value)"
            :label="y.label"
            :value="y.value"
          />
        </el-select>
      </div>

      <div style="display: flex; gap: 20px">
        <!-- 左侧：预算树 -->
        <div v-loading="treeLoading" style="flex: 1; max-width: 780px; max-height: 500px; overflow: auto; min-width: 0">
        <div v-if="departmentTree.length" class="tree-block">
          <div class="tree-title">部门预算</div>
          <el-tree
            ref="departmentTreeRef"
            :data="departmentTree"
            node-key="id"
            :props="treeProps"
            highlight-current
            default-expand-all
            :expand-on-click-node="false"
            show-checkbox
            check-strictly
            :check-on-click-node="false"
            @check-change="onTreeCheckChange"
            @node-click="onNodeClickToggle"
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span class="node-label" :class="{ 'node-label--clickable': data.is_leaf }" @click.stop="onLabelClick(data, node, $refs.departmentTreeRef)">{{ node.label }}</span>
              <span v-if="data.is_leaf" class="node-usage-info">
                <span class="usage-item">
                  <span class="usage-label">预算:</span>
                  <span class="usage-value">{{ formatAmount(data.budget_amount) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">已用:</span>
                  <span class="usage-value usage-value--used">{{ formatAmount(data.used_amount || 0) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">执行率:</span>
                  <span
                    class="usage-value usage-value--rate"
                    :class="getExecutionRateClass(data.execution_rate || 0)"
                  >
                    {{ formatExecutionRate(data.execution_rate || 0) }}
                  </span>
                </span>
              </span>
            </span>
          </el-tree>
        </div>

        <div v-if="projectTree.length" class="tree-block" style="margin-top: 16px">
          <div class="tree-title">自有账户</div>
          <el-tree
            ref="projectTreeRef"
            :data="projectTree"
            node-key="id"
            :props="treeProps"
            highlight-current
            default-expand-all
            :expand-on-click-node="false"
            show-checkbox
            check-strictly
            :check-on-click-node="false"
            @check-change="onTreeCheckChange"
            @node-click="onNodeClickToggle"
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span class="node-label" :class="{ 'node-label--clickable': data.is_leaf }" @click.stop="onLabelClick(data, node, $refs.projectTreeRef)">{{ node.label }}</span>
              <span v-if="data.is_leaf" class="node-usage-info">
                <span class="usage-item">
                  <span class="usage-label">预算:</span>
                  <span class="usage-value">{{ formatAmount(data.budget_amount) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">已用:</span>
                  <span class="usage-value usage-value--used">{{ formatAmount(data.used_amount || 0) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">执行率:</span>
                  <span
                    class="usage-value usage-value--rate"
                    :class="getExecutionRateClass(data.execution_rate || 0)"
                  >
                    {{ formatExecutionRate(data.execution_rate || 0) }}
                  </span>
                </span>
              </span>
            </span>
          </el-tree>
        </div>

        <div v-if="specialFundTree.length" class="tree-block" style="margin-top: 16px">
          <div class="tree-title">专项资金</div>
          <el-tree
            ref="specialFundTreeRef"
            :data="specialFundTree"
            node-key="id"
            :props="treeProps"
            highlight-current
            default-expand-all
            :expand-on-click-node="false"
            show-checkbox
            check-strictly
            :check-on-click-node="false"
            @check-change="onTreeCheckChange"
            @node-click="onNodeClickToggle"
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span class="node-label" :class="{ 'node-label--clickable': data.is_leaf }" @click.stop="onLabelClick(data, node, $refs.specialFundTreeRef)">{{ node.label }}</span>
              <span v-if="data.is_leaf" class="node-usage-info">
                <span class="usage-item">
                  <span class="usage-label">预算:</span>
                  <span class="usage-value">{{ formatAmount(data.budget_amount) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">已用:</span>
                  <span class="usage-value usage-value--used">{{ formatAmount(data.used_amount || 0) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">执行率:</span>
                  <span
                    class="usage-value usage-value--rate"
                    :class="getExecutionRateClass(data.execution_rate || 0)"
                  >
                    {{ formatExecutionRate(data.execution_rate || 0) }}
                  </span>
                </span>
              </span>
            </span>
          </el-tree>
        </div>

        <div v-if="lastYearCarryoverTree.length" class="tree-block" style="margin-top: 16px">
          <div class="tree-title">上一年结转资金</div>
          <el-tree
            ref="lastYearCarryoverTreeRef"
            :data="lastYearCarryoverTree"
            node-key="id"
            :props="treeProps"
            highlight-current
            default-expand-all
            :expand-on-click-node="false"
            show-checkbox
            check-strictly
            :check-on-click-node="false"
            @check-change="onTreeCheckChange"
            @node-click="onNodeClickToggle"
          >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span class="node-label" :class="{ 'node-label--clickable': data.is_leaf }" @click.stop="onLabelClick(data, node, $refs.lastYearCarryoverTreeRef)">{{ node.label }}</span>
              <span v-if="data.is_leaf" class="node-usage-info">
                <span class="usage-item">
                  <span class="usage-label">预算:</span>
                  <span class="usage-value">{{ formatAmount(data.budget_amount) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">已用:</span>
                  <span class="usage-value usage-value--used">{{ formatAmount(data.used_amount || 0) }}</span>
                </span>
                <span class="usage-item">
                  <span class="usage-label">执行率:</span>
                  <span
                    class="usage-value usage-value--rate"
                    :class="getExecutionRateClass(data.execution_rate || 0)"
                  >
                    {{ formatExecutionRate(data.execution_rate || 0) }}
                  </span>
                </span>
              </span>
            </span>
          </el-tree>
        </div>

        <div
          v-if="!treeLoading && departmentTree.length === 0 && projectTree.length === 0 && specialFundTree.length === 0 && lastYearCarryoverTree.length === 0"
          style="text-align: center; color: #909399; padding: 32px 0"
        >
          暂无数据
        </div>
        </div>

        <!-- 右侧：部门金额分配（始终展示，支持单预算/多部门与多预算） -->
        <div style="flex: 0 0 480px; border-left: 1px solid #e4e7ed; padding-left: 20px">
          <div style="margin-bottom: 16px; font-weight: 600; color: #303133; font-size: 16px">
            部门金额分配
          </div>
          <div style="margin-bottom: 16px; color: #303133; font-size: 14px; line-height: 1.6">
            请选择预算来源（可多选），并将本次付款金额分配到对应部门与预算（分配金额可以为0，但分配总额必须匹配本次付款金额）。
          </div>
          <el-table :data="pendingAllocations" border style="width: 100%">
            <el-table-column prop="budget_name" label="预算" min-width="180"></el-table-column>
            <el-table-column prop="department_name" label="部门" width="180"></el-table-column>
            <el-table-column label="分配金额" width="200">
              <template slot-scope="scope">
                <el-input-number
                  v-model="scope.row.allocated_amount"
                  :min="0"
                  :precision="2"
                  :controls="false"
                  style="width: 100%"
                  @change="onAllocationChange"
                ></el-input-number>
              </template>
            </el-table-column>
          </el-table>
          <div style="margin-top: 16px; padding: 16px; background-color: #f5f7fa; border-radius: 6px">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px">
              <span style="font-size: 14px; color: #303133; font-weight: 500">已分配总额：</span>
              <span :style="{ color: allocationTotal === totalAmount ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '16px' }">
                {{ formatAmount(allocationTotal) }}
              </span>
            </div>
            <div v-if="totalAmount > 0" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px">
              <span style="font-size: 14px; color: #303133; font-weight: 500">本次付款金额：</span>
              <span style="font-weight: 600; font-size: 16px; color: #303133">{{ formatAmount(totalAmount) }}</span>
            </div>
            <div v-if="totalAmount > 0" style="display: flex; justify-content: space-between; align-items: center">
              <span style="font-size: 14px; color: #303133; font-weight: 500">剩余金额：</span>
              <span :style="{ color: remainingAmount >= 0 ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '16px' }">
                {{ formatAmount(remainingAmount) }}
              </span>
            </div>
            <div v-if="totalAmount === 0" style="margin-top: 12px; color: #606266; font-size: 13px; line-height: 1.6">
              提示：未识别到"本次付款金额"，当前按 0 校验；若需要校验，请确保流程表单存在该字段。
            </div>
          </div>
        </div>
      </div>

      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button 
          type="primary" 
          :disabled="!canConfirm"
          @click="confirmPick"
        >
          确定
        </el-button>
      </template>
    </el-dialog>

  </div>
</template>

<script>
import request from "@/utils/request";
import { getBudgetYearOptions, getBudgetDataTree } from "@/api/flow";

export default {
  name: "BudgetSourcePickerField",
  props: {
    fieldName: { type: String, required: true },
    value: { type: [String, Number, Object, Array], default: "" },
    display: { type: String, default: "" },
  },
  data() {
    return {
      dialogVisible: false,
      yearLoading: false,
      treeLoading: false,
      yearOptions: [],
      yearId: null,
      treeData: [],
      // 选择相关（支持多选）
      selectedBudgetIds: [],
      lastValidBudgetIds: [],
      selectionError: "",
      // 授权缓存：budget_data_id -> authorizations[]
      authCache: {},
      // 分配相关（右侧始终展示）
      pendingAllocations: [],
      // “本次付款金额（元）”——从流程自定义模型字段中按 label 模糊匹配“本次付款金额”解析
      totalAmount: 0,
      // 生成的显示文本（用于展示区）
      generatedDisplayText: "",
    };
  },
  computed: {
    // 解析JSON格式的value，兼容旧格式
    parsedValue() {
      const value = this.value;
      if (!value || value === null || value === undefined) {
        return { budget_data_id: null, allocations: null, budget_items: null };
      }

      // 已经是对象（推荐的新格式：直接对象落库/回传）
      if (typeof value === "object" && !Array.isArray(value)) {
        return {
          budget_data_id: value?.budget_data_id ?? null,
          allocations: value?.allocations ?? null,
          budget_items: value?.budget_items ?? null,
        };
      }

      // 兼容：如果是数组（极端旧数据/异常数据），当作 allocations
      if (Array.isArray(value)) {
        return { budget_data_id: null, allocations: value, budget_items: null };
      }

      // 字符串：可能是
      // 1) 旧格式： "123"
      // 2) 新格式： '{"budget_data_id":"2","allocations":[...]}'
      // 3) 双重编码： '"{\"budget_data_id\":\"2\",\"allocations\":[...]}"'
      if (typeof value === "string") {
        const raw = value.trim();
        if (!raw) return { budget_data_id: null, allocations: null, budget_items: null };

        const parseMaybeJson = (s) => {
          try {
            return { ok: true, data: JSON.parse(s) };
          } catch (e) {
            return { ok: false, data: null };
          }
        };

        const p1 = parseMaybeJson(raw);
        if (p1.ok) {
          // 解析结果是对象：标准新格式
          if (p1.data && typeof p1.data === "object" && !Array.isArray(p1.data)) {
            return {
              budget_data_id: p1.data?.budget_data_id ?? null,
              allocations: p1.data?.allocations ?? null,
              budget_items: p1.data?.budget_items ?? null,
            };
          }
          // 解析结果是数组：当作 allocations（仍可能缺 budget_data_id）
          if (Array.isArray(p1.data)) {
            return { budget_data_id: null, allocations: p1.data, budget_items: null };
          }
          // 解析结果是字符串：双重编码常见形态
          if (typeof p1.data === "string") {
            const inner = p1.data.trim();
            // inner 可能是 '{...}' 或者 '2'
            const p2 = parseMaybeJson(inner);
            if (p2.ok && p2.data && typeof p2.data === "object" && !Array.isArray(p2.data)) {
              return {
                budget_data_id: p2.data?.budget_data_id ?? null,
                allocations: p2.data?.allocations ?? null,
                budget_items: p2.data?.budget_items ?? null,
              };
            }
            if (p2.ok && Array.isArray(p2.data)) {
              return { budget_data_id: null, allocations: p2.data, budget_items: null };
            }
            // inner 可能是数字字符串
            return {
              budget_data_id: isNaN(inner) ? null : String(inner),
              allocations: null,
              budget_items: null,
            };
          }
        }

        // 非JSON：当作旧格式 ID
        return { budget_data_id: isNaN(raw) ? null : String(raw), allocations: null, budget_items: null };
      }

      return { budget_data_id: null, allocations: null, budget_items: null };
    },
    budgetDataId() {
      return this.parsedValue.budget_data_id;
    },
    allocations() {
      return this.parsedValue.allocations;
    },
    budgetItems() {
      const items = this.parsedValue.budget_items;
      return Array.isArray(items) ? items : [];
    },
    normalizedValue() {
      // 返回JSON格式的字符串（用于表单提交/兜底）
      if (this.budgetItems.length > 0) {
        return JSON.stringify({ budget_items: this.budgetItems });
      }
      if (!this.budgetDataId) return "";
      return JSON.stringify({
        budget_data_id: this.budgetDataId,
        allocations: this.allocations,
      });
    },
    hasValue() {
      return (this.budgetDataId !== null && this.budgetDataId !== "") || this.budgetItems.length > 0;
    },
    displayText() {
      // 优先使用后端返回的 `{字段名}_display`
      if (this.display && this.display.trim()) {
        return this.display;
      }
      
      // 使用生成的显示文本
      if (this.generatedDisplayText && this.generatedDisplayText.trim()) {
        return this.generatedDisplayText;
      }
      
      // 如果都没有，返回空字符串（避免显示JSON或ID）
      return "";
    },
    treeProps() {
      return {
        children: "children",
        label: "name",
        disabled: (data) => !data?.is_leaf,
      };
    },
    departmentTree() {
      return (this.treeData || []).filter((n) => n?.budget_type === "department");
    },
    projectTree() {
      return (this.treeData || []).filter((n) => n?.budget_type === "project");
    },
    specialFundTree() {
      return (this.treeData || []).filter((n) => n?.budget_type === "special_fund");
    },
    lastYearCarryoverTree() {
      return (this.treeData || []).filter((n) => n?.budget_type === "last_year_carryover");
    },
    budgetTypeMap() {
      return {
        department: "部门预算",
        project: "自有账户",
        special_fund: "专项资金",
        last_year_carryover: "上一年结转资金",
      };
    },
    // 分配总额
    allocationTotal() {
      return (this.pendingAllocations || []).reduce((sum, item) => {
        return sum + (parseFloat(item.allocated_amount) || 0);
      }, 0);
    },
    // 剩余金额
    remainingAmount() {
      return this.totalAmount - this.allocationTotal;
    },
    canConfirm() {
      // 必须已选择至少一个预算来源，且分配总额必须等于本次付款金额（未识别时 totalAmount=0，则要求分配总额也为0）
      if (!this.selectedBudgetIds || this.selectedBudgetIds.length === 0) return false;
      if (this.selectionError) return false;
      return Number(this.allocationTotal) === Number(this.totalAmount);
    },
  },
  methods: {
    openDialog() {
      this.dialogVisible = true;
    },
    onDialogOpen() {
      this.selectionError = "";
      this.selectedBudgetIds = [];
      // 读取“本次付款金额”（延迟查找，确保 DOM 已渲染）
      this.$nextTick(() => {
        // 第一次尝试
        this.totalAmount = this.extractPaymentAmountFromForm();
        // 如果没找到，再延迟一次尝试（可能 DOM 还在渲染中）
        if (this.totalAmount === 0) {
          setTimeout(() => {
            this.totalAmount = this.extractPaymentAmountFromForm();
          }, 100);
        }
      });
      this.ensureInit();
    },
    onDialogClose() {
      this.selectionError = "";
    },
    async ensureInit() {
      if (!this.yearOptions || this.yearOptions.length === 0) {
        await this.loadYearOptions();
      }

      if (!this.yearId && this.yearOptions.length > 0) {
        // 尝试根据当前 value 反查 year_id（可选），否则默认第一项
        const fromValue = await this.tryResolveYearIdByValue();
        this.yearId = fromValue || this.yearOptions[0].value;
      }

      if (this.yearId) {
        await this.loadTree(this.yearId);
      }
    },
    async loadYearOptions() {
      this.yearLoading = true;
      try {
        const res = await getBudgetYearOptions(false);
        const arr = Array.isArray(res) ? res : [];
        this.yearOptions = arr.map((y) => ({
          value: y.value,
          label: y.label || (y.year ? `${y.year}年` : `${y.value}年`),
          year: y.year,
        }));
      } finally {
        this.yearLoading = false;
      }
    },
    async tryResolveYearIdByValue() {
      if (!this.hasValue) return null;
      const idFromValue = this.budgetDataId || (this.budgetItems[0] && this.budgetItems[0].budget_data_id);
      if (!idFromValue) return null;
      try {
        const detail = await request({
          method: "get",
          url: `/api/budget/budget-data/${idFromValue}`,
          isLoading: false,
        });
        const yearId = detail?.year_id ?? null;
        return yearId;
      } catch (e) {
        return null;
      }
    },
    async getDepartmentAuthorizations(budgetDataId) {
      const key = String(budgetDataId || "");
      if (!key) return [];
      if (this.authCache[key]) return this.authCache[key];
      try {
        const res = await request({
          method: "get",
          url: `/api/budget/budget-data/${budgetDataId}/department-authorizations`,
          isLoading: false,
        });
        const list = Array.isArray(res) ? res : [];
        this.$set(this.authCache, key, list);
        return list;
      } catch (e) {
        this.$set(this.authCache, key, []);
        return [];
      }
    },
    async loadTree(yearId) {
      if (!yearId) return;
      this.treeLoading = true;
      try {
        const res = await getBudgetDataTree({ year_id: yearId }, false);
        this.treeData = Array.isArray(res) ? res : [];
        // 回显已有选择
        this.$nextTick(async () => {
          await this.restoreSelectionFromValue();
          await this.rebuildAllocationsFromCurrentSelection();
          // 树数据加载完成后，重新生成显示文本
          if (this.hasValue && !this.display) {
            await this.generateDisplayText();
          }
        });
      } finally {
        this.treeLoading = false;
      }
    },
    async onYearChange(val) {
      this.selectionError = "";
      this.selectedBudgetIds = [];
      this.pendingAllocations = [];
      this.treeData = [];
      await this.loadTree(val);
    },
    onNodeClickToggle(data, node, tree) {
      if (!data || !data.is_leaf) return;
      // 点击节点也切换勾选
      if (tree && typeof tree.setChecked === "function") {
        tree.setChecked(data.id, !node.checked, true);
      }
    },
    onLabelClick(data, node, tree) {
      // 点击节点名称文字时切换勾选（仅叶子节点）
      if (!data || !data.is_leaf) return;
      if (tree && typeof tree.setChecked === "function") {
        const isChecked = tree.getCheckedKeys().includes(data.id);
        tree.setChecked(data.id, !isChecked, true);
      }
    },
    onTreeCheckChange() {
      // 任意树勾选变化后统一重算
      this.rebuildAllocationsFromCurrentSelection();
    },
    collectCheckedLeafNodes() {
      const refs = [
        this.$refs.departmentTreeRef,
        this.$refs.projectTreeRef,
        this.$refs.specialFundTreeRef,
        this.$refs.lastYearCarryoverTreeRef,
      ].filter(Boolean);
      const nodes = [];
      refs.forEach((tree) => {
        if (typeof tree.getCheckedNodes === "function") {
          const checked = tree.getCheckedNodes(true, false) || [];
          checked.forEach((n) => {
            if (n && n.is_leaf) nodes.push(n);
          });
        }
      });
      // 去重
      const map = {};
      nodes.forEach((n) => (map[String(n.id)] = n));
      return Object.values(map);
    },
    setCheckedIds(ids) {
      const list = (ids || []).map((x) => String(x));
      const refs = [
        this.$refs.departmentTreeRef,
        this.$refs.projectTreeRef,
        this.$refs.specialFundTreeRef,
        this.$refs.lastYearCarryoverTreeRef,
      ].filter(Boolean);
      refs.forEach((tree) => {
        if (typeof tree.setCheckedKeys === "function") {
          tree.setCheckedKeys(list);
        }
      });
    },
    async restoreSelectionFromValue() {
      // 按 value 回显勾选
      let ids = [];
      if (this.budgetItems.length > 0) {
        ids = this.budgetItems.map((x) => String(x.budget_data_id)).filter(Boolean);
      } else if (this.budgetDataId) {
        ids = [String(this.budgetDataId)];
      }
      this.lastValidBudgetIds = ids;
      this.selectedBudgetIds = ids;
      this.setCheckedIds(ids);
    },
    extractPaymentAmountFromForm() {
      // 从页面 DOM 中模糊匹配 label “本次付款金额”，解析金额（兼容单位后缀）
      // 支持多种查找方式：label、placeholder、字段名等
      try {
        // 方法1：通过 label 查找
        const labels = Array.from(document.querySelectorAll(".el-form-item__label"));
        let labelEl = labels.find((el) => {
          const text = (el.innerText || el.textContent || "").trim();
          return text.includes("本次付款金额") || text.includes("付款金额");
        });
        
        if (labelEl) {
          const formItem = labelEl.closest(".el-form-item");
          if (formItem) {
            const content = formItem.querySelector(".el-form-item__content");
            if (content) {
              // 优先查找各种类型的输入框（可编辑状态）
              let input = content.querySelector("input") ||
                         content.querySelector("textarea") ||
                         content.querySelector(".el-input__inner") ||
                         content.querySelector("input[type='text']") ||
                         content.querySelector("input[type='number']");
              
              if (input) {
                const raw = String(input.value || input.getAttribute("value") || "");
                const num = parseFloat(raw.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                if (!isNaN(num) && num > 0) {
                  return num;
                }
              }
              
              // 如果没找到输入框，查找展示元素（只读/view 状态）
              // 只读字段通常渲染为 span 或其他展示元素
              const displayEl = content.querySelector("span") ||
                               content.querySelector("div") ||
                               content;
              
              if (displayEl) {
                // 获取元素的文本内容（可能是直接文本或子元素的文本）
                const raw = displayEl.innerText || displayEl.textContent || displayEl.getAttribute("value") || "";
                const num = parseFloat(raw.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                if (!isNaN(num) && num > 0) {
                  return num;
                }
              }
            }
          }
        }

        // 方法2：通过 data-field-name 属性查找（如果字段名包含"付款金额"相关关键词）
        const formItems = Array.from(document.querySelectorAll(".el-form-item[data-field-name]"));
        for (const formItem of formItems) {
          const fieldName = formItem.getAttribute("data-field-name") || "";
          const label = formItem.querySelector(".el-form-item__label");
          const labelText = label ? (label.innerText || label.textContent || "").trim() : "";
          
          if (fieldName.includes("付款金额") || fieldName.includes("payment_amount") || 
              labelText.includes("本次付款金额") || labelText.includes("付款金额")) {
            const content = formItem.querySelector(".el-form-item__content");
            if (content) {
              // 优先查找输入框（可编辑状态）
              let input = content.querySelector("input") ||
                         content.querySelector("textarea") ||
                         content.querySelector(".el-input__inner") ||
                         content.querySelector("input[type='text']") ||
                         content.querySelector("input[type='number']");
              
              if (input) {
                const raw = String(input.value || input.getAttribute("value") || "");
                const num = parseFloat(raw.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                if (!isNaN(num) && num > 0) {
                  return num;
                }
              }
              
              // 如果没找到输入框，查找展示元素（只读/view 状态）
              const displayEl = content.querySelector("span") ||
                               content.querySelector("div") ||
                               content;
              
              if (displayEl) {
                const raw = displayEl.innerText || displayEl.textContent || displayEl.getAttribute("value") || "";
                const num = parseFloat(raw.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                if (!isNaN(num) && num > 0) {
                  return num;
                }
              }
            }
          }
        }

        // 方法3：通过 placeholder 查找（可编辑字段）
        const inputs = Array.from(document.querySelectorAll("input, textarea, .el-input__inner"));
        for (const input of inputs) {
          const placeholder = input.getAttribute("placeholder") || "";
          if (placeholder.includes("本次付款金额") || placeholder.includes("付款金额")) {
            const raw = String(input.value || input.getAttribute("value") || "");
            const num = parseFloat(raw.replace(/,/g, "").replace(/[^\d.-]/g, ""));
            if (!isNaN(num) && num > 0) {
              return num;
            }
          }
        }

        // 方法4：直接查找所有包含金额数字的 span/div（只读展示字段）
        // 查找所有 form-item，检查 label 是否包含"付款金额"，然后提取内容
        const allFormItems = Array.from(document.querySelectorAll(".el-form-item"));
        for (const formItem of allFormItems) {
          const label = formItem.querySelector(".el-form-item__label");
          const labelText = label ? (label.innerText || label.textContent || "").trim() : "";
          
          if (labelText.includes("本次付款金额") || labelText.includes("付款金额")) {
            const content = formItem.querySelector(".el-form-item__content");
            if (content) {
              // 查找所有可能的展示元素
              const displayEls = content.querySelectorAll("span, div, p");
              for (const el of displayEls) {
                const text = (el.innerText || el.textContent || "").trim();
                // 如果文本包含数字（可能是金额）
                if (text && /[\d.,]+/.test(text)) {
                  const num = parseFloat(text.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                  if (!isNaN(num) && num > 0) {
                    return num;
                  }
                }
              }
              // 如果子元素没找到，直接取 content 的文本
              const contentText = (content.innerText || content.textContent || "").trim();
              if (contentText && /[\d.,]+/.test(contentText)) {
                const num = parseFloat(contentText.replace(/,/g, "").replace(/[^\d.-]/g, ""));
                if (!isNaN(num) && num > 0) {
                  return num;
                }
              }
            }
          }
        }

        return 0;
      } catch (e) {
        console.warn("[BudgetSourcePickerField] 提取本次付款金额失败:", e);
        return 0;
      }
    },
    getExistingAllocationMap() {
      // 兼容旧/新结构：返回 { `${budgetId}:${deptId}`: amount }
      const map = {};
      // 新：budget_items
      if (this.budgetItems.length > 0) {
        this.budgetItems.forEach((item) => {
          const bid = String(item.budget_data_id || "");
          const allocs = Array.isArray(item.allocations) ? item.allocations : [];
          allocs.forEach((a) => {
            const did = String(a.department_id || "");
            if (!bid || !did) return;
            map[`${bid}:${did}`] = parseFloat(a.allocated_amount) || 0;
          });
        });
      } else if (this.budgetDataId && Array.isArray(this.allocations)) {
        const bid = String(this.budgetDataId);
        this.allocations.forEach((a) => {
          const did = String(a.department_id || "");
          if (!did) return;
          map[`${bid}:${did}`] = parseFloat(a.allocated_amount) || 0;
        });
      }
      return map;
    },
    async rebuildAllocationsFromCurrentSelection() {
      this.selectionError = "";
      const selectedNodes = this.collectCheckedLeafNodes();
      const ids = selectedNodes.map((n) => String(n.id));
      this.selectedBudgetIds = ids;
      if (ids.length === 0) {
        this.pendingAllocations = [];
        return;
      }

      // 重新读取“本次付款金额”
      this.totalAmount = this.extractPaymentAmountFromForm();

      const existingMap = this.getExistingAllocationMap();

      // 单条预算来源
      if (selectedNodes.length === 1) {
        const node = selectedNodes[0];
        const auths = await this.getDepartmentAuthorizations(node.id);
        if (!auths || auths.length === 0) {
          this.selectionError = "该预算来源未配置部门授权";
          this.$message.warning(this.selectionError);
          this.setCheckedIds(this.lastValidBudgetIds);
          return;
        }

        if (auths.length === 1) {
          // 情形(1)：单预算 + 单部门 -> 自动全额填充
          const a = auths[0];
          this.pendingAllocations = [
            {
              budget_data_id: node.id,
              budget_name: node.name || "",
              department_id: a.department_id,
              department_name: a.department?.name || "",
              allocated_amount: this.totalAmount,
            },
          ];
        } else {
          // 情形(2)：单预算 + 多部门 -> 与原逻辑一致
          this.pendingAllocations = auths.map((a) => {
            const key = `${String(node.id)}:${String(a.department_id)}`;
            return {
              budget_data_id: node.id,
              budget_name: node.name || "",
              department_id: a.department_id,
              department_name: a.department?.name || "",
              allocated_amount: existingMap[key] ?? 0,
            };
          });
        }

        this.lastValidBudgetIds = ids;
        return;
      }

      // 多条预算来源：同一直接父级 + 每条唯一授权部门
      const parentId = selectedNodes[0].parent_id ?? null;
      const parentMismatch = selectedNodes.some((n) => (n.parent_id ?? null) !== parentId);
      if (parentMismatch) {
        this.selectionError = "多条预算来源必须同属一个直接父级";
        this.$message.warning(this.selectionError);
        this.setCheckedIds(this.lastValidBudgetIds);
        return;
      }

      const rows = [];
      for (const node of selectedNodes) {
        const auths = await this.getDepartmentAuthorizations(node.id);
        if (!auths || auths.length !== 1) {
          this.selectionError = "多条预算来源时，每条预算必须且仅能授权给一个部门";
          this.$message.warning(this.selectionError);
          this.setCheckedIds(this.lastValidBudgetIds);
          return;
        }
        const a = auths[0];
        const key = `${String(node.id)}:${String(a.department_id)}`;
        rows.push({
          budget_data_id: node.id,
          budget_name: node.name || "",
          department_id: a.department_id,
          department_name: a.department?.name || "",
          // 情形(3) 默认全为 0（由用户手动填充）
          allocated_amount: existingMap[key] ?? 0,
        });
      }
      this.pendingAllocations = rows;
      this.lastValidBudgetIds = ids;
    },
    findPathNames(tree, id, path = []) {
      if (!Array.isArray(tree)) return null;
      for (const n of tree) {
        const nextPath = [...path, n];
        if (String(n.id) === String(id)) return nextPath;
        if (n.children && n.children.length) {
          const found = this.findPathNames(n.children, id, nextPath);
          if (found) return found;
        }
      }
      return null;
    },
    getYearLabel() {
      const opt = (this.yearOptions || []).find(
        (y) => String(y.value) === String(this.yearId)
      );
      return opt?.label || (this.yearId ? `${this.yearId}年` : "");
    },
    async confirmPick() {
      if (!this.canConfirm) {
        this.$message.warning("请先选择预算来源，并确保分配总额等于本次付款金额");
        return;
      }

      // 基于 pendingAllocations 构建最终 payload（必须包含预算ID与部门ID，支持多条）
      const byBudget = {};
      (this.pendingAllocations || []).forEach((row) => {
        const bid = String(row.budget_data_id || "");
        const did = String(row.department_id || "");
        if (!bid || !did) return;
        if (!byBudget[bid]) byBudget[bid] = { budget_data_id: bid, allocations: [] };
        byBudget[bid].allocations.push({
          department_id: did,
          department_name: row.department_name || "",
          allocated_amount: parseFloat(row.allocated_amount) || 0,
        });
      });

      const budgetIds = Object.keys(byBudget);
      let payload;
      if (budgetIds.length === 1) {
        const bid = budgetIds[0];
        payload = {
          budget_data_id: bid,
          allocations: byBudget[bid].allocations,
        };
      } else {
        payload = {
          budget_items: budgetIds.map((bid) => byBudget[bid]),
        };
      }

      // 生成展示文本（多条用 “；” 分隔）
      const yearLabel = this.getYearLabel();
      const displayParts = budgetIds.map((bid) => {
        const nodes = this.findPathNames(this.treeData, bid) || [];
        const names = nodes.map((n) => n?.name).filter(Boolean);
        const leaf = nodes[nodes.length - 1];
        const typeText = this.budgetTypeMap[leaf?.budget_type] || leaf?.budget_type || "";
        return [yearLabel, typeText, ...names].filter(Boolean).join(" / ");
      });
      const display = displayParts.filter(Boolean).join("；");

      this.$emit("input", payload);
      this.$emit("update:display", display);
      this.dialogVisible = false;
    },
    onAllocationChange() {
      // 分配金额变化时的处理（实时验证已在按钮disabled中处理）
    },
    formatAmount(amount) {
      if (amount === null || amount === undefined) return "0.00";
      const num = parseFloat(amount);
      if (isNaN(num)) return "0.00";
      return num.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
    },
    formatExecutionRate(rate) {
      if (rate === null || rate === undefined) return "0.00%";
      const num = parseFloat(rate);
      if (isNaN(num)) return "0.00%";
      return num.toFixed(2) + "%";
    },
    getExecutionRateClass(rate) {
      const num = parseFloat(rate);
      if (isNaN(num)) return "";
      if (num >= 100) return "rate-high";
      if (num >= 80) return "rate-medium";
      if (num >= 50) return "rate-normal";
      return "rate-low";
    },
    clearValue() {
      this.$emit("input", "");
      this.$emit("update:display", "");
      this.generatedDisplayText = "";
    },
    async generateDisplayText() {
      // 如果没有值，清空显示文本
      if (!this.hasValue) {
        this.generatedDisplayText = "";
        return;
      }

      // 如果已经有后端返回的 display，不需要生成
      if (this.display && this.display.trim()) {
        return;
      }

      // 需要加载树数据来生成显示文本
      if (!this.yearOptions || this.yearOptions.length === 0) {
        await this.loadYearOptions();
      }

      // 尝试获取年份ID
      if (!this.yearId) {
        const fromValue = await this.tryResolveYearIdByValue();
        this.yearId = fromValue || (this.yearOptions.length > 0 ? this.yearOptions[0].value : null);
      }

      // 如果没有年份ID，无法生成显示文本
      if (!this.yearId) {
        this.generatedDisplayText = "";
        return;
      }

      // 加载树数据
      if (!this.treeData || this.treeData.length === 0) {
        try {
          const res = await getBudgetDataTree({ year_id: this.yearId }, false);
          this.treeData = Array.isArray(res) ? res : [];
        } catch (e) {
          console.error("加载树数据失败：", e);
          this.generatedDisplayText = "";
          return;
        }
      }

      // 生成显示文本
      const parts = [];
      const yearLabel = this.getYearLabel();

      // 处理多预算来源的情况
      if (this.budgetItems.length > 0) {
        const displayParts = [];
        for (const item of this.budgetItems) {
          const budgetId = String(item.budget_data_id || "");
          if (!budgetId) continue;

          const nodes = this.findPathNames(this.treeData, budgetId) || [];
          const names = nodes.map((n) => n?.name).filter(Boolean);
          const leaf = nodes[nodes.length - 1];
          const typeText = this.budgetTypeMap[leaf?.budget_type] || leaf?.budget_type || "";

          // 获取部门信息
          const allocations = Array.isArray(item.allocations) ? item.allocations : [];
          const deptNames = allocations
            .map((a) => a.department_name)
            .filter(Boolean)
            .slice(0, 3); // 最多显示3个部门

          let partText = [yearLabel, typeText, ...names].filter(Boolean).join(" / ");
          if (deptNames.length > 0) {
            if (deptNames.length === 1) {
              partText += `（${deptNames[0]}）`;
            } else if (deptNames.length <= 3) {
              partText += `（${deptNames.join("、")}）`;
            } else {
              partText += `（${deptNames.slice(0, 3).join("、")}等${allocations.length}个部门）`;
            }
          }
          displayParts.push(partText);
        }
        this.generatedDisplayText = displayParts.filter(Boolean).join("；");
        return;
      }

      // 处理单预算来源的情况
      if (this.budgetDataId) {
        const nodes = this.findPathNames(this.treeData, this.budgetDataId) || [];
        const names = nodes.map((n) => n?.name).filter(Boolean);
        const leaf = nodes[nodes.length - 1];
        const typeText = this.budgetTypeMap[leaf?.budget_type] || leaf?.budget_type || "";

        let displayText = [yearLabel, typeText, ...names].filter(Boolean).join(" / ");

        // 获取部门信息
        const allocations = Array.isArray(this.allocations) ? this.allocations : [];
        if (allocations.length > 0) {
          const deptNames = allocations
            .map((a) => a.department_name)
            .filter(Boolean)
            .slice(0, 3); // 最多显示3个部门

          if (deptNames.length === 1) {
            displayText += `（${deptNames[0]}）`;
          } else if (deptNames.length <= 3) {
            displayText += `（${deptNames.join("、")}）`;
          } else {
            displayText += `（${deptNames.slice(0, 3).join("、")}等${allocations.length}个部门）`;
          }
        }

        this.generatedDisplayText = displayText;
        return;
      }

      // 如果都没有，清空显示文本
      this.generatedDisplayText = "";
    },
  },
  watch: {
    value: {
      immediate: true,
      handler() {
        // 当 value 变化时，重新生成显示文本
        this.$nextTick(() => {
          this.generateDisplayText();
        });
      },
    },
    display(newVal) {
      // 如果后端返回了 display，清空生成的显示文本
      if (newVal && newVal.trim()) {
        this.generatedDisplayText = "";
      }
    },
  },
  mounted() {
    // 组件挂载时，如果有值，生成显示文本
    if (this.hasValue) {
      this.generateDisplayText();
    }
  },
};
</script>

<style scoped>
.budget-source-field {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.budget-source-label {
  color: #303133;
  font-size: 14px;
  font-weight: 500;
  flex: 1;
  min-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.budget-source-label--muted {
  color: #606266;
}

.tree-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 2px solid #e4e7ed;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 12px;
}

.node-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #303133;
  font-weight: 500;
}

.node-label--clickable {
  cursor: pointer;
  transition: color 0.2s;
}

.node-label--clickable:hover {
  color: #409eff;
}

.node-usage-info {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-left: 16px;
  flex-shrink: 0;
  font-size: 14px;
}

.usage-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.usage-label {
  color: #606266;
  font-size: 14px;
  font-weight: 500;
}

.usage-value {
  color: #303133;
  font-weight: 600;
  font-size: 14px;
}

.usage-value--used {
  color: #409eff;
  font-weight: 600;
}

.usage-value--rate {
  min-width: 60px;
  text-align: right;
}

.usage-value--rate.rate-high {
  color: #f56c6c;
  font-weight: 700;
}

.usage-value--rate.rate-medium {
  color: #e6a23c;
  font-weight: 600;
}

.usage-value--rate.rate-normal {
  color: #409eff;
  font-weight: 600;
}

.usage-value--rate.rate-low {
  color: #909399;
  font-weight: 500;
}
</style>


