> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 构建团队带薪休假（PTO）管理工具

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="构建团队 PTO 跟踪工具" description="描述你的工具，Devin 将端到端构建、测试并验证它。" prompt="在 /internal/pto 路径下为我们的团队构建一个内部 PTO 跟踪器。员工通过日期范围、类型（vacation：年假，sick：病假，personal：事假）以及可选备注提交休假申请。经理可以看到待处理请求队列并进行批准或拒绝。日历视图显示谁在休假，并按类型进行颜色区分。仪表盘显示每位员工的 PTO 余额（20 天/年）。员工不能超出其余额或与现有 PTO 重叠。如有队友已在休假，需要给出警告。通过 SLACK_WEBHOOK_URL 在提交以及批准/拒绝时发送 Slack 通知。使用我们的 Next.js 应用、Prisma ORM，以及现有的 DataTable 和 Calendar 组件。在编写代码之前，先给出你的方案纲要供审阅。为余额计算、重叠检测以及审批工作流编写测试。在浏览器中测试每个页面和流程——提交、批准、拒绝、检查日历、验证仪表盘。在端到端一切正常之前不要打开 PR。" category="功能开发" features="" />

<div className="uc-detail-wrapper">
  <Tip>不想手动设置？将此页面的链接粘贴到 Devin 会话中，要求它帮你全部设置好。</Tip>

  <Steps>
    <Step title="（可选）使用 Ask Devin 为代码库划定范围">
      如果你的应用中已经有内部工具，在编写规格说明之前，可以使用 [Ask Devin](https://app.devin.ai/search?utm_source=docs\&utm_medium=use-case-gallery) 来了解现有的实现模式。这样做在你希望新工具与现有架构保持一致时尤其有用：

      <PromptBlock agent="ada">
        ```txt Scope internal tools architecture theme={null}
        Show me how our existing internal tools are structured:
        1. What pages exist under /internal/ and how are they laid out?
        2. How do internal pages handle auth and role-based access?
        3. Which shared UI components do they use (tables, forms, modals)?
        4. How are database migrations structured in our Prisma schema?
        5. Are there any existing notification patterns (Slack, email)?
        ```
      </PromptBlock>

      根据这些回答，在你的规格说明中补充具体的文件引用、组件名称和模式，这样 Devin 构建的新工具就能与你现有的内部工具保持一致。你也可以直接在 Ask Devin 中发起 Devin 会话，它会把已学到的全部内容作为上下文带入。
    </Step>

    <Step title="编写详细规格说明">
      内部工具——PTO (带薪休假) 追踪器、管理面板、数据脚本、CLI 工具——至关重要，却很少被优先处理。它们非常适合交给 Devin，因为需求定义清晰，使用人就是你的团队，而且相比像素级完美的设计，“能正确运行”更重要。

      请具体说明该工具做什么、会存储哪些数据，以及会接入哪些服务。你提供的细节越多，首个版本就越接近你的实际需求。

      <PromptBlock>
        ```txt Build a team PTO tracker theme={null}
        Build an internal PTO tracker for our team under /internal/pto.

        ## Features
        - Employees can submit time-off requests with a date range, type
          (vacation, sick, or personal), and an optional note
        - Managers see a queue of pending requests and can approve or deny
          each one
        - A calendar view shows who's out on which days, color-coded by type
        - A dashboard shows every employee's PTO balance: total days,
          used days, remaining days, and pending requests
        - Each employee gets 20 PTO days per year
        - Employees can't request more days than their remaining balance
        - Requests can't overlap with their own existing approved PTO
        - Show a warning (not a block) if teammates are already out during
          the same dates

        ## Notifications
        - Slack notification to the manager when a request is submitted
        - Slack notification to the employee when it's approved or denied
        - Use SLACK_WEBHOOK_URL from env vars

        ## Technical notes
        - Use our existing Next.js app and Prisma ORM
        - Follow the layout pattern in /internal/users
        - Reuse DataTable and Calendar components from src/components/ui/

        ## Planning
        - Before writing code, outline your implementation plan and share
          it with me for review

        ## Testing
        - Write tests for balance calculations, date overlap detection,
          and the approval workflow
        - After implementing, spin up the dev server and test every page
          and flow in the browser — submit a request, approve it, deny one,
          check the calendar, verify dashboard numbers, and test edge cases
          like overlapping dates and exceeding balance
        - Do not open a PR until everything works end-to-end
        ```
      </PromptBlock>

      你也可以使用 Ask Devin 来迭代完善你的需求说明——粘贴一个初稿，让它根据你的代码库找出遗漏之处或提出改进建议。
    </Step>

    <Step title="添加凭证">
      通过 [Secrets](/zh/product-guides/secrets) 向 Devin 传递所需的任何 API key 或令牌——在本例中是 Slack webhook URL。

      最简单的方法是在开始会话之前将它们存储为组织机密：

      1. 前往 **Settings > Secrets** 并添加 `SLACK_WEBHOOK_URL`
      2. Devin 以环境变量的形式访问机密，因此这些值不会被硬编码进你的源代码中。

      <Note>组织机密必须在启动会话**之前**添加——它们会在会话启动时被注入。或者，你也可以在会话期间通过聊天提供机密；当 Devin 发现缺失的环境变量时，它也会主动向你索取所需的任何凭证。</Note>
    </Step>

    <Step title="通过斜杠命令引导会话">
      会话开始后，你可以使用斜杠命令来引导 Devin 的工作流：

      * **`/plan`** — 让 Devin 在编写任何代码之前先创建一个详细的实现计划。在它开始构建之前，先审查该计划并提出修改建议。
      * **`/test`** — 让 Devin 运行所有测试并验证其工作成果。在每个主要里程碑之后使用此命令，以便及早发现问题。
      * **`/review`** — 让 Devin 在发起 PR 之前，自行审查代码中的错误、边界情况和风格问题。

      这些命令在会话中的任何阶段都可以使用——在开始时使用 `/plan`，每个功能构建完成后使用 `/test`，在发起最终 PR 之前使用 `/review`。
    </Step>

    <Step title="Devin 负责构建并验证其可用性">
      Devin 将内部工具视为正式生产功能的一部分——它会编写代码、添加测试，然后在其内置浏览器中打开应用，验证 UI 是否能够端到端正常工作。

      1. **梳理你的代码库** —— 找到你的 `DataTable` 和 `Calendar` 组件，阅读你的 Prisma schema，并研究现有的 `/internal/` 页面布局
      2. **创建数据库迁移** —— 通过 Prisma 添加 `pto_requests` 和 `pto_balances` 表
      3. **构建页面** —— 在 `/internal/pto` 下创建请求提交表单、经理审批队列、日历视图和余额仪表盘
      4. **集成 Slack** —— 在提交请假请求以及请求被批准或拒绝时发送 webhook 通知
      5. **编写测试** —— 为带薪休假余额 (PTO balance) 计算和日期重叠检测编写单元测试，为请求端点编写 API 测试，为审批工作流编写集成测试
      6. **在其浏览器中打开应用** —— 访问每个页面，提交一条测试带薪休假 (PTO) 请求，从经理视图中批准它，验证日历是否更新，检查仪表盘数据，并测试诸如日期重叠和超出余额等边界情况
      7. **打开一个 PR** —— 交付所有内容：迁移、种子脚本、应用代码、测试，以及解释如何使用该工具的 README 小节

      通过浏览器验证可以发现自动化测试遗漏的问题——例如错乱的表单布局、虽然渲染出来但不响应点击的日历，或者在成功后不会清空表单的提交按钮。
    </Step>

    <Step title="扩展你的工具功能">
      Once the base tool works, add features in follow-up sessions:

      <PromptBlock>
        ```txt 添加带薪休假（PTO）冲突检测 theme={null}
        当员工提交带薪休假（PTO）申请时，检查该员工所在团队中是否有人
        已在相同日期请假。在界面中显示警告：
        “你所在团队中还有 2 人在 11 月 20–22 日休假。”不要拦截这条申请，
        只需提示时间重叠，方便经理进行排班和规划。
        ```
      </PromptBlock>

      <PromptBlock>
        ```txt 为人力资源（HR）构建 CSV 导出功能 theme={null}
        在 PTO 仪表盘上添加一个按钮，将本季度所有已批准的休假
        导出为 CSV。列包括：员工姓名、日期、类型、已用天数、
        剩余余额。人力资源（HR）每月下载一次用于薪资处理。
        ```
      </PromptBlock>
    </Step>

    <Step title="通过 Devin Review 审查该拉取请求（PR）">
      Devin 创建 PR 后，使用 [Devin Review](https://app.devin.ai/review?utm_source=docs\&utm_medium=use-case-gallery) 来审查这些更改。Devin Review 对你的代码库上下文有完整的理解，能够在整个 diff 中发现缺陷、安全问题以及风格不一致之处。
    </Step>
  </Steps>
</div>
