UIPackage
Menu

Framework

Change language

Boilerplate repo

Vendor Supplier Portal

blockdashboard

Supplier and vendor relationship workbench with SLA scorecard metrics, purchase order status, and contracted pricing catalog.

Also available for React ->

Installation

$npx shadcn-vue@latest add https://uipkge.dev/r/vue/vendor-supplier-portal.json
Named registry:npx shadcn-vue@latest add @uipkge/vendor-supplier-portalInstalls to:app/components/blocks/vendor-supplier-portal/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
vendorNamestring'Apex Precision Engineering Ltd'optional
vendorIdstring'VND-2026-9901'optional
tierstring'Strategic Tier-1 Supplier'optional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

VendorPO
interface VendorPO {
  id: string
  poNumber: string
  issueDate: string
  deliveryDeadline: string
  linesCount: number
  totalAmount: number
  status: 'acknowledged' | 'in_production' | 'shipped' | 'pending_ack'
}
ContractedCatalogItem
interface ContractedCatalogItem {
  id: string
  sku: string
  name: string
  moq: number
  contractedPrice: number
  leadTimeDays: number
  validUntil: string
}

npm dependencies

Files installed (2)

  • app/components/blocks/vendor-supplier-portal/VendorSupplierPortal.vue10.6 kB
    <script setup lang="ts">
    import { ref } from 'vue'
    import { Download, FileSpreadsheet, ShieldCheck } from 'lucide-vue-next'
    import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'
    import { Button } from '@/components/ui/button'
    import { Badge } from '@/components/ui/badge'
    import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
    
    export interface VendorPO {
      id: string
      poNumber: string
      issueDate: string
      deliveryDeadline: string
      linesCount: number
      totalAmount: number
      status: 'acknowledged' | 'in_production' | 'shipped' | 'pending_ack'
    }
    
    export interface ContractedCatalogItem {
      id: string
      sku: string
      name: string
      moq: number
      contractedPrice: number
      leadTimeDays: number
      validUntil: string
    }
    
    export interface VendorPortalProps {
      vendorName?: string
      vendorId?: string
      tier?: string
    }
    
    const props = withDefaults(defineProps<VendorPortalProps>(), {
      vendorName: 'Apex Precision Engineering Ltd',
      vendorId: 'VND-2026-9901',
      tier: 'Strategic Tier-1 Supplier',
    })
    
    const activeTab = ref<'orders' | 'catalog'>('orders')
    
    const orders = ref<VendorPO[]>([
      {
        id: 'po-1',
        poNumber: 'PO-2026-8840',
        issueDate: '2026-08-18',
        deliveryDeadline: '2026-08-28',
        linesCount: 4,
        totalAmount: 48500,
        status: 'in_production',
      },
      {
        id: 'po-2',
        poNumber: 'PO-2026-8855',
        issueDate: '2026-08-22',
        deliveryDeadline: '2026-09-02',
        linesCount: 2,
        totalAmount: 19200,
        status: 'pending_ack',
      },
      {
        id: 'po-3',
        poNumber: 'PO-2026-8812',
        issueDate: '2026-08-10',
        deliveryDeadline: '2026-08-21',
        linesCount: 6,
        totalAmount: 82400,
        status: 'shipped',
      },
    ])
    
    const catalog = ref<ContractedCatalogItem[]>([
      {
        id: 'cat-1',
        sku: 'SKU-VALVE-99',
        name: 'High-Pressure Hydraulic Valve 3/8"',
        moq: 50,
        contractedPrice: 185.0,
        leadTimeDays: 7,
        validUntil: '2027-06-30',
      },
      {
        id: 'cat-2',
        sku: 'SKU-SEAL-04',
        name: 'Fluorocarbon O-Ring Flange Kit (Pack of 50)',
        moq: 100,
        contractedPrice: 24.5,
        leadTimeDays: 3,
        validUntil: '2027-06-30',
      },
      {
        id: 'cat-3',
        sku: 'SKU-GAUGE-12',
        name: 'Digital Calibration Pressure Gauge 0-600 PSI',
        moq: 20,
        contractedPrice: 420.0,
        leadTimeDays: 14,
        validUntil: '2027-06-30',
      },
    ])
    
    function acknowledgePO(id: string) {
      const target = orders.value.find((o) => o.id === id)
      if (target) {
        target.status = 'acknowledged'
      }
    }
    </script>
    
    <template>
      <div data-slot="vendor-supplier-portal" class="w-full space-y-6">
        <!-- Header / Supplier SLA Scorecard -->
        <Card>
          <CardHeader class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
            <div class="space-y-1">
              <div class="flex items-center gap-2">
                <span class="text-foreground font-mono text-sm font-semibold">{{ vendorId }}</span>
                <Badge variant="outline">{{ tier }}</Badge>
                <Badge variant="secondary" class="gap-1">
                  <ShieldCheck class="text-foreground size-3" />
                  ISO 9001:2015 Certified
                </Badge>
              </div>
              <CardTitle class="text-xl">{{ vendorName }}</CardTitle>
              <CardDescription> Supplier SLA Performance Scorecard & Active Purchase Order Console </CardDescription>
            </div>
    
            <div class="flex items-center gap-2">
              <Button variant="outline" size="sm" class="gap-1.5">
                <FileSpreadsheet class="size-3.5" />
                Export Statement
              </Button>
              <Button variant="default" size="sm" class="gap-1.5">
                <Download class="size-3.5" />
                Download MSA Contract
              </Button>
            </div>
          </CardHeader>
    
          <CardContent class="border-border grid grid-cols-1 gap-4 border-t pt-4 sm:grid-cols-4">
            <!-- On Time Delivery -->
            <div class="border-border space-y-1 rounded-lg border p-3">
              <div class="text-muted-foreground text-xs font-medium">ON-TIME DELIVERY (OTD)</div>
              <div class="flex items-baseline justify-between pt-1">
                <div class="font-mono text-xl font-semibold">98.6%</div>
                <span class="text-muted-foreground font-mono text-xs">Target: 95.0%</span>
              </div>
            </div>
    
            <!-- QA Acceptance -->
            <div class="border-border space-y-1 rounded-lg border p-3">
              <div class="text-muted-foreground text-xs font-medium">QA ACCEPTANCE RATE</div>
              <div class="flex items-baseline justify-between pt-1">
                <div class="font-mono text-xl font-semibold">99.8%</div>
                <span class="text-muted-foreground font-mono text-xs">&lt; 0.2% NCR</span>
              </div>
            </div>
    
            <!-- Avg Lead Time -->
            <div class="border-border space-y-1 rounded-lg border p-3">
              <div class="text-muted-foreground text-xs font-medium">AVG FULFILLMENT LEAD TIME</div>
              <div class="pt-1 font-mono text-xl font-semibold">5.4 Days</div>
            </div>
    
            <!-- Total YTD Volume -->
            <div class="border-border space-y-1 rounded-lg border p-3">
              <div class="text-muted-foreground text-xs font-medium">ACTIVE PURCHASE VOLUME</div>
              <div class="pt-1 font-mono text-xl font-semibold">$150,100 USD</div>
            </div>
          </CardContent>
        </Card>
    
        <!-- Navigation Tabs & Content Card -->
        <Card>
          <CardHeader class="flex flex-col gap-3 pb-3 sm:flex-row sm:items-center sm:justify-between">
            <div class="flex items-center gap-2">
              <Button :variant="activeTab === 'orders' ? 'default' : 'outline'" size="sm" @click="activeTab = 'orders'">
                Active Purchase Orders ({{ orders.length }})
              </Button>
              <Button :variant="activeTab === 'catalog' ? 'default' : 'outline'" size="sm" @click="activeTab = 'catalog'">
                Contracted Catalog Prices ({{ catalog.length }})
              </Button>
            </div>
    
            <div class="text-muted-foreground text-xs">
              Payment Terms: <span class="text-foreground font-medium">Net-45 Direct ACH Wire</span>
            </div>
          </CardHeader>
    
          <CardContent class="p-0">
            <!-- Table for Orders -->
            <Table v-if="activeTab === 'orders'">
              <TableHeader>
                <TableRow>
                  <TableHead class="w-[180px]">PO Reference</TableHead>
                  <TableHead>Issue Date</TableHead>
                  <TableHead>Delivery Deadline</TableHead>
                  <TableHead class="text-right">Line Items</TableHead>
                  <TableHead class="text-right">Total Order Value</TableHead>
                  <TableHead>Fulfillment Status</TableHead>
                  <TableHead class="w-[140px] text-right">Action</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                <TableRow v-for="order in orders" :key="order.id">
                  <TableCell>
                    <div class="text-foreground font-mono font-semibold">{{ order.poNumber }}</div>
                  </TableCell>
    
                  <TableCell class="text-muted-foreground font-mono text-xs">
                    {{ order.issueDate }}
                  </TableCell>
    
                  <TableCell class="text-foreground font-mono text-xs font-medium">
                    {{ order.deliveryDeadline }}
                  </TableCell>
    
                  <TableCell class="text-right font-mono text-sm"> {{ order.linesCount }} SKUs </TableCell>
    
                  <TableCell class="text-foreground text-right font-mono text-sm font-semibold">
                    ${{ order.totalAmount.toLocaleString() }} USD
                  </TableCell>
    
                  <TableCell>
                    <Badge
                      :variant="
                        order.status === 'shipped'
                          ? 'default'
                          : order.status === 'in_production'
                            ? 'secondary'
                            : order.status === 'acknowledged'
                              ? 'outline'
                              : 'outline'
                      "
                      class="capitalize"
                    >
                      {{ order.status.replace('_', ' ') }}
                    </Badge>
                  </TableCell>
    
                  <TableCell class="text-right">
                    <Button
                      v-if="order.status === 'pending_ack'"
                      size="sm"
                      variant="default"
                      class="h-7 text-xs"
                      @click="acknowledgePO(order.id)"
                    >
                      Acknowledge PO
                    </Button>
                    <span v-else class="text-muted-foreground text-xs"> Processed </span>
                  </TableCell>
                </TableRow>
              </TableBody>
            </Table>
    
            <!-- Table for Catalog Items -->
            <Table v-else>
              <TableHeader>
                <TableRow>
                  <TableHead class="w-[280px]">Product / Description</TableHead>
                  <TableHead>SKU Reference</TableHead>
                  <TableHead class="text-right">Min Order Qty (MOQ)</TableHead>
                  <TableHead class="text-right">Contracted Unit Price</TableHead>
                  <TableHead class="text-right">Standard Lead Time</TableHead>
                  <TableHead>Contract Validity</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                <TableRow v-for="item in catalog" :key="item.id">
                  <TableCell>
                    <div class="text-foreground font-medium">{{ item.name }}</div>
                  </TableCell>
    
                  <TableCell>
                    <span class="font-mono text-xs font-semibold">{{ item.sku }}</span>
                  </TableCell>
    
                  <TableCell class="text-right font-mono text-sm"> {{ item.moq }} units </TableCell>
    
                  <TableCell class="text-foreground text-right font-mono text-sm font-semibold">
                    ${{ item.contractedPrice.toFixed(2) }}
                  </TableCell>
    
                  <TableCell class="text-muted-foreground text-right font-mono text-sm">
                    {{ item.leadTimeDays }} Days
                  </TableCell>
    
                  <TableCell>
                    <span class="text-muted-foreground font-mono text-xs">Valid to {{ item.validUntil }}</span>
                  </TableCell>
                </TableRow>
              </TableBody>
            </Table>
          </CardContent>
    
          <CardFooter class="border-border text-muted-foreground flex items-center justify-between border-t py-3 text-xs">
            <div>Supplier contract SLA terms audited quarterly per ISO 9001 compliance standards.</div>
            <div class="text-foreground font-medium">
              Vendor Status: <span class="text-foreground">Active & In Good Standing</span>
            </div>
          </CardFooter>
        </Card>
      </div>
    </template>
    
  • app/components/blocks/vendor-supplier-portal/index.ts0.2 kB

Raw manifest:https://uipkge.dev/r/vue/vendor-supplier-portal.json