浏览代码

FEATURE NOT COMPLETED: implent the new trading screen

gdias 1 月之前
父节点
当前提交
0fd3533802

文件差异内容过多而无法显示
+ 527 - 60
package-lock.json


+ 3 - 0
package.json

@@ -24,5 +24,8 @@
 		"svelte": "^5.0.0",
 		"tailwindcss": "^3.4.0",
 		"vite": "^7.0.4"
+	},
+	"dependencies": {
+		"layerchart": "^1.0.12"
 	}
 }

+ 22 - 39
src/lib/components/commodities/RegisterCommodity.svelte

@@ -4,6 +4,8 @@
     let descricao = "";
     let quantidade = "";
     let preco = "";
+    let nome = "";
+    let registro = "";
     let vencimentoPagamento = "";
     let dataLimiteEntrega = "";
     let cpr = false;
@@ -68,66 +70,47 @@
 
     <!-- Descrição, Quantidade, Preço -->
     <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Descrição</label>
+            <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nome *</label>
         <input
-          bind:value={descricao}
+          type="text"
+          bind:value={nome}
           class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="Descreva a commodity"
+          placeholder="Nome da commodity"
         />
       </div>
       <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Quantidade</label>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Descrição</label>
         <input
-          type="number"
-          min="0"
-          step="1"
-          bind:value={quantidade}
+          bind:value={descricao}
           class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="0"
+          placeholder="Descreva a commodity"
         />
       </div>
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Preço (R$)</label>
+      
+    </div>
+          <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Numero de registro</label>
         <input
-          type="number"
-          min="0"
-          step="0.01"
-          bind:value={preco}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-          placeholder="0,00"
+          bind:value={registro}
+          class="mt-1 block w-1/3 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
+          placeholder="Numero de registro da commodity"
         />
       </div>
-    </div>
 
     <!-- Vencimento do Pagamento, Data Limite da Entrega, CPR -->
     <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Vencimento do Pagamento</label>
-        <input
-          type="date"
-          bind:value={vencimentoPagamento}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        />
-      </div>
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Data Limite da Entrega</label>
-        <input
-          type="date"
-          bind:value={dataLimiteEntrega}
-          class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-400 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
-        />
-      </div>
+      
       <div class="flex items-end">
-        <label class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
+        <!-- <label class="flex items-center gap-2 text-gray-700 dark:text-gray-300">
           <input type="checkbox" bind:checked={cpr} class="accent-blue-600" />
           CPR
-        </label>
+        </label> -->
       </div>
     </div>
 
     <!-- Anexos / Arquivos -->
-    <div>
+    <!-- <div>
       <label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Anexos</label>
       <div
         class="mt-1 rounded border-2 border-dashed border-gray-300 dark:border-gray-600 p-6 text-center hover:border-blue-400 transition-colors"
@@ -169,7 +152,7 @@
           {/each}
         </ul>
       {/if}
-    </div>
+    </div> -->
 
     <div class="mt-6 flex justify-end">
       <button

+ 66 - 0
src/lib/components/trading/BoletaCompra.svelte

@@ -0,0 +1,66 @@
+<script>
+  import ModalBase from './ModalBase.svelte';
+  export let visible = false;
+  export let onClose = () => {};
+  export let state = '';
+  export let commodity = '';
+  let valorSaca = '';
+  let quantidade = '';
+  let referencia = 'BRL : 12';
+  let validade = '';
+  let calendario = '';
+  $: total = (Number(valorSaca) || 0) * (Number(quantidade) || 0);
+  function confirmar() {
+    const dados = { tipo: 'compra', valorSaca: Number(valorSaca)||0, quantidade: Number(quantidade)||0, referencia, total, validade, calendario, estado: state, commodity };
+    console.log('BoletaCompra confirmada', dados);
+    try { onClose?.(); } catch {}
+  }
+  function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n||0)); }
+</script>
+<ModalBase title="Boleta de Compra" {visible} {onClose}>
+  <div class="space-y-4">
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor/saca</label>
+        <input type="number" min="0" step="0.01" bind:value={valorSaca} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Quantidade em saca</label>
+        <input type="number" min="0" step="1" bind:value={quantidade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência</label>
+        <input type="text" bind:value={referencia} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência valor total</label>
+        <input value={formatBRL(total)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Validade</label>
+        <input type="date" bind:value={validade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Calendário</label>
+        <input type="date" bind:value={calendario} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-green-500" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
+        <input value={state} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
+        <input value={commodity} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+    </div>
+    <div class="flex justify-end">
+      <button class="px-4 py-2 rounded bg-green-600 hover:bg-green-700 text-white focus:outline-none focus:ring-2 focus:ring-green-500" on:click={confirmar}>Confirmar Compra</button>
+    </div>
+  </div>
+</ModalBase>

+ 66 - 0
src/lib/components/trading/BoletaVenda.svelte

@@ -0,0 +1,66 @@
+<script>
+  import ModalBase from './ModalBase.svelte';
+  export let visible = false;
+  export let onClose = () => {};
+  export let state = '';
+  export let commodity = '';
+  let valorSaca = '';
+  let quantidade = '';
+  let referencia = 'BRL : 12';
+  let validade = '';
+  let calendario = '';
+  $: total = (Number(valorSaca) || 0) * (Number(quantidade) || 0);
+  function confirmar() {
+    const dados = { tipo: 'venda', valorSaca: Number(valorSaca)||0, quantidade: Number(quantidade)||0, referencia, total, validade, calendario, estado: state, commodity };
+    console.log('BoletaVenda confirmada', dados);
+    try { onClose?.(); } catch {}
+  }
+  function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n||0)); }
+</script>
+<ModalBase title="Boleta de Venda" {visible} {onClose}>
+  <div class="space-y-4">
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Valor/saca</label>
+        <input type="number" min="0" step="0.01" bind:value={valorSaca} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Quantidade em saca</label>
+        <input type="number" min="0" step="1" bind:value={quantidade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência</label>
+        <input type="text" bind:value={referencia} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Referência valor total</label>
+        <input value={formatBRL(total)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Validade</label>
+        <input type="date" bind:value={validade} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Calendário</label>
+        <input type="date" bind:value={calendario} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-red-500" />
+      </div>
+    </div>
+    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Estado</label>
+        <input value={state} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+      <div>
+        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Commodity</label>
+        <input value={commodity} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+      </div>
+    </div>
+    <div class="flex justify-end">
+      <button class="px-4 py-2 rounded bg-red-600 hover:bg-red-700 text-white focus:outline-none focus:ring-2 focus:ring-red-500" on:click={confirmar}>Confirmar Venda</button>
+    </div>
+  </div>
+</ModalBase>

+ 72 - 0
src/lib/components/trading/GraficoCandlestick.svelte

@@ -0,0 +1,72 @@
+<script>
+  import { Chart, Svg, Axis, Points, Bars, Highlight, Tooltip } from 'layerchart';
+  import { scaleBand, scaleOrdinal } from 'd3-scale';
+
+  export let dadosMock = [];
+
+  const xScale = scaleBand().paddingInner(0.2);
+
+  $: dataSeries = (dadosMock || [])
+    .map((d) => ({ date: d.date || d.time, valor: Number(d.valor) }))
+    .filter((d) => d.date && Number.isFinite(d.valor));
+
+  $: ohlc = dataSeries.map((d, i) => {
+    const open = i > 0 ? dataSeries[i - 1].valor : d.valor;
+    const close = d.valor;
+    const high = Math.max(open, close);
+    const low = Math.min(open, close);
+    return { date: d.date, open, high, low, close };
+  });
+
+  function fmtDate(d) {
+    if (!d) return '';
+    if (typeof d === 'string') {
+      const m = d.match(/^(\d{4})-(\d{2})-(\d{2})/);
+      return m ? `${m[3]}/${m[2]}` : d;
+    }
+    const dt = d instanceof Date ? d : new Date(d);
+    return Number.isNaN(dt.getTime()) ? '' : dt.toLocaleDateString('pt-BR', { day: '2-digit', month: '2-digit' });
+  }
+
+  const tooltip = { mode: 'bisect-x' };
+  function fmtNum(n) {
+    return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(Number(n ?? 0));
+  }
+  const colorKey = (d) => (Number(d.close) < Number(d.open) ? 'desc' : 'asc');
+</script>
+
+<div class="h-[300px] p-4 border rounded bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 cursor-crosshair select-none">
+  <Chart
+    data={ohlc}
+    x="date"
+    xScale={xScale}
+    y={["high", "low"]}
+    yNice
+    c={colorKey}
+    cScale={scaleOrdinal()}
+    cDomain={["desc", "asc"]}
+    cRange={["#e41a1c", "#16a34a"]}
+    padding={{ left: 16, bottom: 36 }}
+    tooltip={tooltip}
+  >
+    <Svg>
+      <Axis placement="left" grid rule ticks={5} />
+      <Axis placement="bottom" rule ticks={Math.min(6, ohlc.length)} format={fmtDate} />
+      <Highlight rule stroke="#94a3b8" strokeWidth={1} strokeDasharray="3 3" />
+      <Points links r={0} c={colorKey} strokeWidth={1.5} strokeLinecap="round" strokeOpacity={0.7} />
+      <Bars y={(d) => [Number(d.open), Number(d.close)]} radius={4} c={colorKey} stroke="rgba(255,255,255,0.12)" fillOpacity={0.8} />
+    </Svg>
+
+    <Tooltip.Root let:data>
+      <div class="pointer-events-none rounded-md bg-gray-900/95 text-white shadow-lg ring-1 ring-black/12 px-3 py-2 text-xs">
+        <div class="font-semibold mb-1">{fmtDate(data?.date)}</div>
+        <div class="grid grid-cols-2 gap-x-3 gap-y-0.5">
+          <div class="opacity-70">Open</div><div>{fmtNum(data?.open)}</div>
+          <div class="opacity-70">Close</div><div>{fmtNum(data?.close)}</div>
+          <div class="opacity-70">High</div><div>{fmtNum(data?.high)}</div>
+          <div class="opacity-70">Low</div><div>{fmtNum(data?.low)}</div>
+        </div>
+      </div>
+    </Tooltip.Root>
+  </Chart>
+</div>

+ 23 - 0
src/lib/components/trading/ModalBase.svelte

@@ -0,0 +1,23 @@
+<script>
+  import { createEventDispatcher } from 'svelte';
+  export let title = '';
+  export let visible = false;
+  export let onClose = () => {};
+  const dispatch = createEventDispatcher();
+  function close() { try { onClose?.(); } catch {} dispatch('close'); }
+  function overlayClick(e) { if (e.target === e.currentTarget) close(); }
+</script>
+{#if visible}
+<div class="fixed inset-0 z-50 flex items-center justify-center">
+  <div class="absolute inset-0 bg-black/50" on:click={overlayClick}></div>
+  <div class="relative bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 w-full max-w-lg mx-4">
+    <div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
+      <h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">{title}</h3>
+      <button class="p-1 rounded text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200" on:click={close}>✕</button>
+    </div>
+    <div class="p-4">
+      <slot />
+    </div>
+  </div>
+</div>
+{/if}

+ 5 - 17
src/lib/components/trading/SellPanel.svelte

@@ -5,9 +5,7 @@
 
   const dispatch = createEventDispatcher();
 
-  let tab = 'market';
   let amountFiat = '';
-  let limitPrice = '';
   let selectedTokenId = tokens?.[0]?.id ?? null;
 
   function formatBRL(n) {
@@ -19,19 +17,16 @@
 
   $: selectedToken = tokens.find(t => t.id === selectedTokenId);
   $: refPriceByToken = selectedToken?.price ?? referencePrice;
-  $: priceUsed = tab === 'limit' ? Number(limitPrice) : Number(refPriceByToken);
   $: numericFiat = Number(amountFiat) || 0;
-  $: computedTokensRaw = (numericFiat && priceUsed) ? numericFiat / priceUsed : 0;
-  $: computedTokens = Math.floor(computedTokensRaw);
+  const FIXED_AMOUNT = 1;
 
   function confirm() {
-    const price = priceUsed;
+    const price = numericFiat;
     const total = numericFiat;
-    const amount = computedTokens;
+    const amount = FIXED_AMOUNT;
     if (!price || !total || !amount) return;
-    dispatch('confirm', { type: tab, price, amount, total, tokenId: selectedToken?.id });
+    dispatch('confirm', { type: 'market', price, amount, total, tokenId: selectedToken?.id });
     amountFiat = '';
-    limitPrice = '';
   }
 </script>
 
@@ -52,13 +47,6 @@
       </select>
     </div>
 
-    {#if tab === 'limit'}
-      <div>
-        <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Preço limite (R$)</label>
-        <input type="number" min="0" step="0.01" bind:value={limitPrice} class="mt-1 block w-full rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
-      </div>
-    {/if}
-
     <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">EasyCoin (R$)</label>
@@ -66,7 +54,7 @@
       </div>
       <div>
         <label class="block text-sm font-medium text-gray-700 dark:text-gray-300">EasyToken (inteiros)</label>
-        <input value={formatEasyToken(computedTokens || 0)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
+        <input value={formatEasyToken(FIXED_AMOUNT)} readonly class="mt-1 block w-full rounded border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/40 text-gray-900 dark:text-gray-200 px-3 py-2" />
       </div>
     </div>
 

+ 43 - 0
src/lib/components/trading/TabelaOrdens.svelte

@@ -0,0 +1,43 @@
+<script>
+  import { ordensCompra, ordensVenda, ultimaVenda } from '$lib/mock/ordens.js';
+  function formatBRL(n) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(Number(n || 0)); }
+  function formatQty(n) { return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(Number(n || 0)); }
+</script>
+<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm">
+  <div class="px-4 py-2 bg-yellow-100 dark:bg-yellow-900/40 border-b border-yellow-300 dark:border-yellow-700 text-sm text-yellow-900 dark:text-yellow-200">
+    <div class="flex items-center justify-between">
+      <span>Última Venda</span>
+      <span class="font-medium">{formatBRL(ultimaVenda?.valor)} · {formatQty(ultimaVenda?.quantidade)}</span>
+    </div>
+  </div>
+  <div class="grid grid-cols-2 divide-x divide-gray-200 dark:divide-gray-700">
+    <div class="p-4">
+      <div class="flex items-center justify-between mb-2">
+        <h3 class="text-sm font-semibold text-green-600">Ordem de Compra</h3>
+        <div class="text-xs text-gray-500">VALOR · QUANTIDADE</div>
+      </div>
+      <div class="space-y-1">
+        {#each ordensCompra as o}
+        <div class="flex items-center justify-between text-sm">
+          <span class="text-green-600">{formatBRL(o.valor)}</span>
+          <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
+        </div>
+        {/each}
+      </div>
+    </div>
+    <div class="p-4">
+      <div class="flex items-center justify-between mb-2">
+        <h3 class="text-sm font-semibold text-red-600">Ordem de Venda</h3>
+        <div class="text-xs text-gray-500">VALOR · QUANTIDADE</div>
+      </div>
+      <div class="space-y-1">
+        {#each ordensVenda as o}
+        <div class="flex items-center justify-between text-sm">
+          <span class="text-red-600">{formatBRL(o.valor)}</span>
+          <span class="text-gray-700 dark:text-gray-200">{formatQty(o.quantidade)}</span>
+        </div>
+        {/each}
+      </div>
+    </div>
+  </div>
+</div>

+ 1 - 0
src/lib/layout/Header.svelte

@@ -19,6 +19,7 @@
     {/if}
   </div>
   <div class="flex items-center mt-2 md:mt-0 space-x-4">
+    <slot name="extra" />
     <div class="flex items-center text-gray-500 dark:text-gray-300 text-sm">
       {#each breadcrumb as item, i}
         <span class="{item.active ? 'text-gray-900 dark:text-gray-100 font-medium' : ''}">{item.label}</span>

+ 28 - 0
src/lib/mock/ordens.js

@@ -0,0 +1,28 @@
+export const ordensCompra = [
+  { valor: 9.98, quantidade: 10000 },
+  { valor: 9.99, quantidade: 20000 },
+  { valor: 10.0, quantidade: 10000 },
+  { valor: 9.98, quantidade: 10000 },
+  { valor: 9.99, quantidade: 20000 },
+  { valor: 10.0, quantidade: 10000 },
+  { valor: 9.98, quantidade: 10000 },
+  { valor: 9.99, quantidade: 20000 },
+  { valor: 10.0, quantidade: 10000 },
+  { valor: 9.98, quantidade: 10000 },
+  { valor: 9.99, quantidade: 20000 },
+  { valor: 10.0, quantidade: 10000 }
+];
+
+export const ordensVenda = [
+  { valor: 10.01, quantidade: 10000 },
+  { valor: 10.02, quantidade: 20000 },
+  { valor: 10.03, quantidade: 10000 },
+  { valor: 10.04, quantidade: 20000 },
+  { valor: 10.05, quantidade: 10000 },
+  { valor: 10.04, quantidade: 20000 },
+  { valor: 10.05, quantidade: 10000 },
+  { valor: 10.04, quantidade: 20000 },
+  { valor: 10.05, quantidade: 10000 }
+];
+
+export const ultimaVenda = { valor: 10.0, quantidade: 8000 };

+ 73 - 22
src/routes/trading/+page.svelte

@@ -1,8 +1,9 @@
 <script>
   import Header from '$lib/layout/Header.svelte';
-  import Tables from '$lib/components/Tables.svelte';
-  import BuyPanel from '$lib/components/trading/BuyPanel.svelte';
-  import SellPanel from '$lib/components/trading/SellPanel.svelte';
+  import TabelaOrdens from '$lib/components/trading/TabelaOrdens.svelte';
+  import GraficoCandlestick from '$lib/components/trading/GraficoCandlestick.svelte';
+  import BoletaCompra from '$lib/components/trading/BoletaCompra.svelte';
+  import BoletaVenda from '$lib/components/trading/BoletaVenda.svelte';
   import { writable } from 'svelte/store';
   import { onMount } from 'svelte';
   import { browser } from '$app/environment';
@@ -84,14 +85,14 @@
     { key: 'status', label: 'Status' }
   ];
 
-$: pendingBuys = $orders.filter((o) => o.side === 'Compra' && o.type === 'limit' && o.status === 'Aberta');
-$: pendingSells = $orders.filter((o) => o.side === 'Venda' && o.type === 'limit' && o.status === 'Aberta');
+$: pendingBuys = $orders.filter((o) => o.side === 'Compra' && o.status === 'Aberta');
+$: pendingSells = $orders.filter((o) => o.side === 'Venda' && o.status === 'Aberta');
 
 $: displayPendingBuys = pendingBuys.map((o) => ({
   side: o.side,
-  price: formatEasyToken(o.price),
+  price: formatBRL(o.price),
   amount: formatEasyToken(o.amount),
-  total: formatEasyToken(o.total),
+  total: formatBRL(o.total),
   status: o.status
 }));
 
@@ -102,26 +103,76 @@ $: displayPendingSells = pendingSells.map((o) => ({
   total: formatBRL(o.total),
   status: o.status
 }));
+
+ const tokens = [
+    { id: 'TK-SOJA',  label: 'Soja (saca 60kg)',  price: 125.50 },
+    { id: 'TK-MILHO', label: 'Milho (saca 60kg)', price: 78.90 },
+    { id: 'TK-CAFE',  name:  'Café (saca 60kg)' },
+  ];
+
+  const stateOptions = ['SP','PR','RS','MG','MT','GO','MS','BA','SC','RO','PA'];
+  let selectedState = 'SP';
+  let selectedCommodity = tokens?.[0]?.id ?? '';
+
+  let showBuyModal = false;
+  let showSellModal = false;
+
+  $: selectedCommodityObj = tokens.find((t) => t.id === selectedCommodity);
+  $: selectedCommodityLabel = selectedCommodityObj?.label || selectedCommodityObj?.name;
+
+  const dadosMock = [
+    { date: '2025-10-01', valor: 9.98 },
+    { date: '2025-10-02', valor: 10.01 },
+    { date: '2025-10-03', valor: 9.97 },
+    { date: '2025-10-04', valor: 10.02 },
+    { date: '2025-10-05', valor: 10.00 },
+    { date: '2025-10-06', valor: 9.99 },
+    { date: '2025-10-07', valor: 10.03 },
+    { date: '2025-10-08', valor: 9.96 },
+    { date: '2025-10-09', valor: 10.05 },
+    { date: '2025-10-10', valor: 10.01 },
+    { date: '2025-10-11', valor: 10.04 },
+    { date: '2025-10-12', valor: 9.98 }
+  ];
 </script>
 
 <div>
-  <Header title="Trading" subtitle="Trading do sistema" breadcrumb={breadcrumb} />
+  <Header title="Trading" subtitle="Trading do sistema" breadcrumb={breadcrumb}>
+    <svelte:fragment slot="extra">
+      <div class="flex items-center gap-3">
+        <button class="px-3 py-1.5 rounded bg-green-600 hover:bg-green-700 text-white focus:outline-none focus:ring-2 focus:ring-green-500" on:click={() => (showBuyModal = true)}>COMPRAR</button>
+        <button class="px-3 py-1.5 rounded bg-red-600 hover:bg-red-700 text-white focus:outline-none focus:ring-2 focus:ring-red-500" on:click={() => (showSellModal = true)}>VENDER</button>
+        <div class="flex items-center gap-2">
+          <span class="text-xs text-gray-600 dark:text-gray-300">Estado</span>
+          <select bind:value={selectedState} class="block w-32 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500">
+            {#each stateOptions as uf}
+              <option value={uf}>{uf}</option>
+            {/each}
+          </select>
+        </div>
+        <div class="flex items-center gap-2">
+          <span class="text-xs text-gray-600 dark:text-gray-300">Commodity</span>
+          <select bind:value={selectedCommodity} class="block w-56 rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700/70 text-gray-900 dark:text-gray-200 px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500">
+            {#each tokens as t}
+              <option value={t.id}>{t.label || t.name}</option>
+            {/each}
+          </select>
+        </div>
+      </div>
+    </svelte:fragment>
+  </Header>
 
   <div class="p-4 space-y-4">
-    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
-      <BuyPanel
-        referencePrice={currentPrice}
-        on:confirm={(e) => addOrder({ side: 'Compra', price: e.detail.price, amount: e.detail.amount, total: e.detail.total, status: 'Aberta', type: e.detail.type })}
-      />
-      <SellPanel
-        referencePrice={currentPrice}
-        on:confirm={(e) => addOrder({ side: 'Venda', price: e.detail.price, amount: e.detail.amount, total: e.detail.total, status: 'Aberta', type: e.detail.type })}
-      />
+    <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
+      <div class="md:col-span-1">
+        <TabelaOrdens />
+      </div>
+      <div class="md:col-span-2">
+        <GraficoCandlestick {dadosMock} />
+      </div>
     </div>
-
-<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
-  <Tables title="Ordens de Compra (pendentes)" columns={orderColumns} data={displayPendingBuys} showActions={false} showAdd={false}/>
-  <Tables title="Ordens de Venda (pendentes)" columns={orderColumns} data={displayPendingSells} showActions={false} showAdd={false}/>
-</div>
   </div>
+
+  <BoletaCompra visible={showBuyModal} onClose={() => (showBuyModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
+  <BoletaVenda visible={showSellModal} onClose={() => (showSellModal = false)} state={selectedState} commodity={selectedCommodityLabel} />
 </div>

部分文件因为文件数量过多而无法显示