<template>
  <div class="app-container">
    <!-- ===== 搜索栏 ===== -->
    <el-card shadow="never" class="mb16 filter-card">
      <el-form :model="queryParams" ref="queryForm" :inline="true" size="small">
        <el-form-item label="租户名称" prop="tenantName">
          <el-input v-model="queryParams.tenantName" placeholder="租户编码/名称" clearable @keyup.enter.native="handleQuery" />
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-select v-model="queryParams.status" placeholder="全部" clearable style="width:120px">
            <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- ===== 操作栏 ===== -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['admin:platform:edit']">新增租户</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading" @click="handleExport">导出</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>

    <!-- ===== 租户列表 ===== -->
    <el-table border v-loading="loading" :data="companyList" size="small" style="width:100%">
      <el-table-column label="租户编码" prop="tenantCode" min-width="80" align="center" />
      <el-table-column label="租户名称" prop="tenantName" min-width="120" />
      <el-table-column label="联系人" prop="contactName" min-width="80" align="center" />
      <el-table-column label="联系电话" prop="contactPhone" min-width="110" align="center" />
      <el-table-column label="余额" align="center" min-width="100">
        <template slot-scope="scope">
          <span style="color:#1890ff;font-weight:bold">{{ scope.row.balance ? '¥' + Number(scope.row.balance).toFixed(2) : '¥0.00' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="已消费总额" align="center" min-width="100">
        <template slot-scope="scope">
          <span>{{ scope.row.totalConsumption ? '¥' + Number(scope.row.totalConsumption).toFixed(2) : '¥0.00' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="开通账户数" align="center" prop="accountCount" min-width="90" />
      <el-table-column label="绑定企微账户数" align="center" prop="qwAccountCount" min-width="110" />
      <el-table-column label="绑定个微账户数" align="center" prop="wxAccountCount" min-width="110" />
      <el-table-column label="客户数" align="center" prop="customerCount" min-width="80" />
      <el-table-column label="企微用户数" align="center" prop="qwUserCount" min-width="90" />
      <el-table-column label="过期时间" align="center" prop="expireTime" min-width="100" />
      <el-table-column label="归属代理" align="center" prop="proxyName" min-width="90" />
      <el-table-column label="状态" align="center" min-width="70">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.status == 1" type="success" size="mini">正常</el-tag>
          <el-tag v-else type="danger" size="mini">禁用</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="380" fixed="right" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleView(scope.row)">编辑</el-button>
          <el-button size="mini" type="text" icon="el-icon-key" style="color:#722ed1" @click="handleResetPwd(scope.row)">重置密码</el-button>
          <el-button size="mini" type="text" style="color:#52c41a" icon="el-icon-coin" @click="handleRecharge(scope.row)">充值/扣款</el-button>
          <el-button size="mini" type="text" style="color:#722ed1" icon="el-icon-menu" @click="handleEditMenu(scope.row, 'sys')">管理端菜单</el-button>
          <el-button size="mini" type="text" style="color:#e6a23c" icon="el-icon-price-tag" @click="handleModulePricing(scope.row)">模块定价</el-button>
          <el-button size="mini" type="text" style="color:#13c2c2" icon="el-icon-sell" @click="handleEditMenu(scope.row, 'com')">销售菜单</el-button>
          <el-button
            v-if="scope.row.status == 1"
            size="mini" type="text" style="color:#fa8c16"
            icon="el-icon-lock"
            @click="handleDisable(scope.row)"
            v-hasPermi="['admin:platform:edit']"
          >禁用</el-button>
          <el-button
            v-else
            size="mini" type="text" style="color:#52c41a"
            icon="el-icon-unlock"
            @click="handleEnable(scope.row)"
            v-hasPermi="['admin:platform:edit']"
          >启用</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />

    <!-- ===== 编辑租户弹窗 ===== -->
    <el-dialog title="编辑租户" :visible.sync="viewOpen" width="720px" append-to-body destroy-on-close class="tenant-dialog">
      <el-form ref="editForm" :model="viewForm" :rules="editRules" label-width="112px" size="small" class="tenant-dialog-form">
        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="租户ID">
              <span>{{ viewForm.id }}</span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="租户编码">
              <span>{{ viewForm.tenantCode || '-' }}</span>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="租户名称" prop="tenantName">
              <el-input v-model="viewForm.tenantName" placeholder="请输入租户名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话" prop="contactPhone">
              <el-input v-model="viewForm.contactPhone" placeholder="请输入联系电话" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系人" prop="contactName">
              <el-input v-model="viewForm.contactName" placeholder="请输入联系人" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="过期时间" prop="expireTime">
              <el-date-picker v-model="viewForm.expireTime" type="date" value-format="yyyy-MM-dd" placeholder="选择过期时间" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="归属代理" prop="proxyId">
              <el-select v-model="viewForm.proxyId" placeholder="请选择代理" clearable filterable style="width:100%">
                <el-option v-for="p in proxyOptions" :key="p.proxyId" :label="p.proxyName" :value="p.proxyId" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="租户状态">
              <el-switch v-model="viewForm.statusBool" active-text="正常" inactive-text="禁用"
                         :active-value="1" :inactive-value="0" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="公司数量" prop="companyNum">
              <el-input-number v-model="viewForm.companyNum" :min="1" :precision="0" controls-position="right" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item prop="accountNum">
              <span slot="label" class="tenant-form-label" title="公司员工账户总数量">员工账户数</span>
              <el-input-number v-model="viewForm.accountNum" :min="1" :precision="0" controls-position="right" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="租户余额" class="tenant-balance-item">
              <span style="color:#1890ff;font-weight:bold">¥{{ viewForm.balance || '0.00' }}</span>
              <span class="tenant-balance-hint">（通过充值/扣款调整）</span>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer">
        <el-button @click="viewOpen = false">取 消</el-button>
        <el-button type="primary" :loading="editSubmitting" @click="submitEdit">保 存</el-button>
      </div>
    </el-dialog>

    <!-- ===== 新增租户弹窗 ===== -->
    <el-dialog title="新增租户" :visible.sync="addDialog.visible" width="720px" append-to-body destroy-on-close class="tenant-dialog">
      <el-form ref="addForm" :model="addDialog.form" :rules="addDialog.rules" label-width="112px" size="small" class="tenant-dialog-form">
        <el-row :gutter="16">
          <el-col :span="12">
            <el-form-item label="企业名称" prop="tenantName">
              <el-input v-model="addDialog.form.tenantName" placeholder="请输入企业名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话" prop="contactPhone">
              <el-input v-model="addDialog.form.contactPhone" placeholder="请输入联系电话" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系人" prop="contactName">
              <el-input v-model="addDialog.form.contactName" placeholder="请输入联系人" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="商务负责人" prop="manager">
              <el-input v-model="addDialog.form.manager" placeholder="请输入商务负责人" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="管理员账号" prop="userName">
              <el-input v-model="addDialog.form.userName" placeholder="请输入管理员账号" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="密码" prop="password">
              <el-input v-model="addDialog.form.password" type="password" show-password placeholder="请输入密码">
                <el-button slot="append" icon="el-icon-refresh" @click="generateAddPwd" title="随机生成密码">生成</el-button>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="开始时间" prop="startTime">
              <el-date-picker v-model="addDialog.form.startTime" type="date" value-format="yyyy-MM-dd" placeholder="选择开始时间" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="到期时间" prop="expireTime">
              <el-date-picker v-model="addDialog.form.expireTime" type="date" value-format="yyyy-MM-dd" placeholder="选择到期时间" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="归属代理" prop="proxyId">
              <el-select v-model="addDialog.form.proxyId" placeholder="请选择代理" clearable filterable style="width:100%">
                <el-option v-for="p in proxyOptions" :key="p.proxyId" :label="p.proxyName" :value="p.proxyId" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="公司数量" prop="companyNum">
              <el-input-number v-model="addDialog.form.companyNum" :min="1" :precision="0" controls-position="right" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item prop="accountNum">
              <span slot="label" class="tenant-form-label" title="公司员工账户总数量">员工账户数</span>
              <el-input-number v-model="addDialog.form.accountNum" :min="1" :precision="0" controls-position="right" style="width:100%" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="状态" prop="status" class="tenant-status-item">
              <el-radio-group v-model="addDialog.form.status">
                <el-radio :label="1">启用</el-radio>
                <el-radio :label="0">禁用</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>

        </el-row>
      </el-form>
      <div slot="footer">
        <el-button @click="addDialog.visible = false">取 消</el-button>
        <el-button type="primary" :loading="addDialog.submitting" @click="submitAdd">确 定</el-button>
      </div>
    </el-dialog>

    <!-- ===== 充值/扣款弹窗 ===== -->
    <el-dialog :title="rechargeTitle" :visible.sync="rechargeOpen" width="420px" append-to-body>
      <el-form ref="rechargeForm" :model="rechargeForm" :rules="rechargeRules" label-width="90px">
        <el-form-item label="租户名称">
          <span>{{ rechargeForm.companyName }}</span>
        </el-form-item>
        <el-form-item label="当前余额">
          <span style="color:#1890ff;font-weight:bold">¥{{ rechargeForm.currentBalance || '0.00' }}</span>
        </el-form-item>
        <el-form-item label="操作类型" prop="operateType">
          <el-radio-group v-model="rechargeForm.operateType">
            <el-radio label="recharge">充值</el-radio>
            <el-radio label="deduct">扣款</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="金额" prop="amount">
          <el-input-number v-model="rechargeForm.amount" :min="0.01" :precision="2" style="width:200px" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="rechargeForm.remark" type="textarea" :rows="2" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="rechargeOpen = false">取 消</el-button>
        <el-button type="primary" @click="submitRecharge">确 定</el-button>
      </div>
    </el-dialog>

    <!-- ===== 菜单编辑弹窗（租户列表：管理端菜单 / 销售菜单） ===== -->
    <el-dialog :title="menuDialog.title" :visible.sync="menuDialog.visible" width="560px" append-to-body destroy-on-close @opened="onMenuDialogOpened">
      <div v-loading="menuDialog.loading" class="menu-tree-scroll">
        <div v-if="menuDialog.treeReady && menuDialog.treeData.length" class="menu-tree-toolbar">
          <el-button type="text" size="mini" @click="checkAllMenuNodes">全选</el-button>
          <el-button type="text" size="mini" @click="uncheckAllMenuNodes">全不选</el-button>
          <el-button type="text" size="mini" @click="expandAllMenuNodes">展开全部</el-button>
          <el-button type="text" size="mini" @click="collapseAllMenuNodes">收起全部</el-button>
        </div>
        <el-tree
          v-if="menuDialog.treeReady"
          ref="menuTree"
          :data="menuDialog.treeData"
          show-checkbox
          node-key="menuId"
          :props="menuTreeProps"
          :expand-on-click-node="false"
        >
          <span slot-scope="{ data }" class="custom-tree-node">
            <span>{{ data.menuName }}</span>
            <el-tag v-if="data.menuType === 'M'" size="mini" style="margin-left:6px">目录</el-tag>
            <el-tag v-else-if="data.menuType === 'C'" type="success" size="mini" style="margin-left:6px">菜单</el-tag>
            <el-tag v-else-if="data.menuType === 'F'" type="warning" size="mini" style="margin-left:6px">按钮</el-tag>
            <el-tag v-if="isMenuAssigned(data)" type="success" size="mini" style="margin-left:6px">已分配</el-tag>
            <el-tag v-else type="info" size="mini" style="margin-left:6px">未分配</el-tag>
          </span>
        </el-tree>
        <el-empty v-if="!menuDialog.loading && menuDialog.treeReady && !menuDialog.treeData.length" description="暂无菜单数据" />
      </div>
      <div slot="footer">
        <el-button @click="menuDialog.visible = false">取 消</el-button>
        <el-button type="primary" :loading="menuDialog.submitting" @click="submitMenuEdit">确 定</el-button>
      </div>
    </el-dialog>

    <!-- ===== 模块定价弹窗 ===== -->
    <el-dialog :title="'模块定价 - ' + pricingDialog.tenantName" :visible.sync="pricingDialog.visible" width="720px" append-to-body destroy-on-close class="pricing-dialog">
      <div v-loading="pricingDialog.loading" class="pricing-container">
        <!-- 头部提示 -->
        <div class="pricing-header">
          <i class="el-icon-info" style="color:#409EFF;margin-right:6px"></i>
          <span>租户售价/成本价留空或填0则使用全局定价</span>
        </div>

        <!-- 模块卡片列表 -->
        <div class="pricing-list">
          <div v-for="(item, index) in pricingDialog.modules" :key="item.serviceType" class="pricing-card">
            <!-- 卡片头部 -->
            <div class="pricing-card-header">
              <div class="module-title">
                <el-tag size="small" type="primary" effect="plain">{{ item.moduleName }}</el-tag>
              </div>
              <el-switch
                v-model="item.status"
                :active-value="1"
                :inactive-value="0"
                active-text="启用"
                inactive-text="禁用"
                size="small"
              />
            </div>

            <!-- 定价区域 -->
            <div class="pricing-card-body">
              <!-- 全局定价参考 -->
              <div class="global-pricing">
                <div class="price-item">
                  <span class="price-label">全局售价</span>
                  <span class="price-value global">¥{{ item.globalPrice != null ? item.globalPrice : '-' }}</span>
                </div>
                <div class="price-item">
                  <span class="price-label">全局成本</span>
                  <span class="price-value global">¥{{ item.globalCost != null ? item.globalCost : '-' }}</span>
                </div>
              </div>

              <div class="divider"></div>

              <!-- 租户自定义定价 -->
              <div class="tenant-pricing">
                <div class="price-item">
                  <span class="price-label">
                    <i class="el-icon-price-tag" style="color:#67C23A;margin-right:4px"></i>租户售价
                  </span>
                  <el-input-number
                    v-model="item.price"
                    :precision="4"
                    :min="0"
                    :step="0.01"
                    size="small"
                    controls-position="right"
                    style="width:140px"
                    placeholder="跟随全局"
                  />
                </div>
                <div class="price-item">
                  <span class="price-label">
                    <i class="el-icon-coin" style="color:#E6A23C;margin-right:4px"></i>租户成本
                  </span>
                  <el-input-number
                    v-model="item.costPrice"
                    :precision="4"
                    :min="0"
                    :step="0.01"
                    size="small"
                    controls-position="right"
                    style="width:140px"
                    placeholder="跟随全局"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div slot="footer" class="pricing-footer">
        <el-button @click="pricingDialog.visible = false" size="medium">取 消</el-button>
        <el-button type="primary" :loading="pricingDialog.submitting" size="medium" icon="el-icon-check" @click="submitModulePricing">保 存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listAllCompanies, getCompanyInfo, addCompany, updateTenant, disableCompany, enableCompany, rechargeCompany, exportCompany, getTenantMenuTree, editTenantMenu, resetTenantPwd } from '@/api/admin/sysCompany'
import { listTrafficPricing, addTrafficPricing, updateTrafficPricing } from '@/api/admin/trafficPricing'
import { allEnabledProxies } from '@/api/admin/proxy'
import { listServiceCost } from '@/api/admin/serviceCost'
import { generateRandomPwd } from '@/utils/index'

export default {
  name: 'SysCompanyAdmin',
  data() {
    return {
      loading: true,
      exportLoading: false,
      showSearch: true,
      total: 0,
      companyList: [],
      statusOptions: [
        { value: 1, label: '正常' },
        { value: 3, label: '禁用' }
      ],
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        tenantName: null,
        status: null
      },
      // 详情弹窗
      viewOpen: false,
      viewForm: {},
      editSubmitting: false,
      editRules: {
        tenantName: [{ required: true, message: '请输入租户名称', trigger: 'blur' }],
        contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
        companyNum: [{ required: true, message: '请输入公司数量', trigger: 'blur' }],
        accountNum: [{ required: true, message: '请输入员工账户数', trigger: 'blur' }]
      },
      // 新增租户弹窗
      addDialog: {
        visible: false,
        submitting: false,
        form: {
          tenantName: '',
          contactPhone: '',
          contactName: '',
          userName: '',
          password: '',
          manager: '',
          startTime: null,
          expireTime: null,
          status: 1,
          companyNum: 1,
          accountNum: 1
        },
        rules: {
          tenantName: [{ required: true, message: '请输入企业名称', trigger: 'blur' }],
          contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
          userName: [{ required: true, message: '请输入管理员账号', trigger: 'blur' }],
          password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
          companyNum: [{ required: true, message: '请输入公司数量', trigger: 'blur' }],
          accountNum: [{ required: true, message: '请输入员工账户数', trigger: 'blur' }]
        }
      },
      // 充值/扣款弹窗
      rechargeOpen: false,
      rechargeTitle: '',
      rechargeForm: { companyId: null, companyName: '', currentBalance: 0, operateType: 'recharge', amount: null, remark: '' },
      rechargeRules: {
        operateType: [{ required: true, message: '请选择操作类型', trigger: 'change' }],
        amount: [{ required: true, message: '请输入金额', trigger: 'blur' }]
      },
      menuTreeProps: { label: 'menuName', children: 'children' },
      // 菜单编辑弹窗
      menuDialog: {
        visible: false,
        title: '',
        flag: 'sys',
        companyId: null,
        companyName: '',
        treeData: [],
        treeReady: false,
        checkedKeys: [],
        checkedKeysFromApi: [],
        checkedKeySet: null,
        initialAssignedIds: null,
        loading: false,
        submitting: false
      },
      // 模块定价弹窗
      pricingDialog: {
        visible: false,
        tenantId: null,
        tenantName: '',
        loading: false,
        submitting: false,
        modules: []
      },
      // 代理列表（下拉框用）
      proxyOptions: []
    }
  },
  created() {
    this.getList()
    this.loadProxyOptions()
  },
  methods: {
    loadProxyOptions() {
      allEnabledProxies().then(res => {
        this.proxyOptions = res.data || []
      }).catch(() => {})
    },
    getList() {
      this.loading = true
      listAllCompanies(this.queryParams).then(response => {
        this.companyList = response.rows
        this.total = response.total
        this.loading = false
      })
    },
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    resetQuery() {
      this.resetForm('queryForm')
      this.handleQuery()
    },
    /** 新增租户 */
    handleAdd() {
      this.addDialog.form = {
        tenantName: '',
        contactPhone: '',
        contactName: '',
        userName: '',
        password: generateRandomPwd(12),
        manager: '',
        proxyId: null,
        startTime: null,
        expireTime: null,
        status: 1,
        companyNum: 1,
        accountNum: 1
      }
      this.addDialog.visible = true
      this.$nextTick(() => {
        if (this.$refs.addForm) this.$refs.addForm.clearValidate()
      })
    },
    /** 随机生成新增密码 */
    generateAddPwd() {
      this.addDialog.form.password = generateRandomPwd(12)
    },
    /** 重置租户管理员密码 */
    handleResetPwd(row) {
      const newPwd = generateRandomPwd(12)
      this.$prompt('为租户 "' + row.tenantName + '" 重置管理员密码', '重置密码', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        inputValue: newPwd,
        inputPattern: /^.{6,30}$/,
        inputErrorMessage: '密码长度必须介于 6 和 30 之间',
        inputType: 'text'
      }).then(({ value }) => {
        resetTenantPwd(row.id, value).then(() => {
          this.$message.success('密码重置成功，新密码为：' + value)
        }).catch(() => {
          this.$message.error('密码重置失败')
        })
      }).catch(() => {})
    },
    /** 提交新增租户 */
    submitAdd() {
      this.$refs['addForm'].validate(valid => {
        if (!valid) return
        this.addDialog.submitting = true
        addCompany(this.addDialog.form).then(() => {
          this.$message.success('新增成功')
          this.addDialog.visible = false
          this.getList()
        }).catch(() => {
          this.$message.error('新增失败，请重试')
        }).finally(() => {
          this.addDialog.submitting = false
        })
      })
    },
    /** 编辑租户 */
    handleView(row) {
      getCompanyInfo(row.id).then(response => {
        this.viewForm = response.data
        if (this.viewForm.companyNum == null) {
          this.$set(this.viewForm, 'companyNum', 1)
        }
        if (this.viewForm.accountNum == null) {
          this.$set(this.viewForm, 'accountNum', 1)
        }
        // 为 el-switch 提供 number 类型的 status
        this.$set(this.viewForm, 'statusBool', this.viewForm.status)
        this.viewOpen = true
        this.$nextTick(() => {
          if (this.$refs.editForm) this.$refs.editForm.clearValidate()
        })
      }).catch(() => {
        this.$message.error('获取租户信息失败')
      })
    },
    /** 提交编辑租户 */
    submitEdit() {
      this.$refs['editForm'].validate(valid => {
        if (!valid) return
        this.editSubmitting = true
        const data = {
          id: this.viewForm.id,
          tenantName: this.viewForm.tenantName,
          contactName: this.viewForm.contactName,
          contactPhone: this.viewForm.contactPhone,
          expireTime: this.viewForm.expireTime,
          status: this.viewForm.statusBool,
          proxyId: this.viewForm.proxyId,
          companyNum: this.viewForm.companyNum,
          accountNum: this.viewForm.accountNum
        }
        updateTenant(data).then(() => {
          this.$message.success('保存成功')
          this.viewOpen = false
          this.getList()
        }).catch(() => {
          this.$message.error('保存失败，请重试')
        }).finally(() => {
          this.editSubmitting = false
        })
      })
    },
    /** 充值/扣款 */
    handleRecharge(row) {
      this.rechargeForm = {
        companyId: row.id,
        companyName: row.tenantName,
        currentBalance: row.balance || 0,
        operateType: 'recharge',
        amount: null,
        remark: ''
      }
      this.rechargeTitle = `充值/扣款 - ${row.tenantName}`
      this.rechargeOpen = true
    },
    submitRecharge() {
      this.$refs['rechargeForm'].validate(valid => {
        if (!valid) return
        const { companyId, operateType, amount, remark } = this.rechargeForm
        rechargeCompany(companyId, { operateType, amount, remark }).then(res => {
          if (res.code === 200) {
            this.$message.success(res.msg || (operateType === 'recharge' ? '充值成功' : '扣款成功'))
            this.rechargeOpen = false
            this.getList()
          } else {
            this.$message.error(res.msg || '操作失败')
          }
        }).catch(() => {
          this.$message.error('操作失败，请重试')
        })
      })
    },
    /** 禁用租户 */
    handleDisable(row) {
      this.$confirm('确定禁用租户 [' + row.tenantName + '] 吗?', '提示', {
        confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'
      }).then(() => {
        disableCompany(row.id).then(() => {
          this.$message.success('禁用成功')
          this.getList()
        })
      })
    },
    /** 启用租户 */
    handleEnable(row) {
      this.$confirm('确定启用租户 [' + row.tenantName + '] 吗?', '提示', {
        confirmButtonText: '确定', cancelButtonText: '取消', type: 'info'
      }).then(() => {
        enableCompany(row.id).then(() => {
          this.$message.success('启用成功')
          this.getList()
        })
      })
    },
    handleExport() {
      this.exportLoading = true
      exportCompany(this.queryParams).then(response => {
        // 直接处理 Blob 下载
        const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
        const url = window.URL.createObjectURL(blob)
        const link = document.createElement('a')
        link.href = url
        link.download = '租户列表数据.xlsx'
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
        window.URL.revokeObjectURL(url)
        this.exportLoading = false
      }).catch(() => { this.exportLoading = false })
    },
    normalizeMenuId(id) {
      if (id == null || id === '') return null
      const n = Number(id)
      return Number.isNaN(n) ? id : n
    },
    /** 租户库已分配：优先 checkedKeys，其次 visible=0（不再依赖 status，避免按钮类菜单回显失败） */
    isMenuAssigned(menu) {
      if (!menu) return false
      const menuId = this.normalizeMenuId(menu.menuId)
      if (menuId != null && this.menuDialog.checkedKeySet && this.menuDialog.checkedKeySet.has(menuId)) {
        return true
      }
      return menu.visible === '0' || menu.visible === 0
    },
    normalizeMenuFlatList(menus) {
      return (menus || []).map(m => ({
        ...m,
        menuId: this.normalizeMenuId(m.menuId),
        parentId: m.parentId != null && m.parentId !== '' ? this.normalizeMenuId(m.parentId) : m.parentId
      }))
    },
    collectAssignedMenuIds(nodes) {
      const ids = []
      const walk = (list) => {
        (list || []).forEach(n => {
          if (this.isMenuAssigned(n)) {
            const mid = this.normalizeMenuId(n.menuId)
            if (mid != null) ids.push(mid)
          }
          if (n.children && n.children.length) walk(n.children)
        })
      }
      walk(nodes)
      return ids
    },
    applyMenuTreeChecked(checkedKeys) {
      const tree = this.$refs.menuTree
      const d = this.menuDialog
      if (!tree) return
      const keys = (checkedKeys || []).map(id => this.normalizeMenuId(id)).filter(id => id != null)
      tree.setCheckedKeys([])
      keys.forEach(menuId => {
        const node = tree.getNode(menuId)
        if (node) node.setChecked(true, false)
      })
      const currentKeys = tree.getCheckedKeys().concat(tree.getHalfCheckedKeys()).map(id => this.normalizeMenuId(id))
      d.checkedKeys = currentKeys
      d.checkedKeySet = new Set(currentKeys)
    },
    walkMenuTreeNodes(nodes, fn) {
      (nodes || []).forEach(n => {
        fn(n)
        if (n.children && n.children.length) this.walkMenuTreeNodes(n.children, fn)
      })
    },
    collectAllMenuIds(nodes) {
      const ids = []
      this.walkMenuTreeNodes(nodes, n => {
        const mid = this.normalizeMenuId(n.menuId)
        if (mid != null) ids.push(mid)
      })
      return ids
    },
    setAllMenuNodesChecked(checked) {
      const tree = this.$refs.menuTree
      if (!tree) return
      // 与回显一致：逐节点 setChecked，避免 setCheckedKeys(父节点) 级联导致 diff 异常
      this.walkMenuTreeNodes(this.menuDialog.treeData, n => {
        const node = tree.getNode(this.normalizeMenuId(n.menuId))
        if (node) node.setChecked(checked, false)
      })
    },
    checkAllMenuNodes() {
      this.setAllMenuNodesChecked(true)
    },
    uncheckAllMenuNodes() {
      this.setAllMenuNodesChecked(false)
    },
    expandAllMenuNodes() {
      const tree = this.$refs.menuTree
      if (!tree) return
      this.walkMenuTreeNodes(this.menuDialog.treeData, n => {
        const node = tree.getNode(this.normalizeMenuId(n.menuId))
        if (node) node.expanded = true
      })
    },
    collapseAllMenuNodes() {
      const tree = this.$refs.menuTree
      if (!tree) return
      this.walkMenuTreeNodes(this.menuDialog.treeData, n => {
        const node = tree.getNode(this.normalizeMenuId(n.menuId))
        if (node) node.expanded = false
      })
    },
    checkAllMenuNodes() {
      const tree = this.$refs.menuTree
      if (!tree) return
      const allKeys = []
      this.walkMenuTreeNodes(this.menuDialog.treeData, n => allKeys.push(n.menuId))
      tree.setCheckedKeys(allKeys)
    },
    uncheckAllMenuNodes() {
      const tree = this.$refs.menuTree
      if (!tree) return
      tree.setCheckedKeys([])
    },
    onMenuDialogOpened() {
      if (this.menuDialog.companyId) {
        this.loadTenantMenuTree()
      }
    },
    loadTenantMenuTree() {
      const d = this.menuDialog
      if (!d.companyId) return
      d.loading = true
      d.treeReady = false
      d.treeData = []
      getTenantMenuTree(d.companyId, d.flag).then(res => {
        if (res.code !== 200) {
          return Promise.reject(new Error(res.msg || '加载菜单失败'))
        }
        const flat = this.normalizeMenuFlatList(res.menus || [])
        const checkedFromApi = (res.checkedKeys || [])
          .map(id => this.normalizeMenuId(id))
          .filter(id => id != null)
        d.checkedKeysFromApi = checkedFromApi
        d.initialAssignedIds = new Set(checkedFromApi)
        d.checkedKeySet = new Set(checkedFromApi)
        // 与模板维护页相同：扁平数据 + handleTree(menuId) 建树，保证层级一致
        const tree = this.handleTree(flat, 'menuId')
        d.treeData = tree
        requestAnimationFrame(() => {
          d.treeReady = true
          this.$nextTick(() => this.applyMenuTreeChecked(checkedFromApi))
        })
      }).catch(err => {
        this.$message.error(err.message || '加载菜单失败')
      }).finally(() => {
        d.loading = false
      })
    },
    /** 编辑菜单（管理端/销售端） */
    handleEditMenu(row, flag) {
      this.menuDialog = {
        visible: true,
        title: (flag === 'sys' ? '编辑管理端菜单 - ' : '编辑销售菜单 - ') + row.tenantName,
        flag: flag,
        companyId: row.id,
        companyName: row.tenantName,
        treeData: [],
        treeReady: false,
        checkedKeys: [],
        checkedKeysFromApi: [],
        checkedKeySet: null,
        initialAssignedIds: null,
        loading: false,
        submitting: false
      }
    },
    /** 模块定价 */
    handleModulePricing(row) {
      this.pricingDialog = {
        visible: true,
        tenantId: row.id,
        tenantName: row.tenantName,
        loading: true,
        submitting: false,
        modules: []
      }
      // 从收费配置API获取启用的模块列表（排除手拨外呼serviceType=6）
      Promise.all([
        listServiceCost(),
        listTrafficPricing({ tenantId: row.id, pageSize: 100 })
      ]).then(([costRes, pricingRes]) => {
        const costList = (costRes.data || []).filter(c => c.enabled === 1 && c.serviceType !== 6)
        const tenantPricings = pricingRes.rows || []
        const pricingMap = {}
        tenantPricings.forEach(p => { pricingMap[p.serviceType] = p })
        this.pricingDialog.modules = costList.map(c => {
          const existing = pricingMap[c.serviceType]
          // 如果租户定价为空或为0，则使用全局定价作为默认值
          const tenantPrice = existing ? existing.price : null
          const tenantCostPrice = existing ? existing.costPrice : null
          return {
            serviceType: c.serviceType,
            moduleName: c.configName,
            unit: c.feeUnit,
            globalPrice: c.feeStandard,
            globalCost: c.platformCost,
            price: tenantPrice || c.feeStandard,
            costPrice: tenantCostPrice || c.platformCost,
            status: existing ? existing.status : 1,
            id: existing ? existing.id : null
          }
        })
        this.pricingDialog.loading = false
      }).catch(() => {
        this.pricingDialog.loading = false
        this.$message.error('加载定价数据失败')
      })
    },
    /** 提交模块定价 */
    submitModulePricing() {
      this.pricingDialog.submitting = true
      const tenantId = this.pricingDialog.tenantId
      const promises = this.pricingDialog.modules.map(m => {
        const data = {
          tenantId: tenantId,
          serviceType: m.serviceType,
          price: m.price,
          costPrice: m.costPrice,
          status: m.status
        }
        if (m.id) {
          data.id = m.id
          return updateTrafficPricing(data)
        } else {
          return addTrafficPricing(data)
        }
      })
      Promise.all(promises).then(() => {
        this.$message.success('模块定价保存成功')
        this.pricingDialog.visible = false
      }).catch(() => {
        this.$message.error('部分定价保存失败，请重试')
      }).finally(() => {
        this.pricingDialog.submitting = false
      })
    },
    /** 模块定价 */
    handleModulePricing(row) {
      this.pricingDialog = {
        visible: true,
        tenantId: row.id,
        tenantName: row.tenantName,
        loading: true,
        submitting: false,
        modules: []
      }
      // 从收费配置API获取启用的模块列表（排除手拨外呼serviceType=6）
      Promise.all([
        listServiceCost(),
        listTrafficPricing({ tenantId: row.id, pageSize: 100 })
      ]).then(([costRes, pricingRes]) => {
        const costList = (costRes.data || []).filter(c => c.enabled === 1 && c.serviceType !== 6)
        const tenantPricings = pricingRes.rows || []
        const pricingMap = {}
        tenantPricings.forEach(p => { pricingMap[p.serviceType] = p })
        this.pricingDialog.modules = costList.map(c => {
          const existing = pricingMap[c.serviceType]
          // 如果租户定价为空或为0，则使用全局定价作为默认值
          const tenantPrice = existing ? existing.price : null
          const tenantCostPrice = existing ? existing.costPrice : null
          return {
            serviceType: c.serviceType,
            moduleName: c.configName,
            unit: c.feeUnit,
            globalPrice: c.feeStandard,
            globalCost: c.platformCost,
            price: tenantPrice || c.feeStandard,
            costPrice: tenantCostPrice || c.platformCost,
            status: existing ? existing.status : 1,
            id: existing ? existing.id : null
          }
        })
        this.pricingDialog.loading = false
      }).catch(() => {
        this.pricingDialog.loading = false
        this.$message.error('加载定价数据失败')
      })
    },
    /** 提交模块定价 */
    submitModulePricing() {
      this.pricingDialog.submitting = true
      const tenantId = this.pricingDialog.tenantId
      const promises = this.pricingDialog.modules.map(m => {
        // 空值转为 0（使用全局定价）
        const price = m.price || 0
        const costPrice = m.costPrice || 0
        // 从未设置过且都是 0，跳过
        if (!m.id && price === 0 && costPrice === 0) {
          return Promise.resolve()
        }
        const data = {
          tenantId: tenantId,
          serviceType: m.serviceType,
          price: price,
          costPrice: costPrice,
          status: m.status
        }
        if (m.id) {
          data.id = m.id
          return updateTrafficPricing(data)
        } else {
          return addTrafficPricing(data)
        }
      })
      Promise.all(promises).then(() => {
        this.$message.success('模块定价保存成功')
        this.pricingDialog.visible = false
      }).catch(() => {
        this.$message.error('部分定价保存失败，请重试')
      }).finally(() => {
        this.pricingDialog.submitting = false
      })
    },
    /** 提交菜单编辑：后端为全量替换，须提交当前完整勾选列表 */
    submitMenuEdit() {
      const tree = this.$refs.menuTree
      if (!tree) return
      const selected = tree.getCheckedKeys()
        .concat(tree.getHalfCheckedKeys())
        .map(id => this.normalizeMenuId(id))
        .filter(id => id != null)
      const uniqueSelected = [...new Set(selected)]
      if (uniqueSelected.length === 0) {
        this.$confirm('未勾选任何菜单，保存后将清空该租户已分配的菜单，是否继续？', '提示', {
          type: 'warning'
        }).then(() => {
          this.doSubmitMenuEdit(uniqueSelected)
        }).catch(() => {})
        return
      }
      this.doSubmitMenuEdit(uniqueSelected)
    },
    doSubmitMenuEdit(selected) {
      this.menuDialog.submitting = true
      editTenantMenu(this.menuDialog.companyId, {
        flag: this.menuDialog.flag,
        selected
      }).then(res => {
        if (res.code === 200) {
          this.$message.success('菜单更新成功')
          this.menuDialog.visible = false
        } else {
          this.$message.error(res.msg || '菜单更新失败')
        }
      }).catch(() => {
        this.$message.error('菜单更新失败')
      }).finally(() => {
        this.menuDialog.submitting = false
      })
    }
  }
}
</script>

<style scoped>
.mb8 { margin-bottom: 8px; }
.mb16 { margin-bottom: 16px; }
.filter-card { padding-bottom: 0; }
.menu-tree-scroll {
  min-height: 120px;
  max-height: 420px;
  overflow-y: auto;
}
.menu-tree-toolbar {
  margin-bottom: 8px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
}
.custom-tree-node {
  display: flex;
  align-items: center;
  font-size: 13px;
}
.tenant-dialog-form ::v-deep .el-form-item__label {
  white-space: nowrap;
  line-height: 32px;
}
.tenant-dialog-form ::v-deep .el-form-item {
  margin-bottom: 16px;
}
.tenant-dialog-form ::v-deep .el-input-number {
  width: 100%;
}
.tenant-form-label {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}
.tenant-balance-hint {
  color: #999;
  font-size: 12px;
  margin-left: 8px;
}
.tenant-balance-item ::v-deep .el-form-item__content {
  line-height: 32px;
}
.tenant-status-item ::v-deep .el-form-item__content {
  line-height: 32px;
}

/* ===== 模块定价弹窗样式 ===== */
.pricing-dialog ::v-deep .el-dialog {
  border-radius: 12px;
  overflow: hidden;
}
.pricing-dialog ::v-deep .el-dialog__header {
  background: linear-gradient(135deg, #409EFF 0%, #317ecc 100%);
  padding: 16px 20px;
}
.pricing-dialog ::v-deep .el-dialog__title {
  color: #fff;
  font-weight: 500;
}
.pricing-dialog ::v-deep .el-dialog__headerbtn .el-dialog__close {
  color: #fff;
}
.pricing-dialog ::v-deep .el-dialog__body {
  padding: 20px;
  background: #f5f7fa;
}

.pricing-container {
  max-height: 60vh;
  overflow-y: auto;
}

/* 头部提示 */
.pricing-header {
  background: linear-gradient(135deg, #ecf5ff 0%, #f0f9ff 100%);
  border: 1px solid #d9ecff;
  border-radius: 8px;
  padding: 12px 16px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  font-size: 13px;
  color: #409EFF;
}

/* 卡片列表 */
.pricing-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* 定价卡片 */
.pricing-card {
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
  border: 1px solid #ebeef5;
  overflow: hidden;
  transition: all 0.3s ease;
}
.pricing-card:hover {
  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  transform: translateY(-1px);
}

/* 卡片头部 */
.pricing-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background: linear-gradient(135deg, #fafbfc 0%, #f5f7fa 100%);
  border-bottom: 1px solid #ebeef5;
}
.module-title .el-tag {
  font-size: 13px;
  font-weight: 500;
  padding: 4px 12px;
}

/* 卡片主体 */
.pricing-card-body {
  padding: 16px;
  display: flex;
  align-items: center;
  gap: 20px;
}

/* 定价区域 */
.global-pricing,
.tenant-pricing {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* 分割线 */
.divider {
  width: 1px;
  height: 60px;
  background: linear-gradient(180deg, transparent 0%, #dcdfe6 50%, transparent 100%);
}

/* 价格项 */
.price-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.price-label {
  font-size: 13px;
  color: #606266;
  white-space: nowrap;
}
.price-value {
  font-size: 14px;
  font-weight: 500;
  font-family: 'Microsoft YaHei', sans-serif;
}
.price-value.global {
  color: #909399;
  background: #f4f4f5;
  padding: 4px 12px;
  border-radius: 4px;
}

/* 底部按钮 */
.pricing-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px 20px;
  background: #fff;
  border-top: 1px solid #ebeef5;
}
.pricing-footer .el-button {
  padding: 10px 24px;
  border-radius: 6px;
}
</style>
