/**
     * 姓名脱敏
     *
     * 规则:
     * 1. 单姓:保留姓,名字部分用 * 替换
     *    例:张三 => 张*
     *        王小明 => 王**
     *
     * 2. 复姓:保留复姓,后面的名字部分用 * 替换
     *    例:欧阳娜娜 => 欧阳**
     *        司马懿 => 司马*
     *
     * 3. 单字姓名:直接返回
     *    例:王 => 王
     *
     * @param string $name 姓名
     * @return string
     */
    public static function maskChineseName(string $name): string
    {
        $name = trim($name);
        if ($name === '') {
            return '';
        }

        // 常见复姓表,可按需继续补充
        $compoundSurnames = [
            '欧阳', '太史', '端木', '上官', '司马', '东方', '独孤', '南宫', '万俟', '闻人',
            '夏侯', '诸葛', '尉迟', '公羊', '赫连', '澹台', '皇甫', '宗政', '濮阳', '公冶',
            '太叔', '申屠', '公孙', '慕容', '仲孙', '钟离', '长孙', '宇文', '司徒', '鲜于',
            '司空', '闾丘', '子车', '亓官', '司寇', '巫马', '公西', '颛孙', '壤驷', '公良',
            '漆雕', '乐正', '宰父', '谷梁', '拓跋', '夹谷', '轩辕', '令狐', '段干', '百里',
            '呼延', '东郭', '南门', '羊舌', '微生', '公户', '公玉', '公仪', '梁丘', '公仲',
            '公上', '公门', '公山', '公坚', '左丘', '公伯', '西门', '公祖', '第五', '公乘',
            '贯丘', '公皙', '南荣', '东里', '东宫', '仲长', '子书', '子桑', '即墨', '达奚',
            '褚师'
        ];

        $length = mb_strlen($name, 'UTF-8');

        // 单字姓名直接返回
        if ($length <= 1) {
            return $name;
        }

        // 先取前两个字,判断是否复姓
        $firstTwo = mb_substr($name, 0, 2, 'UTF-8');

        if (in_array($firstTwo, $compoundSurnames, true)) {
            $surname = $firstTwo;
            $givenNameLength = $length - 2;
        } else {
            $surname = mb_substr($name, 0, 1, 'UTF-8');
            $givenNameLength = $length - 1;
        }

        if ($givenNameLength <= 0) {
            return $surname;
        }

        return $surname . str_repeat('*', $givenNameLength);
    }
    /**
     * 解析表格
     * composer require phpoffice/phpspreadsheet
     * @param $file //上传的file对象 为空则默认从request里面尝试取file
     * @return array
     * @throws ApiException
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    public function ImportExcel($file = null)
    {
        //如果没有传值 就自动从request里面尝试取下
        $request = app(Request::class);
        if (!$file) $file = $request->file("file");
        //  初始化Excel读取器(自动识别Excel格式)
        if (!$file) throw new ApiException("请上传有效文件");
        $filename = time() . '.xlsx';
        $dir_path = public_path() . 'import/excel';
        $info = $file->move($dir_path, $filename);
        $path = $dir_path . '/' . $filename;
        $reader = self::getExcelReader($path);
        if (!$reader) {
            throw new ApiException("不支持的Excel格式,请使用.xlsx或.xls文件");
        }
        // 3. 读取Excel数据(仅读取数据,不加载格式,提升性能)
        $spreadsheet = $reader->load($path);
        $worksheet = $spreadsheet->getActiveSheet(); // 获取第一个工作表
        $data = $worksheet->toArray(null, false, true, true); // 保留表头,关联列名
        // 4. 验证数据是否为空
        if (count($data) <= 1) { // 小于等于1行表示只有表头或无数据
            throw new ApiException("Excel文件中无有效数据");
        }
        return $data;
    }


    /**
     * 获取Excel读取器(根据文件后缀识别格式)
     * @param string $filePath 文件路径
     * @return Xlsx|Xls|null 读取器实例
     */
    public static function getExcelReader(string $filePath)
    {
        $fileExt = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        switch ($fileExt) {
            case 'xlsx':
                return new Xlsx();
            case 'xls':
                return new Xls();
            default:
                return null;
        }
    }
Last modification:March 16, 2026
反正也没人会打赏