npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aftership/approval-widget-kit

v1.0.3

Published

Reusable approval widgets component library for AfterShip platforms

Downloads

126

Readme

@aftership/approval-widget-kit

🎨 Reusable approval widgets component library for AfterShip platforms

📦 安装

# npm
npm install @aftership/approval-widget-kit

# yarn
yarn add @aftership/approval-widget-kit

# pnpm
pnpm add @aftership/approval-widget-kit

✨ 特性

  • 零配置:无需手动配置认证和环境,开箱即用
  • 🎨 基于 Ant Design:与 Ant Design 完美集成
  • 📦 Tree-shakable:支持按需加载,减小打包体积
  • 🔒 TypeScript:完整的类型定义支持
  • 🌍 多环境支持:自动识别 production/staging/development
  • 🔐 自动认证:无缝集成 AfterShip 认证系统
  • 🔥 热更新友好:支持开发环境热更新

🚀 零配置使用

本组件库采用零配置设计,自动处理:

  • 认证:通过 @aftership/automizely-product-auth 自动获取 token
  • 环境:通过 process.env.APP_ENV 自动识别环境
  • API 请求:内置统一请求工具,自动添加认证头

前置条件

使用本组件库前,你的应用需要:

  1. 包裹 AuthProviderEmployee(来自 @aftership/automizely-product-auth
  2. 包裹 QueryClientProvider(来自 react-query
  3. 设置环境变量 process.env.APP_ENV(可选,默认 production)

快速开始

import React from 'react';
import ReactDOM from 'react-dom';
import { AuthProviderEmployee } from '@aftership/automizely-product-auth/internal';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ApprovalDetail } from '@aftership/approval-widget-kit';
import '@aftership/approval-widget-kit/dist/index.css';

// 创建 QueryClient 实例
const queryClient = new QueryClient();

function App() {
  return (
    <AuthProviderEmployee 
      config={{ 
        forceLogin: true,
        clientId: 'your-client-id' 
      }}
    >
      <QueryClientProvider client={queryClient}>
        {/* 使用审批详情组件 */}
        <ApprovalDetail approvalId="12345" />
      </QueryClientProvider>
    </AuthProviderEmployee>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

📚 组件说明

ApprovalDetail

审批详情组件,展示审批流程的完整信息,包括审批数据、流程图、评论和操作按钮。

Props

interface TApprovalDetailProps {
  // 必填
  approvalId: string;                           // 审批单 ID
  
  // 可选 - 显示控制
  isShowData?: boolean;                         // 是否显示审批数据,默认 true
  isShowLink?: boolean;                         // 是否显示流程图,默认 true
  isShowComment?: boolean;                      // 是否显示评论区,默认 true
  isShowOperation?: boolean;                    // 是否显示操作按钮,默认 true
  
  // 可选 - 事件回调
  onApprovalChange?: (approval: TApproval) => void;  // 审批状态变化回调
}

基础用法

import { ApprovalDetail } from '@aftership/approval-widget-kit';
import '@aftership/approval-widget-kit/dist/index.css';

function MyApprovalPage() {
  return <ApprovalDetail approvalId="12345" />;
}

自定义显示模块

import { ApprovalDetail } from '@aftership/approval-widget-kit';

function CustomApprovalView() {
  return (
    <ApprovalDetail 
      approvalId="12345"
      isShowData={true}      // 显示审批数据
      isShowLink={true}      // 显示流程图
      isShowComment={true}   // 显示评论区
      isShowOperation={false} // 隐藏操作按钮(只读模式)
    />
  );
}

监听审批状态变化

import { ApprovalDetail } from '@aftership/approval-widget-kit';
import type { TApproval, EApprovalState } from '@aftership/approval-widget-kit';

function ApprovalWithCallback() {
  const handleApprovalChange = (approval: TApproval) => {
    console.log('审批状态已更新:', approval.status);
    
    // 根据状态执行不同操作
    if (approval.status === EApprovalState.APPROVED) {
      console.log('审批已通过!');
      // 执行通过后的逻辑
    } else if (approval.status === EApprovalState.REJECTED) {
      console.log('审批已拒绝!');
      // 执行拒绝后的逻辑
    }
  };

  return (
    <ApprovalDetail 
      approvalId="12345"
      onApprovalChange={handleApprovalChange}
    />
  );
}

打印模式(隐藏操作)

import { ApprovalDetail } from '@aftership/approval-widget-kit';

function PrintableApproval() {
  const handlePrint = () => {
    window.print();
  };

  return (
    <div>
      <button onClick={handlePrint}>打印</button>
      
      {/* 打印时不显示操作按钮 */}
      <ApprovalDetail 
        approvalId="12345"
        isShowOperation={false}
      />
    </div>
  );
}

其他工具组件

UserSelect - 用户选择器

import { UserSelect } from '@aftership/approval-widget-kit';

function MyForm() {
  return (
    <UserSelect 
      placeholder="Please select users"
      mode="multiple"
      filterUser={['user1', 'user2']} // 过滤掉特定用户
    />
  );
}

UserTag - 用户标签

import { UserTag } from '@aftership/approval-widget-kit';

function UserDisplay() {
  return <UserTag email="[email protected]" />;
}

CopyButton - 复制按钮

import { CopyButton } from '@aftership/approval-widget-kit';

function CopyDemo() {
  return <CopyButton text="要复制的文本内容" />;
}

RichEditor - 富文本编辑器

import { RichEditor } from '@aftership/approval-widget-kit';
import { useRef } from 'react';

function EditorDemo() {
  const editorRef = useRef(null);

  return (
    <RichEditor 
      editorRef={editorRef}
      placeholder="请输入内容..."
    />
  );
}

🔧 工具函数

请求工具

组件库内置统一请求工具,自动处理认证头和环境配置。

import { request, get, post, put, del } from '@aftership/approval-widget-kit';
import type { IResponse } from '@aftership/approval-widget-kit';

// GET 请求
const fetchUser = async () => {
  const data = await get<IResponse<UserData>>('/api/users/123');
  return data;
};

// POST 请求
const createApproval = async () => {
  const result = await post<IResponse>('/api/approvals', { 
    title: 'New Approval',
    description: 'Approval description'
  });
  return result;
};

// PUT 请求
const updateApproval = async () => {
  const result = await put<IResponse>('/api/approvals/123', {
    status: 'approved'
  });
  return result;
};

// DELETE 请求
const deleteApproval = async () => {
  await del('/api/approvals/123');
};

// 自定义请求
const customRequest = async () => {
  const response = await request('/api/custom', {
    method: 'POST',
    headers: { 'X-Custom-Header': 'value' },
    payload: { data: 'value' }
  });
  return response;
};

工具函数

import { 
  camelCaseToShow,  // 驼峰转展示文本
  onError,          // 统一错误处理
} from '@aftership/approval-widget-kit';

// 驼峰转展示文本
const displayText = camelCaseToShow('approvalStatus'); // "Approval Status"

// 统一错误处理
try {
  await someApiCall();
} catch (error) {
  onError(error); // 自动显示友好错误提示
}

🎯 类型定义

核心类型

import type {
  // 审批相关
  TApproval,                    // 审批单数据
  TApprovalNode,                // 审批节点
  ApprovalComment,              // 审批评论
  TAttachments,                 // 附件
  ApprovalError,                // 错误类型
  
  // 枚举
  EApprovalState,               // 审批状态
  EApprovalStatusOperation,     // 审批操作
  ESignType,                    // 签名类型
  ERequireApproverField,        // 审批人必填字段
  
  // 请求相关
  IResponse,                    // 响应类型
  TMethod,                      // 请求方法
} from '@aftership/approval-widget-kit';

枚举说明

EApprovalState - 审批状态

enum EApprovalState {
  PENDING = 'pending',       // 待审批
  APPROVED = 'approved',     // 已通过
  REJECTED = 'rejected',     // 已拒绝
  CANCELLED = 'cancelled',   // 已取消
  EXPIRED = 'expired',       // 已过期
}

EApprovalStatusOperation - 审批操作

enum EApprovalStatusOperation {
  APPROVE = 'approve',       // 通过
  REJECT = 'reject',         // 拒绝
  REASSIGN = 'reassign',     // 转交
  ADD = 'add',               // 加签
  CANCEL = 'cancel',         // 取消
}

类型示例

import type { TApproval, EApprovalState } from '@aftership/approval-widget-kit';

// 审批单数据结构
const approval: TApproval = {
  id: '12345',
  title: '采购申请',
  status: EApprovalState.PENDING,
  createTime: '2024-01-01T00:00:00Z',
  creator: {
    id: 'user1',
    name: 'John Doe',
    email: '[email protected]'
  },
  // ... 更多字段
};

🏗️ 开发

本地开发

# 安装依赖
pnpm install

# 开发模式(监听文件变化自动重新构建)
pnpm dev

# 构建
pnpm build

# 类型检查
pnpm typecheck

在 Monorepo 中使用

如果你的项目也是 monorepo,可以使用 workspace 协议:

{
  "dependencies": {
    "@aftership/approval-widget-kit": "workspace:*"
  }
}

📝 注意事项

必需的依赖

确保你的项目已安装以下 peer dependencies:

{
  "peerDependencies": {
    "react": "^17.0.0 || ^18.0.0",
    "react-dom": "^17.0.0 || ^18.0.0",
    "antd": "^5.0.0",
    "react-query": "^3.0.0",
    "@aftership/automizely-product-auth": "^1.23.0"
  }
}

前置条件检查清单

使用组件库前,确保:

  • ✅ 应用已包裹 AuthProviderEmployee
  • ✅ 应用已包裹 QueryClientProvider
  • ✅ 已导入样式 @aftership/approval-widget-kit/dist/index.css
  • ✅ 设置了 process.env.APP_ENV 环境变量(可选)

样式导入

重要:必须导入组件库的样式文件

// 在入口文件或组件中导入
import '@aftership/approval-widget-kit/dist/index.css';

环境变量

组件库会读取以下环境变量(可选):

# 应用环境(默认: production)
APP_ENV=development  # development | staging | production

🐛 故障排查

1. 样式丢失

现象: 组件显示不正常,缺少样式

原因: 未导入 CSS 文件

解决方案:

import '@aftership/approval-widget-kit/dist/index.css';

2. 认证失败

现象: 请求返回 401 错误

原因: 未包裹 AuthProviderEmployee 或配置错误

解决方案:

<AuthProviderEmployee 
  config={{ 
    forceLogin: true,
    clientId: 'your-client-id' 
  }}
>
  {/* 你的应用 */}
</AuthProviderEmployee>

3. React Query 错误

现象: 组件报错 "No QueryClient set"

原因: 未包裹 QueryClientProvider

解决方案:

import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

<QueryClientProvider client={queryClient}>
  {/* 你的应用 */}
</QueryClientProvider>

4. TypeScript 类型错误

现象: 导入类型时报错

原因: 可能是组件库版本问题或构建产物缺失

解决方案:

# 清理并重新安装
rm -rf node_modules
pnpm install

5. 打包体积过大

优化方案:

  1. 按需导入组件:
// ✅ 推荐:按需导入
import { ApprovalDetail } from '@aftership/approval-widget-kit';

// ❌ 避免:全量导入
import * as ApprovalKit from '@aftership/approval-widget-kit';
  1. 使用 Tree-shaking(确保你的打包工具支持)

📖 完整示例

示例 1: 基础审批详情页

import React from 'react';
import { ApprovalDetail } from '@aftership/approval-widget-kit';
import '@aftership/approval-widget-kit/dist/index.css';
import { PageHeader, Button } from 'antd';
import { useNavigate, useSearchParams } from 'react-router-dom';

function ApprovalDetailPage() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const approvalId = searchParams.get('approvalId') || '';

  const handleBack = () => {
    navigate('/approvals');
  };

  return (
    <PageHeader
      title="Approval Detail"
      onBack={handleBack}
      extra={[
        <Button key="print" onClick={() => window.print()}>
          Print
        </Button>
      ]}
    >
      <ApprovalDetail approvalId={approvalId} />
    </PageHeader>
  );
}

export default ApprovalDetailPage;

示例 2: 打印视图

import React, { useRef } from 'react';
import { ApprovalDetail } from '@aftership/approval-widget-kit';
import { Button } from 'antd';

function PrintableApprovalPage({ approvalId }: { approvalId: string }) {
  const printRef = useRef<HTMLDivElement>(null);

  const handlePrint = () => {
    // 隐藏其他内容,只显示审批详情
    const printContent = printRef.current;
    if (printContent) {
      const printWindow = window.open('', '', 'width=800,height=600');
      printWindow?.document.write(printContent.innerHTML);
      printWindow?.document.close();
      printWindow?.print();
    }
  };

  return (
    <div>
      <Button onClick={handlePrint}>打印审批单</Button>
      
      <div ref={printRef}>
        <ApprovalDetail 
          approvalId={approvalId}
          isShowOperation={false}  // 打印时隐藏操作按钮
        />
      </div>
    </div>
  );
}

示例 3: 审批状态监控

import React, { useState } from 'react';
import { ApprovalDetail } from '@aftership/approval-widget-kit';
import type { TApproval, EApprovalState } from '@aftership/approval-widget-kit';
import { message, Badge } from 'antd';

function ApprovalMonitor({ approvalId }: { approvalId: string }) {
  const [status, setStatus] = useState<EApprovalState>();

  const handleApprovalChange = (approval: TApproval) => {
    setStatus(approval.status);
    
    // 根据状态显示不同提示
    switch (approval.status) {
      case EApprovalState.APPROVED:
        message.success('审批已通过!');
        break;
      case EApprovalState.REJECTED:
        message.error('审批已拒绝!');
        break;
      case EApprovalState.CANCELLED:
        message.warning('审批已取消!');
        break;
    }
  };

  return (
    <div>
      <div style={{ marginBottom: 16 }}>
        当前状态: <Badge status="processing" text={status} />
      </div>
      
      <ApprovalDetail 
        approvalId={approvalId}
        onApprovalChange={handleApprovalChange}
      />
    </div>
  );
}

🤝 贡献

欢迎提交 Issue 和 Pull Request!

开发流程

  1. Fork 本仓库
  2. 创建功能分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'feat: Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 提交 Pull Request

📄 License

MIT © AfterShip Team

🔗 相关链接

📮 联系我们

如有问题或建议,欢迎通过以下方式联系:

  • 提交 GitHub Issue
  • 联系 AfterShip 团队