文件还在测试中

This commit is contained in:
2026-08-08 15:53:53 +08:00
parent 5f1e7adb64
commit 8101177cb5
241 changed files with 18074 additions and 22 deletions
+23
View File
@@ -0,0 +1,23 @@
<?php
/** PSI 手动调整库存(盘盈/盘亏/报损) */
$isMat = $type === 'material';
$label = $isMat ? '物料' : '成品';
?>
<div class="page-head"><h1>调整库存 — <?php echo e($item['name']); ?></h1></div>
<div class="panel">
<p>当前库存:<b><?php echo e((float)($item['stock'] ?? 0)); ?></b></p>
<form method="post" action="<?php echo site_url('PSI/' . ($isMat ? 'materials' : 'products') . '/adjust/' . $item['id']); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>方向</label>
<select name="direction">
<option value="in">入库 +(盘盈)</option>
<option value="out">出库 -(盘亏/报损)</option>
</select>
</div>
<div class="field"><label>数量 *</label><input name="qty" type="number" step="0.01" required></div>
</div>
<button class="btn-primary" type="submit">确认调整</button>
<a class="btn-soft" href="<?php echo site_url('PSI/' . ($isMat ? 'materials' : 'products')); ?>">取消</a>
</form>
</div>
+144
View File
@@ -0,0 +1,144 @@
<?php
/** PSI 进销存仪表盘 */
?>
<div class="page-head">
<h1>进销存仪表盘</h1>
<p class="sub">服装生产 · 进出口贸易 · 终端销售 一体化库存</p>
</div>
<div class="stat-grid">
<div class="stat-card"><div class="stat-num"><?php echo e($materialTotal); ?></div><div class="stat-label">物料种类</div></div>
<div class="stat-card"><div class="stat-num"><?php echo e($productTotal); ?></div><div class="stat-label">成品种类</div></div>
<div class="stat-card"><div class="stat-num"><?php echo e(number_format($matStock, 0)); ?></div><div class="stat-label">物料库存量</div></div>
<div class="stat-card"><div class="stat-num"><?php echo e(number_format($prodStock, 0)); ?></div><div class="stat-label">成品库存量</div></div>
<div class="stat-card"><div class="stat-num">¥<?php echo e(number_format($purchaseAmt, 0)); ?></div><div class="stat-label">采购总额</div></div>
<div class="stat-card"><div class="stat-num">¥<?php echo e(number_format($salesAmt, 0)); ?></div><div class="stat-label">销售总额</div></div>
</div>
<!-- 订单业务看板 -->
<div class="stat-grid">
<a class="stat-card" href="<?php echo site_url('PSI/reports/soPo?type=sales'); ?>" style="text-decoration:none">
<div class="stat-ic"><?php echo admin_icon('trending-up', 20); ?></div>
<div class="stat-num">¥<?php echo e(number_format($salesAmount, 0)); ?></div><div class="stat-label">订单销售额(累计)</div>
</a>
<a class="stat-card" href="<?php echo site_url('PSI/reports/soPo?type=sales'); ?>" style="text-decoration:none">
<div class="stat-ic"><?php echo admin_icon('trending-up', 20); ?></div>
<div class="stat-num">¥<?php echo e(number_format($salesAmountMonth, 0)); ?></div><div class="stat-label">当月订单销售额</div>
</a>
<a class="stat-card" href="<?php echo site_url('PSI/reports/delivery'); ?>" style="text-decoration:none">
<div class="stat-ic" style="color:#f59e0b"><?php echo admin_icon('alert', 20); ?></div>
<div class="stat-num" style="color:#f59e0b"><?php echo e($undelivered['count']); ?> <small>单 / ¥<?php echo e(number_format($undelivered['amount'], 0)); ?></small></div>
<div class="stat-label">未交订单</div>
</a>
<a class="stat-card" href="<?php echo site_url('PSI/reports/delivery'); ?>" style="text-decoration:none">
<div class="stat-ic" style="color:#10b981"><?php echo admin_icon('check', 20); ?></div>
<div class="stat-num" style="color:#10b981"><?php echo e($monthDeliveries['count']); ?> <small>单 / ¥<?php echo e(number_format($monthDeliveries['amount'], 0)); ?></small></div>
<div class="stat-label">当月交付订单</div>
</a>
</div>
<div class="panel">
<div class="panel-bar"><h3>按业务员(订单销售额)</h3>
<a class="btn-sm btn-ghost" href="<?php echo site_url('PSI/reports/soPo?type=sales'); ?>">查看明细</a></div>
<?php if (empty($bySalesman)): ?><p class="muted">暂无销售订单数据</p><?php else: ?>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>业务员</th><th>订单数</th><th>销售额</th></tr></thead>
<tbody>
<?php foreach ($bySalesman as $r): ?>
<tr><td><?php echo e($r['salesman']); ?></td><td><?php echo e($r['orders']); ?></td>
<td>¥<?php echo e(number_format((float)($r['amount'] ?? 0), 2)); ?></td></tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<div class="quick-actions">
<a class="qa-card" href="<?php echo site_url('PSI/materials/create'); ?>">
<span class="qa-ico">🧵</span><span class="qa-t">录入物料</span><span class="qa-d">登记面料/辅料/纱线</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/products/create'); ?>">
<span class="qa-ico">👕</span><span class="qa-t">录入成品</span><span class="qa-d">款号/颜色/尺码</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/purchases/create'); ?>">
<span class="qa-ico">📥</span><span class="qa-t">采购入库</span><span class="qa-d">生成入库单与流水</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/sales/create'); ?>">
<span class="qa-ico">📤</span><span class="qa-t">销售出库</span><span class="qa-d">生成出库单与流水</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/sales_orders/create'); ?>">
<span class="qa-ico">📝</span><span class="qa-t">销售订单</span><span class="qa-d">录入并可打印</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/purchase_orders/create'); ?>">
<span class="qa-ico">📋</span><span class="qa-t">采购订单</span><span class="qa-d">录入并收货入库</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/outbounds/create'); ?>">
<span class="qa-ico">🚚</span><span class="qa-t">出库单</span><span class="qa-d">交付并扣库存</span>
</a>
<a class="qa-card" href="<?php echo site_url('PSI/reports'); ?>">
<span class="qa-ico">📊</span><span class="qa-t">报表中心</span><span class="qa-d">订单/交付明细</span>
</a>
</div>
<div class="two-col">
<div class="panel">
<h3>最近采购入库</h3>
<?php if (empty($recentPurchases)): ?><p class="muted">暂无采购单</p><?php else: ?>
<table class="tbl">
<thead><tr><th>单号</th><th>物料/成品</th><th>数量</th><th>金额</th><th>日期</th></tr></thead>
<tbody>
<?php foreach ($recentPurchases as $p): ?>
<tr>
<td><?php echo e($p['no'] ?? $p['id'] ?? ''); ?></td>
<td><?php echo e($p['name'] ?? ''); ?></td>
<td><?php echo e((float)($p['qty'] ?? 0)); ?></td>
<td>¥<?php echo e(number_format((float)($p['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($p['created_at'] ?? ''); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<div class="panel">
<h3>最近销售出库</h3>
<?php if (empty($recentSales)): ?><p class="muted">暂无销售单</p><?php else: ?>
<table class="tbl">
<thead><tr><th>单号</th><th>物料/成品</th><th>数量</th><th>金额</th><th>日期</th></tr></thead>
<tbody>
<?php foreach ($recentSales as $s): ?>
<tr>
<td><?php echo e($s['no'] ?? $s['id'] ?? ''); ?></td>
<td><?php echo e($s['name'] ?? ''); ?></td>
<td><?php echo e((float)($s['qty'] ?? 0)); ?></td>
<td>¥<?php echo e(number_format((float)($s['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($s['created_at'] ?? ''); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
<div class="panel">
<h3>库存预警(低于 20</h3>
<?php if (empty($lowStock)): ?>
<p class="muted">当前库存充足 ✅</p>
<?php else: ?>
<table class="tbl">
<thead><tr><th>名称</th><th>类型</th><th>当前库存</th></tr></thead>
<tbody>
<?php foreach ($lowStock as $x): ?>
<tr>
<td><?php echo e($x['item']['name']); ?></td>
<td><?php echo e($x['type']); ?></td>
<td style="color:#dc2626;font-weight:700"><?php echo e((float)($x['item']['stock'] ?? 0)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
+45
View File
@@ -0,0 +1,45 @@
<?php
/** PSI 物料表单(面辅料) */
$m = $material;
$isEdit = !empty($m);
$catOpts = ['面料' => '面料', '辅料' => '辅料', '纱线' => '纱线', '包装' => '包装', '其他' => '其他'];
$curCat = $m['category'] ?? '面料';
if ($curCat && !isset($catOpts[$curCat])) { $catOpts[$curCat] = $curCat; }
?>
<div class="page-head"><h1><?php echo $isEdit ? '编辑物料' : '新增物料'; ?></h1></div>
<div class="panel">
<form method="post" action="<?php echo site_url($isEdit ? 'PSI/materials/update/' . $m['id'] : 'PSI/materials/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>编码</label><input name="code" value="<?php echo e($m['code'] ?? ''); ?>"></div>
<div class="field"><label>名称 *</label><input name="name" value="<?php echo e($m['name'] ?? ''); ?>" required></div>
<div class="field"><label>分类</label>
<select name="category">
<?php foreach ($catOpts as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo $curCat === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>规格</label><input name="spec" value="<?php echo e($m['spec'] ?? ''); ?>"></div>
<div class="field"><label>单位</label><input name="unit" value="<?php echo e($m['unit'] ?? '个'); ?>"></div>
<div class="field"><label>颜色</label><input name="color" value="<?php echo e($m['color'] ?? ''); ?>"></div>
<div class="field"><label>成分</label><input name="composition" value="<?php echo e($m['composition'] ?? ''); ?>" placeholder="如:100%棉 / 65%涤35%棉"></div>
<div class="field"><label>克重(g/m²)</label><input name="weight_gsm" type="number" step="0.01" value="<?php echo e($m['weight_gsm'] ?? '0'); ?>"></div>
<div class="field"><label>幅宽(cm)</label><input name="width_cm" type="number" step="0.01" value="<?php echo e($m['width_cm'] ?? '0'); ?>"></div>
<div class="field"><label>缸号/批号</label><input name="batch_no" value="<?php echo e($m['batch_no'] ?? ''); ?>"></div>
<div class="field"><label>初始库存</label><input name="stock" type="number" step="0.01" value="<?php echo e($m['stock'] ?? '0'); ?>"></div>
<div class="field"><label>单价</label><input name="price" type="number" step="0.01" value="<?php echo e($m['price'] ?? '0'); ?>"></div>
<div class="field"><label>默认供应商</label>
<select name="supplier_id">
<option value="0">无</option>
<?php foreach ($suppliers as $s): ?>
<option value="<?php echo e($s['id']); ?>" <?php echo ($m['supplier_id'] ?? 0) == $s['id'] ? 'selected' : ''; ?>><?php echo e($s['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="field"><label>备注</label><textarea name="remark" rows="2"><?php echo e($m['remark'] ?? ''); ?></textarea></div>
<button class="btn-primary" type="submit">保存</button>
<a class="btn-soft" href="<?php echo site_url('PSI/materials'); ?>">取消</a>
</form>
</div>
+38
View File
@@ -0,0 +1,38 @@
<?php
/** PSI 物料列表(面辅料) */
?>
<div class="page-head">
<h1>物料管理</h1>
<a class="btn-primary" href="<?php echo site_url('PSI/materials/create'); ?>">+ 新增物料</a>
</div>
<div class="panel">
<table class="tbl">
<thead><tr><th>ID</th><th>编码</th><th>名称</th><th>规格</th><th>单位</th><th>分类</th><th>颜色</th><th>成分</th><th>克重(g)</th><th>幅宽(cm)</th><th>缸号</th><th>库存</th><th>单价</th><th>供应商</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($materials as $m): ?>
<tr>
<td><?php echo e($m['id']); ?></td>
<td><?php echo e($m['code'] ?? ''); ?></td>
<td><?php echo e($m['name']); ?></td>
<td><?php echo e($m['spec'] ?? ''); ?></td>
<td><?php echo e($m['unit'] ?? '个'); ?></td>
<td><?php echo e($m['category'] ?? ''); ?></td>
<td><?php echo e($m['color'] ?? ''); ?></td>
<td><?php echo e($m['composition'] ?? ''); ?></td>
<td><?php echo e((float)($m['weight_gsm'] ?? 0)); ?></td>
<td><?php echo e((float)($m['width_cm'] ?? 0)); ?></td>
<td><?php echo e($m['batch_no'] ?? ''); ?></td>
<td><b><?php echo e((float)($m['stock'] ?? 0)); ?></b></td>
<td>¥<?php echo e(number_format((float)($m['price'] ?? 0), 2)); ?></td>
<td><?php echo e($smap[$m['supplier_id']] ?? ''); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/materials/adjust/' . $m['id']); ?>">调整库存</a>
<a href="<?php echo site_url('PSI/materials/edit/' . $m['id']); ?>">编辑</a>
<a href="<?php echo site_url('PSI/materials/destroy/' . $m['id']); ?>" data-confirm="确认删除?">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($materials)): ?><tr><td colspan="15" class="muted">暂无物料,点击右上角新增</td></tr><?php endif; ?>
</tbody>
</table>
</div>
+46
View File
@@ -0,0 +1,46 @@
<?php
/** @var array $v */
$checked = fn($k) => !empty($v[$k]) ? 'checked' : '';
?>
<div class="page-head">
<div><h2>通知设置</h2><p class="muted">配置“新订单 / 新事件”的负责人通知渠道(邮件 + 企业微信)。</p></div>
</div>
<form method="post" action="<?php echo \Core\App::url('PSI/notifications/save'); ?>" class="form-card notify-form">
<?php echo csrf_field(); ?>
<div class="form-section">
<label class="check"><input type="checkbox" name="notify_enabled" <?php echo $checked('notify_enabled'); ?>> <b>启用事件通知</b></label>
<small>关闭后仅记录站内紧急事件,不发送邮件 / 微信。</small>
</div>
<fieldset class="form-section">
<legend>邮件通知</legend>
<label class="check"><input type="checkbox" name="notify_email_enabled" <?php echo $checked('notify_email_enabled'); ?>> 启用邮件</label>
<div class="form-row"><label>SMTP 服务器</label><input type="text" name="notify_email_smtp_host" value="<?php echo e($v['notify_email_smtp_host'] ?? ''); ?>" placeholder="如 smtp.exmail.qq.com(留空则使用系统 mail()"></div>
<div class="form-row"><label>端口</label><input type="text" name="notify_email_smtp_port" value="<?php echo e($v['notify_email_smtp_port'] ?? '465'); ?>" placeholder="465=SSL587=STARTTLS"></div>
<div class="form-row"><label>账号</label><input type="text" name="notify_email_smtp_user" value="<?php echo e($v['notify_email_smtp_user'] ?? ''); ?>" placeholder="发信邮箱/账号"></div>
<div class="form-row"><label>密码 / 授权码</label><input type="password" name="notify_email_smtp_pass" value="<?php echo e($v['notify_email_smtp_pass'] ?? ''); ?>" autocomplete="new-password"></div>
<div class="form-row"><label>发件人</label><input type="text" name="notify_email_from" value="<?php echo e($v['notify_email_from'] ?? ''); ?>" placeholder="留空则用上面的账号"></div>
<div class="form-row"><label>负责人邮箱(逗号分隔)</label><input type="text" name="notify_email_to" value="<?php echo e($v['notify_email_to'] ?? ''); ?>" placeholder="a@qq.com, b@qq.com"></div>
</fieldset>
<fieldset class="form-section">
<legend>企业微信通知</legend>
<label class="check"><input type="checkbox" name="notify_wechat_enabled" <?php echo $checked('notify_wechat_enabled'); ?>> 启用企业微信(群机器人)</label>
<div class="form-row"><label>群机器人 Webhook 地址</label><input type="text" name="notify_wechat_webhook" value="<?php echo e($v['notify_wechat_webhook'] ?? ''); ?>" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=..."></div>
<div class="form-row"><label>被 @ 的手机号/英文 id(逗号分隔)</label><input type="text" name="notify_wechat_mention" value="<?php echo e($v['notify_wechat_mention'] ?? ''); ?>" placeholder="138..., 139...(留空则不@"></div>
<small>提示:在企业微信群中添加「群机器人」即可获得 webhook 地址。</small>
</fieldset>
<fieldset class="form-section">
<legend>低库存预警</legend>
<label class="check"><input type="checkbox" name="notify_lowstock_enabled" <?php echo $checked('notify_lowstock_enabled'); ?>> 库存跌破阈值时通知</label>
<div class="form-row"><label>预警阈值</label><input type="text" name="notify_lowstock_threshold" value="<?php echo e($v['notify_lowstock_threshold'] ?? '20'); ?>" placeholder="如 20"></div>
</fieldset>
<div class="form-actions">
<button class="btn-primary" type="submit">保存设置</button>
<a class="btn-ghost" href="<?php echo \Core\App::url('PSI/reminders'); ?>">查看紧急提醒</a>
</div>
</form>
+56
View File
@@ -0,0 +1,56 @@
<?php
/** PSI 订单详情(合并自后台订单详情) */
/** @var array $o @var array $payments */
$canManage = \subsys_admin('psi');
$channelLabel = function ($c) {
return $c === 'wechat' ? '微信' : ($c === 'alipay' ? '支付宝' : '—');
};
?>
<div class="page-head">
<div><h1>订单详情</h1><div class="desc">订单号 <?php echo e($o['order_no']); ?></div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/orders'); ?>">← 返回列表</a>
</div>
<?php echo flash_html(); ?>
<div class="panel">
<table class="tbl">
<tr><th>商品</th><td><?php echo e($o['product_name']); ?></td></tr>
<tr><th>客户</th><td><?php echo e($o['customer_name']); ?><?php echo e($o['phone']); ?><?php if (!empty($o['email'])): ?>/ <?php echo e($o['email']); ?><?php endif; ?></td></tr>
<tr><th>数量</th><td><?php echo e($o['qty']); ?> 套</td></tr>
<tr><th>金额</th><td>¥<?php echo e(number_format((float)($o['amount'] ?? 0), 2)); ?></td></tr>
<tr><th>支付通道</th><td><?php echo $channelLabel($o['channel']); ?></td></tr>
<tr><th>状态</th><td>
<?php echo $o['status'] === 'paid'
? '<span class="tag-mini" style="background:#dcfce7;color:#15803d">已支付</span>'
: '<span class="tag-mini" style="background:#fef3c7;color:#b45309">待支付</span>'; ?>
<?php if (!empty($o['paid_at'])): ?><span class="muted"><?php echo e($o['paid_at']); ?></span><?php endif; ?>
</td></tr>
<tr><th>网关交易号</th><td><?php echo e($o['gateway_trade_no'] ?? '—'); ?></td></tr>
<tr><th>下单时间</th><td><?php echo e($o['created_at']); ?></td></tr>
</table>
<?php if ($canManage && $o['status'] !== 'paid'): ?>
<form method="post" action="<?php echo site_url('PSI/orders/markPaid/' . $o['id']); ?>" style="margin-top:16px">
<?php echo csrf_field(); ?><button class="btn-primary" type="submit" data-confirm="标记为已支付?">标记为已支付</button>
</form>
<?php endif; ?>
<?php if ($payments): ?>
<h3 style="margin:24px 0 10px">付款记录</h3>
<table class="tbl">
<thead><tr><th>通道</th><th>交易号</th><th>金额</th><th>状态</th><th>付款时间</th></tr></thead>
<tbody>
<?php foreach ($payments as $p): ?>
<tr>
<td><?php echo $p['channel'] === 'wechat' ? '微信' : '支付宝'; ?></td>
<td><?php echo e($p['trade_no']); ?></td>
<td>¥<?php echo e(number_format((float)($p['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($p['status']); ?></td>
<td><?php echo e($p['paid_at']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
+63
View File
@@ -0,0 +1,63 @@
<?php
/** PSI 订单管理(合并自后台订单) */
/** @var array $orders */
$canManage = \subsys_admin('psi');
$statusTag = function ($s) {
return $s === 'paid'
? '<span class="tag-mini" style="background:#dcfce7;color:#15803d">已支付</span>'
: '<span class="tag-mini" style="background:#fef3c7;color:#b45309">待支付</span>';
};
$channelLabel = function ($c) {
return $c === 'wechat' ? '微信' : ($c === 'alipay' ? '支付宝' : '—');
};
?>
<div class="page-head">
<div><h1>订单管理</h1><div class="desc">客户下单与付款处理(合并自后台订单,便于在 PSI 内快速处理)</div></div>
</div>
<?php echo flash_html(); ?>
<div class="panel">
<div class="panel-bar">
<h3>订单列表</h3>
<span class="muted">共 <?php echo count($orders); ?> 笔</span>
</div>
<div class="table-wrap">
<table class="tbl">
<thead><tr>
<th>订单号</th><th>商品</th><th>客户</th><th>数量</th><th>金额</th>
<th>通道</th><th>状态</th><th>下单时间</th><th>操作</th>
</tr></thead>
<tbody>
<?php foreach ($orders as $o): ?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo e($o['product_name']); ?></td>
<td><?php echo e($o['customer_name']); ?><br><span class="muted"><?php echo e($o['phone']); ?></span></td>
<td><?php echo e($o['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($o['amount'] ?? 0), 2)); ?></td>
<td><?php echo $channelLabel($o['channel']); ?></td>
<td><?php echo $statusTag($o['status']); ?></td>
<td class="muted"><?php echo e($o['created_at']); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/orders/show/' . $o['id']); ?>">详情</a>
<?php if ($canManage && $o['status'] !== 'paid'): ?>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/orders/markPaid/' . $o['id']); ?>" data-confirm="标记为已支付?">
<?php echo csrf_field(); ?><button type="submit" class="link-ok">标记支付</button>
</form>
<?php endif; ?>
<?php if ($canManage): ?>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/orders/destroy/' . $o['id']); ?>" data-confirm="确认删除该订单?">
<?php echo csrf_field(); ?><button type="submit" class="link-danger">删除</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($orders)): ?>
<tr><td colspan="9" class="muted" style="text-align:center;padding:24px">暂无订单</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
+131
View File
@@ -0,0 +1,131 @@
<?php
/** PSI 出库单录入/编辑 */
/** @var array|null $o @var array $items @var array|null $so @var array $soItems @var array $products */
$isEdit = !empty($o);
$prodMap = [];
foreach ($products as $p) { $prodMap[(int)$p['id']] = ['name' => $p['name'], 'spec' => $p['spec'] ?? '', 'unit' => $p['unit'] ?? '', 'price' => (float)($p['price'] ?? 0)]; }
// 行数据来源:编辑=出库明细;新建且带销售订单=销售订单未交明细;否则空行
$rows = [];
if ($isEdit) {
foreach ($items as $it) $rows[] = ['so_item_id' => $it['so_item_id'], 'product_id' => $it['product_id'], 'name' => $it['name'], 'spec' => $it['spec'], 'unit' => $it['unit'], 'qty' => $it['qty'], 'price' => $it['price']];
} elseif ($so) {
foreach ($soItems as $si) { $remain = max(0, (int)($si['qty'] ?? 0) - (int)($si['delivered_qty'] ?? 0)); if ($remain <= 0) continue;
$rows[] = ['so_item_id' => $si['id'], 'product_id' => $si['product_id'], 'name' => $si['name'], 'spec' => $si['spec'], 'unit' => $si['unit'], 'qty' => $remain, 'price' => $si['price']];
}
}
?>
<div class="page-head">
<div><h1><?php echo $isEdit ? '编辑出库单' : '新建出库单'; ?></h1>
<div class="desc"><?php echo $so ? ('关联销售订单:<b>' . e($so['order_no']) . '</b> · 已预填未交明细') : '填写出库明细,保存后自动扣减库存'; ?></div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/outbounds'); ?>">← 返回</a>
</div>
<div class="panel form-card">
<form method="post" action="<?php echo site_url($isEdit ? ('PSI/outbounds/update/' . $o['id']) : 'PSI/outbounds/store'); ?>">
<?php echo csrf_field(); ?>
<input type="hidden" name="so_no" value="<?php echo e($o['so_no'] ?? ($so['order_no'] ?? '')); ?>">
<div class="form-row">
<label>关联销售订单</label>
<input type="text" value="<?php echo e($o['so_no'] ?? ($so['order_no'] ?? '')); ?>" readonly placeholder="可选,留空为独立出库">
</div>
<div class="form-row">
<label>客户 <span class="req">*</span></label>
<input type="text" name="customer" value="<?php echo e($o['customer'] ?? ($so['customer'] ?? '')); ?>" required>
</div>
<div class="form-row">
<label>业务员</label>
<input type="text" name="salesman" value="<?php echo e($o['salesman'] ?? ($so['salesman'] ?? ($_SESSION['admin_name'] ?? ''))); ?>">
</div>
<div class="form-row">
<label>仓库</label>
<input type="text" name="warehouse" value="<?php echo e($o['warehouse'] ?? ''); ?>" placeholder="如:主仓">
</div>
<div class="form-row">
<label>出库日期</label>
<input type="date" name="delivery_date" value="<?php echo e($o['delivery_date'] ?? date('Y-m-d')); ?>">
</div>
<div class="form-row">
<label>备注</label>
<textarea name="remark" rows="2"><?php echo e($o['remark'] ?? ''); ?></textarea>
</div>
<div class="form-row">
<label>出库明细 <span class="req">*</span></label>
<div class="table-wrap">
<table class="tbl" id="itemTbl">
<thead><tr>
<th style="width:150px">关联成品</th><th>名称</th><th>规格</th><th>单位</th>
<th>数量</th><th>单价</th><th>金额</th><th></th>
</tr></thead>
<tbody id="itemBody"></tbody>
</table>
</div>
<button type="button" class="btn" id="addRow" style="margin-top:10px"><?php echo admin_icon('plus', 16); ?> 添加明细</button>
</div>
<div class="form-row" style="margin-bottom:14px">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:normal">
<input type="checkbox" name="auto_print" value="1" checked style="width:auto;margin:0"> 保存后打印预览
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">保存并出库</button>
<a class="btn-ghost" href="<?php echo site_url('PSI/outbounds'); ?>">取消</a>
</div>
</form>
</div>
<script>
const PROD = <?php echo json_encode($prodMap, JSON_UNESCAPED_UNICODE); ?>;
let ROW = 0;
function newRow(p){
p = p || {};
const tr = document.createElement('tr');
tr.className='item-row';
tr.innerHTML = `
<td><select class="prod-sel" style="width:100%">
<option value="0">手动输入</option>
${Object.keys(PROD).map(id=>`<option value="${id}">${PROD[id].name}</option>`).join('')}
</select>
<input type="hidden" name="items[${ROW}][so_item_id]" value="${p.so_item_id||0}">
<input type="hidden" name="items[${ROW}][product_id]" class="pid" value="${p.product_id||0}"></td>
<td><input type="text" name="items[${ROW}][name]" value="${p.name||''}" required style="width:100%"></td>
<td><input type="text" name="items[${ROW}][spec]" value="${p.spec||''}" style="width:90px"></td>
<td><input type="text" name="items[${ROW}][unit]" value="${p.unit||''}" style="width:50px"></td>
<td><input type="number" min="1" name="items[${ROW}][qty]" value="${p.qty||1}" class="qty" style="width:64px"></td>
<td><input type="number" step="0.01" min="0" name="items[${ROW}][price]" value="${p.price||0}" class="price" style="width:84px"></td>
<td class="amt" style="white-space:nowrap">¥0.00</td>
<td><button type="button" class="row-del" title="删除">×</button></td>`;
ROW++;
tr.querySelector('.prod-sel').addEventListener('change', e=>{ const id=e.target.value;
if(PROD[id]){ const d=PROD[id];
tr.querySelector('input[name$="[name]"]').value=d.name;
tr.querySelector('input[name$="[spec]"]').value=d.spec;
tr.querySelector('input[name$="[unit]"]').value=d.unit;
tr.querySelector('input[name$="[price]"]').value=d.price; calc(tr);
tr.querySelector('.pid').value=id;
}});
tr.querySelector('.qty').addEventListener('input', ()=>calc(tr));
tr.querySelector('.price').addEventListener('input', ()=>calc(tr));
tr.querySelector('.row-del').addEventListener('click', ()=>tr.remove());
return tr;
}
function calc(tr){ const q=parseFloat(tr.querySelector('.qty').value)||0,p=parseFloat(tr.querySelector('.price').value)||0; tr.querySelector('.amt').textContent='¥'+(q*p).toFixed(2); }
document.getElementById('addRow').addEventListener('click', ()=>document.getElementById('itemBody').appendChild(newRow()));
<?php if (!empty($rows)): ?>
<?php foreach ($rows as $r): ?>
document.getElementById('itemBody').appendChild(newRow({
so_item_id:<?php echo (int)($r['so_item_id'] ?? 0); ?>,
product_id:<?php echo (int)($r['product_id'] ?? 0); ?>,
name:<?php echo json_encode($r['name'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
spec:<?php echo json_encode($r['spec'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
unit:<?php echo json_encode($r['unit'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
qty:<?php echo (int)($r['qty'] ?? 1); ?>,
price:<?php echo (float)($r['price'] ?? 0); ?>
}));
<?php endforeach; ?>
<?php else: ?>
document.getElementById('itemBody').appendChild(newRow());
<?php endif; ?>
</script>
+32
View File
@@ -0,0 +1,32 @@
<?php
/** PSI 出库单打印正文 */
/** @var array $o @var array $items */
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
?>
<h2>出库单</h2>
<div class="sub"><?php echo e($o['order_no']); ?></div>
<div class="meta">
<span><b>关联销售订单:</b><?php echo $o['so_no'] ? e($o['so_no']) : '—'; ?></span>
<span><b>客户:</b><?php echo e($o['customer']); ?></span>
<span><b>业务员:</b><?php echo e($o['salesman']); ?></span>
<span><b>仓库:</b><?php echo e($o['warehouse']); ?></span>
<span><b>出库日期:</b><?php echo e($o['delivery_date'] ?? '—'); ?></span>
</div>
<table>
<thead><tr><th>商品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<?php foreach ($items as $it): ?>
<tr>
<td><?php echo e($it['name']); ?></td>
<td><?php echo e($it['spec']); ?></td>
<td><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot><tr><th colspan="5" style="text-align:right">合计</th><th>¥<?php echo e(number_format($amt, 2)); ?></th></tr></tfoot>
</table>
<?php if ($o['remark']): ?><p style="font-size:13px;color:#374151;margin-top:10px"><b>备注:</b><?php echo e($o['remark']); ?></p><?php endif; ?>
<div class="sign"><span>发货:<?php echo e($o['salesman']); ?></span><span>收货签字:____________</span></div>
+50
View File
@@ -0,0 +1,50 @@
<?php
/** PSI 出库单详情 */
/** @var array $o @var array $items */
$obStatus = ['delivered' => ['label' => '已交付', 'cls' => 'tag-green'], 'partial' => ['label' => '部分交付', 'cls' => 'tag-amber']];
$s = $obStatus[$o['status']] ?? $obStatus['delivered'];
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
?>
<div class="page-head">
<div><h1>出库单详情</h1><div class="desc">出库单号 <?php echo e($o['order_no']); ?></div></div>
<div style="display:flex;gap:10px">
<a class="btn-ghost" href="<?php echo site_url('PSI/outbounds/print/' . $o['id']); ?>" target="_blank"><?php echo admin_icon('printer', 16); ?> 打印</a>
<a class="btn-ghost" href="<?php echo site_url('PSI/outbounds'); ?>">← 返回</a>
</div>
</div>
<div class="panel two-col">
<table class="tbl">
<tr><th>关联销售订单</th><td><?php echo $o['so_no'] ? e($o['so_no']) : '<span class="muted">—</span>'; ?></td></tr>
<tr><th>客户</th><td><?php echo e($o['customer']); ?></td></tr>
<tr><th>业务员</th><td><?php echo e($o['salesman']); ?></td></tr>
<tr><th>仓库</th><td><?php echo e($o['warehouse']); ?></td></tr>
<tr><th>状态</th><td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td></tr>
<tr><th>出库日期</th><td><?php echo e($o['delivery_date'] ?? '—'); ?></td></tr>
<tr><th>备注</th><td class="muted"><?php echo e($o['remark'] ?: '—'); ?></td></tr>
</table>
</div>
<div class="panel">
<div class="panel-bar"><h3>出库明细</h3><span class="muted">合计 ¥<?php echo e(number_format($amt, 2)); ?></span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>商品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<?php foreach ($items as $it): ?>
<tr>
<td><?php echo e($it['name']); ?></td>
<td class="muted"><?php echo e($it['spec']); ?></td>
<td class="muted"><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div style="margin-top:16px;display:flex;gap:10px">
<a class="btn-primary" href="<?php echo site_url('PSI/outbounds/edit/' . $o['id']); ?>">编辑</a>
</div>
</div>
+46
View File
@@ -0,0 +1,46 @@
<?php
/** PSI 出库单列表 */
/** @var array $list */
$obStatus = ['delivered' => ['label' => '已交付', 'cls' => 'tag-green'], 'partial' => ['label' => '部分交付', 'cls' => 'tag-amber']];
?>
<div class="page-head">
<div><h1>出库单</h1><div class="desc">按销售订单发货出库(自动扣减库存并回写已交付量,可直接打印)</div></div>
<a class="btn-primary" href="<?php echo site_url('PSI/outbounds/create'); ?>"><?php echo admin_icon('plus', 16); ?> 新建出库单</a>
</div>
<div class="panel">
<div class="table-wrap">
<table class="tbl">
<thead><tr>
<th>出库单号</th><th>关联销售订单</th><th>客户</th><th>业务员</th><th>仓库</th>
<th>金额</th><th>状态</th><th>出库日期</th><th>操作</th>
</tr></thead>
<tbody>
<?php foreach ($list as $o):
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $o['_items'] ?? []));
$s = $obStatus[$o['status']] ?? $obStatus['delivered'];
?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo $o['so_no'] ? e($o['so_no']) : '<span class="muted">—</span>'; ?></td>
<td><?php echo e($o['customer']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td class="muted"><?php echo e($o['warehouse']); ?></td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
<td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td>
<td class="muted"><?php echo e($o['delivery_date'] ?? '—'); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/outbounds/show/' . $o['id']); ?>">详情</a>
<a href="<?php echo site_url('PSI/outbounds/print/' . $o['id']); ?>" target="_blank">打印</a>
<a href="<?php echo site_url('PSI/outbounds/edit/' . $o['id']); ?>">编辑</a>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/outbounds/destroy/' . $o['id']); ?>" data-confirm="确认删除该出库单?将回冲库存与已交付量。">
<?php echo csrf_field(); ?><button class="link-danger" type="submit">删除</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($list)): ?><tr><td colspan="9" class="muted" style="text-align:center;padding:24px">暂无出库单</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
+47
View File
@@ -0,0 +1,47 @@
<?php
/** PSI 成品表单(降温服/成衣:款号/颜色/尺码/季节/年份) */
$p = $product;
$isEdit = !empty($p);
$catOpts = ['降温服' => '降温服', '成衣' => '成衣', '配饰' => '配饰', '其他' => '其他'];
$curCat = $p['category'] ?? '降温服';
if ($curCat && !isset($catOpts[$curCat])) { $catOpts[$curCat] = $curCat; }
$seasonOpts = ['春' => '春', '夏' => '夏', '秋' => '秋', '冬' => '冬', '四季' => '四季'];
$curSeason = $p['season'] ?? '';
?>
<div class="page-head"><h1><?php echo $isEdit ? '编辑成品' : '新增成品'; ?></h1></div>
<div class="panel">
<form method="post" action="<?php echo site_url($isEdit ? 'PSI/products/update/' . $p['id'] : 'PSI/products/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>款号 *</label><input name="style_no" value="<?php echo e($p['style_no'] ?? ''); ?>" placeholder="如:KJ-2026-001"></div>
<div class="field"><label>名称 *</label><input name="name" value="<?php echo e($p['name'] ?? ''); ?>" required></div>
<div class="field"><label>编码</label><input name="code" value="<?php echo e($p['code'] ?? ''); ?>"></div>
<div class="field"><label>分类</label>
<select name="category">
<?php foreach ($catOpts as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo $curCat === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>规格</label><input name="spec" value="<?php echo e($p['spec'] ?? ''); ?>"></div>
<div class="field"><label>单位</label><input name="unit" value="<?php echo e($p['unit'] ?? '件'); ?>"></div>
<div class="field"><label>颜色</label><input name="color" value="<?php echo e($p['color'] ?? ''); ?>"></div>
<div class="field"><label>尺码段</label><input name="size_run" value="<?php echo e($p['size_run'] ?? ''); ?>" placeholder="如:S/M/L/XL"></div>
<div class="field"><label>季节</label>
<select name="season">
<option value="">未设置</option>
<?php foreach ($seasonOpts as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo $curSeason === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>年份</label><input name="year" value="<?php echo e($p['year'] ?? ''); ?>" placeholder="如:2026"></div>
<div class="field"><label>初始库存</label><input name="stock" type="number" step="0.01" value="<?php echo e($p['stock'] ?? '0'); ?>"></div>
<div class="field"><label>成本</label><input name="cost" type="number" step="0.01" value="<?php echo e($p['cost'] ?? '0'); ?>"></div>
<div class="field"><label>售价</label><input name="price" type="number" step="0.01" value="<?php echo e($p['price'] ?? '0'); ?>"></div>
</div>
<div class="field"><label>备注</label><textarea name="remark" rows="2"><?php echo e($p['remark'] ?? ''); ?></textarea></div>
<button class="btn-primary" type="submit">保存</button>
<a class="btn-soft" href="<?php echo site_url('PSI/products'); ?>">取消</a>
</form>
</div>
+38
View File
@@ -0,0 +1,38 @@
<?php
/** PSI 成品列表(降温服/成衣:款号/颜色/尺码/季节) */
?>
<div class="page-head">
<h1>成品管理</h1>
<a class="btn-primary" href="<?php echo site_url('PSI/products/create'); ?>">+ 新增成品</a>
</div>
<div class="panel">
<table class="tbl">
<thead><tr><th>ID</th><th>编码</th><th>款号</th><th>名称</th><th>规格</th><th>单位</th><th>分类</th><th>颜色</th><th>尺码</th><th>季节</th><th>年份</th><th>库存</th><th>成本</th><th>售价</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($products as $p): ?>
<tr>
<td><?php echo e($p['id']); ?></td>
<td><?php echo e($p['code'] ?? ''); ?></td>
<td><b><?php echo e($p['style_no'] ?? ''); ?></b></td>
<td><?php echo e($p['name']); ?></td>
<td><?php echo e($p['spec'] ?? ''); ?></td>
<td><?php echo e($p['unit'] ?? '件'); ?></td>
<td><?php echo e($p['category'] ?? ''); ?></td>
<td><?php echo e($p['color'] ?? ''); ?></td>
<td><?php echo e($p['size_run'] ?? ''); ?></td>
<td><?php echo e($p['season'] ?? ''); ?></td>
<td><?php echo e($p['year'] ?? ''); ?></td>
<td><b><?php echo e((float)($p['stock'] ?? 0)); ?></b></td>
<td>¥<?php echo e(number_format((float)($p['cost'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($p['price'] ?? 0), 2)); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/products/adjust/' . $p['id']); ?>">调整库存</a>
<a href="<?php echo site_url('PSI/products/edit/' . $p['id']); ?>">编辑</a>
<a href="<?php echo site_url('PSI/products/destroy/' . $p['id']); ?>" data-confirm="确认删除?">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($products)): ?><tr><td colspan="15" class="muted">暂无成品,点击右上角新增</td></tr><?php endif; ?>
</tbody>
</table>
</div>
+56
View File
@@ -0,0 +1,56 @@
<?php
/** PSI 采购表单(物料/成品统一) */
$mats = isset($GLOBALS['_psi_materials']) ? $GLOBALS['_psi_materials'] : [];
$prods = isset($GLOBALS['_psi_products']) ? $GLOBALS['_psi_products'] : [];
// 通过控制器注入时取不到,这里改为从全局读取;若为空则由控制器提供
?>
<div class="page-head"><h1>新增采购入库</h1></div>
<div class="panel">
<form method="post" action="<?php echo site_url('PSI/purchases/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>供应商</label>
<select name="supplier_id">
<option value="0">未选择</option>
<?php foreach ($suppliers as $s): ?>
<option value="<?php echo e($s['id']); ?>"><?php echo e($s['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>入库类型</label>
<select name="item_type" id="item_type">
<option value="material">物料</option>
<option value="product">成品</option>
</select>
</div>
<div class="field"><label>物料/成品</label>
<select name="item_id" id="item_id">
<optgroup label="物料">
<?php foreach ($materials as $m): ?><option value="<?php echo e($m['id']); ?>"><?php echo e($m['name']); ?></option><?php endforeach; ?>
</optgroup>
<optgroup label="成品">
<?php foreach ($products as $p): ?><option value="<?php echo e($p['id']); ?>"><?php echo e($p['name']); ?></option><?php endforeach; ?>
</optgroup>
</select>
</div>
<div class="field"><label>数量 *</label><input name="qty" type="number" step="0.01" required></div>
<div class="field"><label>单价</label><input name="price" type="number" step="0.01" value="0"></div>
<div class="field"><label>批次/缸号</label><input name="batch_no" placeholder="面辅料缸号/批次"></div>
<div class="field"><label>预计到货</label><input name="expected_at" type="date"></div>
</div>
<div class="field"><label>备注</label><textarea name="remark" rows="2"></textarea></div>
<button class="btn-primary" type="submit">入库并提交</button>
<a class="btn-soft" href="<?php echo site_url('PSI/purchases'); ?>">取消</a>
</form>
</div>
<script>
// 切换类型时仅保留对应分组的选项
document.getElementById('item_type').addEventListener('change', function(){
var type = this.value; // material|product
var sel = document.getElementById('item_id');
Array.prototype.forEach.call(sel.querySelectorAll('optgroup'), function(og){
og.style.display = (og.label === (type==='product'?'成品':'物料')) ? '' : 'none';
});
sel.selectedIndex = 0;
});
</script>
+132
View File
@@ -0,0 +1,132 @@
<?php
/** PSI 采购订单录入/编辑 */
/** @var array|null $o @var array $items @var array $materials @var array $products */
$isEdit = !empty($o);
$cat = ['material' => [], 'product' => []];
foreach ($materials as $m) { $cat['material'][(int)$m['id']] = ['name' => $m['name'], 'spec' => $m['spec'] ?? '', 'unit' => $m['unit'] ?? '', 'price' => (float)($m['price'] ?? 0)]; }
foreach ($products as $p) { $cat['product'][(int)$p['id']] = ['name' => $p['name'], 'spec' => $p['spec'] ?? '', 'unit' => $p['unit'] ?? '', 'price' => (float)($p['price'] ?? 0)]; }
?>
<div class="page-head">
<div><h1><?php echo $isEdit ? '编辑采购订单' : '新建采购订单'; ?></h1><div class="desc">选择供应商与采购明细(物料 / 成品),收货后自动入库</div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/purchase_orders'); ?>">← 返回</a>
</div>
<div class="panel form-card">
<form method="post" action="<?php echo site_url($isEdit ? ('PSI/purchase_orders/update/' . $o['id']) : 'PSI/purchase_orders/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-row">
<label>供应商 <span class="req">*</span></label>
<input type="text" name="supplier_name" value="<?php echo e($o['supplier_name'] ?? ''); ?>" required placeholder="供应商名称">
</div>
<div class="form-row">
<label>采购员</label>
<input type="text" name="salesman" value="<?php echo e($o['salesman'] ?? ($_SESSION['admin_name'] ?? '')); ?>" placeholder="默认当前登录人">
</div>
<div class="form-row">
<label>期望到货</label>
<input type="date" name="expected_at" value="<?php echo e($o['expected_at'] ?? ''); ?>">
</div>
<div class="form-row">
<label>备注</label>
<textarea name="remark" rows="2" placeholder="选填"><?php echo e($o['remark'] ?? ''); ?></textarea>
</div>
<div class="form-row">
<label>采购明细 <span class="req">*</span></label>
<div class="table-wrap">
<table class="tbl" id="itemTbl">
<thead><tr>
<th style="width:90px">类型</th><th style="width:160px">选择</th><th>名称</th><th>规格</th><th>单位</th>
<th>数量</th><th>单价</th><th>金额</th><th></th>
</tr></thead>
<tbody id="itemBody"></tbody>
</table>
</div>
<button type="button" class="btn" id="addRow" style="margin-top:10px"><?php echo admin_icon('plus', 16); ?> 添加明细</button>
</div>
<div class="form-row" style="margin-bottom:14px">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:normal">
<input type="checkbox" name="auto_print" value="1" checked style="width:auto;margin:0"> 保存后打印预览
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">保存</button>
<a class="btn-ghost" href="<?php echo site_url('PSI/purchase_orders'); ?>">取消</a>
</div>
</form>
</div>
<script>
const CAT = <?php echo json_encode($cat, JSON_UNESCAPED_UNICODE); ?>;
let ROW = 0;
function opts(type){
let h = '<option value="0">手动输入</option>';
for (const id in CAT[type]) h += `<option value="${id}">${CAT[type][id].name}</option>`;
return h;
}
function newRow(p){
p = p || {};
const type = p.item_type || 'material';
const tr = document.createElement('tr');
tr.className = 'item-row';
tr.innerHTML = `
<td><select class="itype">
<option value="material" ${type==='material'?'selected':''}>物料</option>
<option value="product" ${type==='product'?'selected':''}>成品</option>
</select>
<input type="hidden" name="items[${ROW}][item_type]" class="itype-h" value="${type}"></td>
<td><select class="isel" style="width:100%">${opts(type)}</select>
<input type="hidden" name="items[${ROW}][item_id]" class="iid" value="${p.item_id||0}"></td>
<td><input type="text" name="items[${ROW}][name]" value="${p.name||''}" required style="width:100%"></td>
<td><input type="text" name="items[${ROW}][spec]" value="${p.spec||''}" style="width:90px"></td>
<td><input type="text" name="items[${ROW}][unit]" value="${p.unit||''}" style="width:50px"></td>
<td><input type="number" min="1" name="items[${ROW}][qty]" value="${p.qty||1}" class="qty" style="width:64px"></td>
<td><input type="number" step="0.01" min="0" name="items[${ROW}][price]" value="${p.price||0}" class="price" style="width:84px"></td>
<td class="amt" style="white-space:nowrap">¥0.00</td>
<td><button type="button" class="row-del" title="删除">×</button></td>`;
ROW++;
const sel = tr.querySelector('.isel');
const typeSel = tr.querySelector('.itype');
sel.value = p.item_id || '0';
typeSel.addEventListener('change', e=>{
const t = e.target.value;
tr.querySelector('.itype-h').value = t;
sel.innerHTML = opts(t); sel.value = '0';
});
sel.addEventListener('change', e=>{
const id = e.target.value;
tr.querySelector('.iid').value = id;
if (CAT[type][id]) { const d=CAT[type][id];
tr.querySelector('input[name$="[name]"]').value=d.name;
tr.querySelector('input[name$="[spec]"]').value=d.spec;
tr.querySelector('input[name$="[unit]"]').value=d.unit;
tr.querySelector('input[name$="[price]"]').value=d.price; calc(tr);
}
});
tr.querySelector('.qty').addEventListener('input', ()=>calc(tr));
tr.querySelector('.price').addEventListener('input', ()=>calc(tr));
tr.querySelector('.row-del').addEventListener('click', ()=>tr.remove());
return tr;
}
function calc(tr){
const q=parseFloat(tr.querySelector('.qty').value)||0, p=parseFloat(tr.querySelector('.price').value)||0;
tr.querySelector('.amt').textContent='¥'+(q*p).toFixed(2);
}
document.getElementById('addRow').addEventListener('click', ()=>document.getElementById('itemBody').appendChild(newRow()));
<?php if (!empty($items)): ?>
<?php foreach ($items as $it): ?>
document.getElementById('itemBody').appendChild(newRow({
item_type:'<?php echo $it['item_type']==='product'?'product':'material'; ?>',
item_id:<?php echo (int)($it['item_id'] ?? 0); ?>,
name:<?php echo json_encode($it['name'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
spec:<?php echo json_encode($it['spec'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
unit:<?php echo json_encode($it['unit'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
qty:<?php echo (int)($it['qty'] ?? 1); ?>,
price:<?php echo (float)($it['price'] ?? 0); ?>
}));
<?php endforeach; ?>
<?php else: ?>
document.getElementById('itemBody').appendChild(newRow());
<?php endif; ?>
</script>
+32
View File
@@ -0,0 +1,32 @@
<?php
/** PSI 采购订单打印正文 */
/** @var array $o @var array $items */
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
?>
<h2>采购订单</h2>
<div class="sub"><?php echo e($o['order_no']); ?></div>
<div class="meta">
<span><b>供应商:</b><?php echo e($o['supplier_name']); ?></span>
<span><b>采购员:</b><?php echo e($o['salesman']); ?></span>
<span><b>期望到货:</b><?php echo e($o['expected_at'] ?? '—'); ?></span>
<span><b>下单:</b><?php echo e($o['created_at']); ?></span>
</div>
<table>
<thead><tr><th>类型</th><th>名称</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<?php foreach ($items as $it): ?>
<tr>
<td><?php echo $it['item_type'] === 'product' ? '成品' : '物料'; ?></td>
<td><?php echo e($it['name']); ?></td>
<td><?php echo e($it['spec']); ?></td>
<td><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot><tr><th colspan="6" style="text-align:right">合计</th><th>¥<?php echo e(number_format($amt, 2)); ?></th></tr></tfoot>
</table>
<?php if ($o['remark']): ?><p style="font-size:13px;color:#374151;margin-top:10px"><b>备注:</b><?php echo e($o['remark']); ?></p><?php endif; ?>
<div class="sign"><span>制单:<?php echo e($o['salesman']); ?></span><span>供应商签字:____________</span></div>
+60
View File
@@ -0,0 +1,60 @@
<?php
/** PSI 采购订单详情 */
/** @var array $o @var array $items */
$poStatus = [
'pending' => ['label' => '待处理', 'cls' => 'tag-gray'],
'partial' => ['label' => '部分收货', 'cls' => 'tag-amber'],
'received' => ['label' => '已收货', 'cls' => 'tag-green'],
'closed' => ['label' => '已关闭', 'cls' => 'tag-gray'],
];
$s = $poStatus[$o['status']] ?? $poStatus['pending'];
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
?>
<div class="page-head">
<div><h1>采购订单详情</h1><div class="desc">订单号 <?php echo e($o['order_no']); ?></div></div>
<div style="display:flex;gap:10px">
<a class="btn-ghost" href="<?php echo site_url('PSI/purchase_orders/print/' . $o['id']); ?>" target="_blank"><?php echo admin_icon('printer', 16); ?> 打印</a>
<a class="btn-ghost" href="<?php echo site_url('PSI/purchase_orders'); ?>">← 返回</a>
</div>
</div>
<div class="panel two-col">
<table class="tbl">
<tr><th>供应商</th><td><?php echo e($o['supplier_name']); ?></td></tr>
<tr><th>采购员</th><td><?php echo e($o['salesman']); ?></td></tr>
<tr><th>状态</th><td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td></tr>
<tr><th>期望到货</th><td><?php echo e($o['expected_at'] ?? '—'); ?></td></tr>
<tr><th>备注</th><td class="muted"><?php echo e($o['remark'] ?: '—'); ?></td></tr>
</table>
</div>
<div class="panel">
<div class="panel-bar"><h3>采购明细</h3><span class="muted">合计 ¥<?php echo e(number_format($amt, 2)); ?></span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>类型</th><th>名称</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th><th>已收</th></tr></thead>
<tbody>
<?php foreach ($items as $it): ?>
<tr>
<td><?php echo $it['item_type'] === 'product' ? '成品' : '物料'; ?></td>
<td><?php echo e($it['name']); ?></td>
<td class="muted"><?php echo e($it['spec']); ?></td>
<td class="muted"><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($it['received_qty'] ?? 0); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div style="margin-top:16px;display:flex;gap:10px">
<?php if ($o['status'] !== 'received'): ?>
<a class="btn-primary" href="<?php echo site_url('PSI/purchase_orders/edit/' . $o['id']); ?>">编辑</a>
<form method="post" action="<?php echo site_url('PSI/purchase_orders/receive/' . $o['id']); ?>" data-confirm="确认收货入库?将增加对应成品库存。">
<?php echo csrf_field(); ?><button class="btn-ok" type="submit">收货入库</button>
</form>
<?php endif; ?>
</div>
</div>
+55
View File
@@ -0,0 +1,55 @@
<?php
/** PSI 采购订单列表 */
/** @var array $orders */
$poStatus = [
'pending' => ['label' => '待处理', 'cls' => 'tag-gray'],
'partial' => ['label' => '部分收货', 'cls' => 'tag-amber'],
'received' => ['label' => '已收货', 'cls' => 'tag-green'],
'closed' => ['label' => '已关闭', 'cls' => 'tag-gray'],
];
?>
<div class="page-head">
<div><h1>采购订单</h1><div class="desc">录入对供应商的采购订单,收货后自动入库并增加库存(可打印)</div></div>
<a class="btn-primary" href="<?php echo site_url('PSI/purchase_orders/create'); ?>"><?php echo admin_icon('plus', 16); ?> 新建采购订单</a>
</div>
<div class="panel">
<div class="table-wrap">
<table class="tbl">
<thead><tr>
<th>订单号</th><th>供应商</th><th>采购员</th><th>明细</th><th>金额</th>
<th>状态</th><th>期望到货</th><th>操作</th>
</tr></thead>
<tbody>
<?php foreach ($orders as $o):
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $o['_items'] ?? []));
$s = $poStatus[$o['status']] ?? $poStatus['pending'];
?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo e($o['supplier_name']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td class="muted"><?php echo count($o['_items'] ?? []); ?> 项</td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
<td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td>
<td class="muted"><?php echo e($o['expected_at'] ?? '—'); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/purchase_orders/show/' . $o['id']); ?>">详情</a>
<a href="<?php echo site_url('PSI/purchase_orders/print/' . $o['id']); ?>" target="_blank">打印</a>
<?php if ($o['status'] !== 'received'): ?>
<a href="<?php echo site_url('PSI/purchase_orders/edit/' . $o['id']); ?>">编辑</a>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/purchase_orders/receive/' . $o['id']); ?>" data-confirm="确认收货入库?将增加对应成品库存。">
<?php echo csrf_field(); ?><button class="link-ok" type="submit">收货</button>
</form>
<?php endif; ?>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/purchase_orders/destroy/' . $o['id']); ?>" data-confirm="确认删除该采购订单?">
<?php echo csrf_field(); ?><button class="link-danger" type="submit">删除</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($orders)): ?><tr><td colspan="8" class="muted" style="text-align:center;padding:24px">暂无采购订单</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
+32
View File
@@ -0,0 +1,32 @@
<?php
/** PSI 采购入库列表 */
?>
<div class="page-head">
<h1>采购入库</h1>
<a class="btn-primary" href="<?php echo site_url('PSI/purchases/create'); ?>">+ 新增采购</a>
</div>
<div class="panel">
<p class="muted">提交采购单后系统自动增加对应物料/成品库存,并写入库存流水。</p>
<table class="tbl">
<thead><tr><th>单号</th><th>供应商</th><th>类型</th><th>批次/缸号</th><th>数量</th><th>单价</th><th>金额</th><th>预计到货</th><th>日期</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($purchases as $p): ?>
<tr>
<td><?php echo e($p['order_no']); ?></td>
<td><?php echo e($smap[$p['supplier_id']] ?? ''); ?></td>
<td><?php echo $p['item_type'] === 'product' ? '成品' : '物料'; ?></td>
<td><?php echo e($p['batch_no'] ?? ''); ?></td>
<td><?php echo e((float)($p['qty'] ?? 0)); ?></td>
<td>¥<?php echo e(number_format((float)($p['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($p['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($p['expected_at'] ?? ''); ?></td>
<td><?php echo e($p['created_at'] ?? ''); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/purchases/destroy/' . $p['id']); ?>" data-confirm="删除不会回滚库存,确认?">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($purchases)): ?><tr><td colspan="10" class="muted">暂无采购记录</td></tr><?php endif; ?>
</tbody>
</table>
</div>
+26
View File
@@ -0,0 +1,26 @@
<?php
/** @var string $title */
/** @var string $body */
?>
<div class="page-head">
<div><h2>发起紧急提醒</h2><p class="muted">提交后将作为紧急事件通知相关负责人(站内 + 邮件 + 微信,依通知设置)。</p></div>
<div class="head-actions">
<a class="btn-ghost" href="<?php echo \Core\App::url('PSI/reminders'); ?>">返回列表</a>
</div>
</div>
<form method="post" action="<?php echo \Core\App::url('PSI/reminders/create'); ?>" class="form-card">
<?php echo csrf_field(); ?>
<div class="form-row">
<label>提醒标题 <span class="req">*</span></label>
<input type="text" name="title" maxlength="120" required value="<?php echo e($title); ?>" placeholder="例如:A 客户订单需今日发货">
</div>
<div class="form-row">
<label>提醒内容</label>
<textarea name="body" rows="5" placeholder="补充说明,可留空"><?php echo e($body); ?></textarea>
</div>
<div class="form-actions">
<button class="btn-primary" type="submit">发送紧急提醒</button>
<a class="btn-ghost" href="<?php echo \Core\App::url('PSI/reminders'); ?>">取消</a>
</div>
</form>
+73
View File
@@ -0,0 +1,73 @@
<?php
/** @var array $events */
/** @var int $unread */
$typeLabel = [
'sales_order' => '新销售订单',
'purchase_order' => '新采购订单',
'customer_order' => '新客户订单',
'low_stock' => '低库存预警',
'manual' => '手动提醒',
];
?>
<div class="page-head">
<div>
<h2>紧急提醒</h2>
<p class="muted">系统将“新订单 / 新事件”作为紧急事件推送;未读 <b style="color:#dc2626"><?php echo $unread; ?></b> 条。</p>
</div>
<div class="head-actions">
<a class="btn-primary" href="<?php echo \Core\App::url('PSI/reminders/create'); ?>"><?php echo admin_icon('bell', 16); ?> 发起提醒</a>
<?php if ($unread > 0): ?>
<form method="post" action="<?php echo \Core\App::url('PSI/reminders/markAll'); ?>" class="inline-form">
<?php echo csrf_field(); ?>
<button class="btn-ghost" type="submit">全部标为已读</button>
</form>
<?php endif; ?>
</div>
</div>
<?php if (empty($events)): ?>
<div class="empty-box">暂无紧急事件。</div>
<?php else: ?>
<div class="ev-list">
<?php foreach ($events as $ev):
$type = $ev['type'] ?? 'manual';
$channels = json_decode($ev['channels'] ?? '[]', true) ?: [];
$isRead = !empty($ev['_read']);
?>
<div class="ev-card<?php echo $isRead ? ' read' : ''; ?>">
<div class="ev-left">
<span class="ev-dot"></span>
</div>
<div class="ev-main">
<div class="ev-top">
<span class="ev-tag"><?php echo e($typeLabel[$type] ?? $type); ?></span>
<?php if (!$isRead): ?><span class="ev-new">未读</span><?php endif; ?>
<span class="ev-time"><?php echo e($ev['created_at'] ?? ''); ?></span>
</div>
<div class="ev-title"><?php echo e($ev['title'] ?? ''); ?></div>
<div class="ev-body"><?php echo nl2br(e($ev['body'] ?? '')); ?></div>
<div class="ev-foot">
<span class="ev-channels">
<?php foreach ($channels as $c): ?>
<span class="ch ch-<?php echo e($c); ?>"><?php echo e($c === 'inapp' ? '站内' : ($c === 'email' ? '邮件' : ($c === 'wechat' ? '微信' : $c))); ?></span>
<?php endforeach; ?>
</span>
<span class="ev-ops">
<?php if (!empty($ev['url'])): ?>
<a class="link-ok" href="<?php echo \Core\App::url($ev['url']); ?>">查看详情</a>
<?php endif; ?>
<?php if (!$isRead): ?>
<form method="post" action="<?php echo \Core\App::url('PSI/reminders/mark/' . $ev['id']); ?>" class="inline-form">
<?php echo csrf_field(); ?>
<button class="link-ok" type="submit">标为已读</button>
</form>
<?php else: ?>
<span class="muted">已读</span>
<?php endif; ?>
</span>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
+59
View File
@@ -0,0 +1,59 @@
<?php
/** PSI 交付明细报表:出库单 + 销售订单交付进度 */
/** @var array $list @var array $progress */
$soStatus = ['pending'=>'待处理','partial'=>'部分交付','delivered'=>'已交付','closed'=>'已关闭'];
?>
<div class="page-head">
<div><h1>交付明细</h1><div class="desc">出库(交付)记录与销售订单交付进度、未交订单</div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/reports'); ?>">← 报表中心</a>
</div>
<div class="panel">
<div class="panel-bar"><h3>销售订单交付进度</h3><span class="muted">应发 / 已发 / 未发</span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>销售订单</th><th>客户</th><th>业务员</th><th>状态</th><th>应发</th><th>已发</th><th>未发</th><th>金额</th></tr></thead>
<tbody>
<?php foreach ($progress as $p): ?>
<tr>
<td><?php echo e($p['order_no']); ?></td>
<td><?php echo e($p['customer']); ?></td>
<td><?php echo e($p['salesman']); ?></td>
<td><span class="tag-mini <?php echo $p['status']==='delivered'?'tag-green':($p['status']==='partial'?'tag-amber':'tag-gray'); ?>"><?php echo $soStatus[$p['status']] ?? '待处理'; ?></span></td>
<td><?php echo $p['ordered']; ?></td>
<td><?php echo $p['delivered']; ?></td>
<td><?php echo $p['remain']; ?></td>
<td>¥<?php echo e(number_format($p['amount'], 2)); ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($progress)): ?><tr><td colspan="8" class="muted" style="text-align:center;padding:16px">暂无销售订单交付数据</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
<div class="panel">
<div class="panel-bar"><h3>出库(交付)记录</h3><span class="muted">共 <?php echo count($list); ?> 单</span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>出库单号</th><th>关联销售订单</th><th>客户</th><th>业务员</th><th>金额</th><th>出库日期</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($list as $o):
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $o['_items'] ?? []));
?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo $o['so_no'] ? e($o['so_no']) : '<span class="muted">—</span>'; ?></td>
<td><?php echo e($o['customer']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
<td class="muted"><?php echo e($o['delivery_date'] ?? '—'); ?></td>
<td class="row-actions"><a href="<?php echo site_url('PSI/outbounds/show/' . $o['id']); ?>">详情</a>
<a href="<?php echo site_url('PSI/outbounds/print/' . $o['id']); ?>" target="_blank">打印</a></td>
</tr>
<?php endforeach; ?>
<?php if (empty($list)): ?><tr><td colspan="7" class="muted" style="text-align:center;padding:16px">暂无出库记录</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
+42
View File
@@ -0,0 +1,42 @@
<?php
/** PSI 采购订单明细报表 */
/** @var array $orders */
$poStatus = ['pending'=>'待处理','partial'=>'部分收货','received'=>'已收货','closed'=>'已关闭'];
?>
<div class="page-head">
<div><h1>采购订单明细</h1><div class="desc">每张采购订单的物料/成品明细(共 <?php echo count($orders); ?> 张)</div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/reports'); ?>">← 报表中心</a>
</div>
<?php foreach ($orders as $o):
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $o['_items'] ?? []));
?>
<div class="panel">
<div class="panel-bar">
<h3><?php echo e($o['order_no']); ?> · <?php echo e($o['supplier_name']); ?>
<span class="tag-mini tag-gray" style="margin-left:6px"><?php echo $poStatus[$o['status']] ?? '待处理'; ?></span></h3>
<span class="muted">采购员 <?php echo e($o['salesman']); ?> · 合计 ¥<?php echo e(number_format($amt, 2)); ?></span>
</div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>类型</th><th>名称</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th><th>已收</th></tr></thead>
<tbody>
<?php foreach (($o['_items'] ?? []) as $it): ?>
<tr>
<td><?php echo $it['item_type'] === 'product' ? '成品' : '物料'; ?></td>
<td><?php echo e($it['name']); ?></td>
<td class="muted"><?php echo e($it['spec']); ?></td>
<td class="muted"><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($it['received_qty'] ?? 0); ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($o['_items'])): ?><tr><td colspan="8" class="muted" style="text-align:center;padding:16px">无明细</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php endforeach; ?>
<?php if (empty($orders)): ?><div class="panel"><div class="muted" style="text-align:center;padding:24px">暂无采购订单</div></div><?php endif; ?>
+66
View File
@@ -0,0 +1,66 @@
<?php
/** PSI 销售/采购订单明细(合并筛选) */
/** @var string $type @var array $so @var array $po */
$soStatus = ['pending'=>'待处理','partial'=>'部分交付','delivered'=>'已交付','closed'=>'已关闭'];
$poStatus = ['pending'=>'待处理','partial'=>'部分收货','received'=>'已收货','closed'=>'已关闭'];
?>
<div class="page-head">
<div><h1>销售 / 采购订单明细</h1><div class="desc">合并查看销售订单与采购订单(含金额)</div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/reports'); ?>">← 报表中心</a>
</div>
<div class="panel">
<div class="panel-bar">
<h3>筛选</h3>
<div class="seg" style="display:flex;gap:8px">
<a class="btn-sm <?php echo $type==='all'?'btn-primary':'btn-ghost'; ?>" href="<?php echo site_url('PSI/reports/soPo?type=all'); ?>">全部</a>
<a class="btn-sm <?php echo $type==='sales'?'btn-primary':'btn-ghost'; ?>" href="<?php echo site_url('PSI/reports/soPo?type=sales'); ?>">仅销售订单</a>
<a class="btn-sm <?php echo $type==='purchase'?'btn-primary':'btn-ghost'; ?>" href="<?php echo site_url('PSI/reports/soPo?type=purchase'); ?>">仅采购订单</a>
</div>
</div>
<?php if ($type !== 'purchase'): ?>
<h4 style="margin:14px 0 8px">销售订单(<?php echo count($so); ?></h4>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>订单号</th><th>客户</th><th>业务员</th><th>渠道</th><th>明细</th><th>金额</th><th>状态</th></tr></thead>
<tbody>
<?php foreach ($so as $o): ?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo e($o['customer']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td><?php echo $o['channel']==='export'?'外贸':'内贸'; ?></td>
<td class="muted"><?php echo count($o['_items']??[]); ?> 项</td>
<td>¥<?php echo e(number_format((float)($o['_amt'] ?? 0), 2)); ?></td>
<td><?php echo $soStatus[$o['status']] ?? '待处理'; ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($so)): ?><tr><td colspan="7" class="muted" style="text-align:center;padding:14px">无销售订单</td></tr><?php endif; ?>
</tbody>
</table>
</div>
<?php endif; ?>
<?php if ($type !== 'sales'): ?>
<h4 style="margin:18px 0 8px">采购订单(<?php echo count($po); ?></h4>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>订单号</th><th>供应商</th><th>采购员</th><th>明细</th><th>金额</th><th>状态</th></tr></thead>
<tbody>
<?php foreach ($po as $o): ?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo e($o['supplier_name']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td class="muted"><?php echo count($o['_items']??[]); ?> 项</td>
<td>¥<?php echo e(number_format((float)($o['_amt'] ?? 0), 2)); ?></td>
<td><?php echo $poStatus[$o['status']] ?? '待处理'; ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($po)): ?><tr><td colspan="6" class="muted" style="text-align:center;padding:14px">无采购订单</td></tr><?php endif; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
+25
View File
@@ -0,0 +1,25 @@
<?php
/** PSI 报表中心首页 */
/** @var int $poCount @var int $soCount @var int $obCount */
$cards = [
['label' => '采购订单明细', 'desc' => '按采购订单查看物料/成品明细', 'url' => 'PSI/reports/poDetail', 'icon' => 'file-text', 'n' => $poCount],
['label' => '销售/采购订单明细', 'desc' => '合并查看两类订单与金额', 'url' => 'PSI/reports/soPo', 'icon' => 'clipboard', 'n' => $soCount + $poCount],
['label' => '交付明细', 'desc' => '出库交付进度与未交订单', 'url' => 'PSI/reports/delivery', 'icon' => 'truck', 'n' => $obCount],
];
?>
<div class="page-head">
<div><h1>报表中心</h1><div class="desc">集中查看单据与单据之间的关联性</div></div>
</div>
<div class="stat-grid" style="grid-template-columns:repeat(auto-fill,minmax(280px,1fr))">
<?php foreach ($cards as $c): ?>
<a class="stat-card" href="<?php echo site_url($c['url']); ?>" style="text-decoration:none">
<div class="stat-ic"><?php echo admin_icon($c['icon'], 22); ?></div>
<div class="stat-main">
<div class="stat-num"><?php echo admin_icon($c['icon'], 18) ? '' : ''; ?><?php echo e($c['label']); ?></div>
<div class="stat-sub"><?php echo e($c['desc']); ?></div>
<div class="muted" style="font-size:12px;margin-top:6px">相关单据 <?php echo $c['n']; ?> 条</div>
</div>
</a>
<?php endforeach; ?>
</div>
+56
View File
@@ -0,0 +1,56 @@
<?php
/** PSI 销售出库表单 */
?>
<div class="page-head"><h1>新增销售出库</h1></div>
<div class="panel">
<form method="post" action="<?php echo site_url('PSI/sales/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>客户/买方</label><input name="customer" value="" placeholder="出口填海外客户名"></div>
<div class="field"><label>渠道</label>
<select name="channel">
<option value="domestic">内销(终端/批发)</option>
<option value="export">外贸出口</option>
</select>
</div>
<div class="field"><label>销售区域</label><input name="region" value="" placeholder="如:华东/海外"></div>
<div class="field"><label>出库类型</label>
<select name="item_type" id="item_type2">
<option value="product">成品</option>
<option value="material">物料</option>
</select>
</div>
<div class="field"><label>成品/物料</label>
<select name="item_id" id="item_id2">
<optgroup label="成品">
<?php foreach ($products as $p): ?><option value="<?php echo e($p['id']); ?>"><?php echo e($p['name']); ?>(库存<?php echo e((float)($p['stock'] ?? 0)); ?>)</option><?php endforeach; ?>
</optgroup>
<optgroup label="物料">
<?php foreach ($materials as $m): ?><option value="<?php echo e($m['id']); ?>"><?php echo e($m['name']); ?>(库存<?php echo e((float)($m['stock'] ?? 0)); ?>)</option><?php endforeach; ?>
</optgroup>
</select>
</div>
<div class="field"><label>数量 *</label><input name="qty" type="number" step="0.01" required></div>
<div class="field"><label>单价</label><input name="price" type="number" step="0.01" value="0"></div>
<div class="field"><label>批次/缸号</label><input name="batch_no" placeholder="出库批次/缸号"></div>
</div>
<div class="field"><label>备注</label><textarea name="remark" rows="2"></textarea></div>
<div class="field" style="margin-bottom:16px">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:normal">
<input type="checkbox" name="auto_print" value="1" checked style="width:auto;margin:0"> 保存后打印预览
</label>
</div>
<button class="btn-primary" type="submit">出库并提交</button>
<a class="btn-soft" href="<?php echo site_url('PSI/sales'); ?>">取消</a>
</form>
</div>
<script>
document.getElementById('item_type2').addEventListener('change', function(){
var type = this.value;
var sel = document.getElementById('item_id2');
Array.prototype.forEach.call(sel.querySelectorAll('optgroup'), function(og){
og.style.display = (og.label === (type==='material'?'物料':'成品')) ? '' : 'none';
});
sel.selectedIndex = 0;
});
</script>
+34
View File
@@ -0,0 +1,34 @@
<?php
/** PSI 销售出库列表 */
$chLabel = ['domestic' => '内销', 'export' => '外贸出口'];
?>
<div class="page-head">
<h1>销售出库</h1>
<a class="btn-primary" href="<?php echo site_url('PSI/sales/create'); ?>">+ 新增销售</a>
</div>
<div class="panel">
<p class="muted">支持内销与外贸出口。提交后自动扣减库存,库存不足将被拦截。</p>
<table class="tbl">
<thead><tr><th>单号</th><th>客户</th><th>渠道</th><th>区域</th><th>数量</th><th>单价</th><th>金额</th><th>日期</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($sales as $s): ?>
<tr>
<td><?php echo e($s['order_no']); ?></td>
<td><?php echo e($s['customer'] ?? ''); ?></td>
<td><?php echo e($chLabel[$s['channel'] ?? ''] ?? $s['channel'] ?? ''); ?></td>
<td><?php echo e($s['region'] ?? ''); ?></td>
<td><?php echo e((float)($s['qty'] ?? 0)); ?></td>
<td>¥<?php echo e(number_format((float)($s['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($s['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($s['created_at'] ?? ''); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/sales/show/' . $s['id']); ?>">查看</a>
<a href="<?php echo site_url('PSI/sales/print/' . $s['id']); ?>" target="_blank">打印</a>
<a class="del" href="<?php echo site_url('PSI/sales/destroy/' . $s['id']); ?>" data-confirm="删除不会回滚库存,确认?">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($sales)): ?><tr><td colspan="9" class="muted">暂无销售记录</td></tr><?php endif; ?>
</tbody>
</table>
</div>
+125
View File
@@ -0,0 +1,125 @@
<?php
/** PSI 销售订单录入/编辑 */
/** @var array|null $o @var array $items @var array $products */
$isEdit = !empty($o);
$prodMap = [];
foreach ($products as $p) { $prodMap[(int)$p['id']] = ['name' => $p['name'], 'spec' => $p['spec'] ?? '', 'unit' => $p['unit'] ?? '', 'price' => (float)($p['price'] ?? 0)]; }
?>
<div class="page-head">
<div><h1><?php echo $isEdit ? '编辑销售订单' : '新建销售订单'; ?></h1><div class="desc">填写客户与商品明细,保存后即可打印 / 据此出库</div></div>
<a class="btn-ghost" href="<?php echo site_url('PSI/sales_orders'); ?>">← 返回</a>
</div>
<div class="panel form-card">
<form method="post" action="<?php echo site_url($isEdit ? ('PSI/sales_orders/update/' . $o['id']) : 'PSI/sales_orders/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-row">
<label>客户 <span class="req">*</span></label>
<input type="text" name="customer" value="<?php echo e($o['customer'] ?? ''); ?>" required placeholder="客户名称">
</div>
<div class="form-row">
<label>业务员</label>
<input type="text" name="salesman" value="<?php echo e($o['salesman'] ?? ($_SESSION['admin_name'] ?? '')); ?>" placeholder="默认当前登录人">
</div>
<div class="radio-row" style="margin-bottom:16px">
<label class="radio"><input type="radio" name="channel" value="domestic" <?php echo (!empty($o) && $o['channel']==='export')?'':'checked'; ?>> 内贸</label>
<label class="radio"><input type="radio" name="channel" value="export" <?php echo (!empty($o) && $o['channel']==='export')?'checked':''; ?>> 外贸</label>
</div>
<div class="form-row">
<label>地区</label>
<input type="text" name="region" value="<?php echo e($o['region'] ?? ''); ?>" placeholder="如:华东 / 北美">
</div>
<div class="form-row">
<label>交货日期</label>
<input type="date" name="delivery_date" value="<?php echo e($o['delivery_date'] ?? ''); ?>">
</div>
<div class="form-row">
<label>备注</label>
<textarea name="remark" rows="2" placeholder="选填"><?php echo e($o['remark'] ?? ''); ?></textarea>
</div>
<div class="form-row">
<label>商品明细 <span class="req">*</span></label>
<div class="table-wrap">
<table class="tbl" id="itemTbl">
<thead><tr>
<th style="width:160px">关联成品</th><th>名称</th><th>规格</th><th>单位</th>
<th>数量</th><th>单价</th><th>金额</th><th></th>
</tr></thead>
<tbody id="itemBody"></tbody>
</table>
</div>
<button type="button" class="btn" id="addRow" style="margin-top:10px"><?php echo admin_icon('plus', 16); ?> 添加明细</button>
</div>
<div class="form-row" style="margin-bottom:14px">
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-weight:normal">
<input type="checkbox" name="auto_print" value="1" checked style="width:auto;margin:0"> 保存后打印预览
</label>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">保存</button>
<a class="btn-ghost" href="<?php echo site_url('PSI/sales_orders'); ?>">取消</a>
</div>
</form>
</div>
<script>
const PROD = <?php echo json_encode($prodMap, JSON_UNESCAPED_UNICODE); ?>;
let ROW = 0;
function newRow(p) {
p = p || {};
const tr = document.createElement('tr');
tr.className = 'item-row';
tr.innerHTML = `
<td><select class="prod-sel" style="width:100%">
<option value="0">手动输入</option>
${Object.keys(PROD).map(id=>`<option value="${id}">${PROD[id].name}</option>`).join('')}
</select>
<input type="hidden" name="items[${ROW}][product_id]" class="pid" value="${p.product_id||0}"></td>
<td><input type="text" name="items[${ROW}][name]" value="${p.name||''}" required style="width:100%"></td>
<td><input type="text" name="items[${ROW}][spec]" value="${p.spec||''}" style="width:90px"></td>
<td><input type="text" name="items[${ROW}][unit]" value="${p.unit||''}" style="width:50px"></td>
<td><input type="number" min="1" name="items[${ROW}][qty]" value="${p.qty||1}" class="qty" style="width:64px"></td>
<td><input type="number" step="0.01" min="0" name="items[${ROW}][price]" value="${p.price||0}" class="price" style="width:84px"></td>
<td class="amt" style="white-space:nowrap">¥0.00</td>
<td><button type="button" class="row-del" title="删除">×</button></td>`;
ROW++;
tr.querySelector('.prod-sel').addEventListener('change', e=>{
const id = e.target.value;
if (PROD[id]) {
const d = PROD[id];
tr.querySelector('input[name$="[name]"]').value = d.name;
tr.querySelector('input[name$="[spec]"]').value = d.spec;
tr.querySelector('input[name$="[unit]"]').value = d.unit;
tr.querySelector('input[name$="[price]"]').value = d.price;
tr.querySelector('.pid').value = id;
calc(tr);
}
});
tr.querySelector('.qty').addEventListener('input', ()=>calc(tr));
tr.querySelector('.price').addEventListener('input', ()=>calc(tr));
tr.querySelector('.row-del').addEventListener('click', ()=>tr.remove());
return tr;
}
function calc(tr){
const q = parseFloat(tr.querySelector('.qty').value)||0;
const p = parseFloat(tr.querySelector('.price').value)||0;
tr.querySelector('.amt').textContent = '¥' + (q*p).toFixed(2);
}
document.getElementById('addRow').addEventListener('click', ()=>document.getElementById('itemBody').appendChild(newRow()));
<?php if (!empty($items)): ?>
<?php foreach ($items as $it): ?>
document.getElementById('itemBody').appendChild(newRow({
product_id: <?php echo (int)($it['product_id'] ?? 0); ?>,
name: <?php echo json_encode($it['name'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
spec: <?php echo json_encode($it['spec'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
unit: <?php echo json_encode($it['unit'] ?? '', JSON_UNESCAPED_UNICODE); ?>,
qty: <?php echo (int)($it['qty'] ?? 1); ?>,
price:<?php echo (float)($it['price'] ?? 0); ?>
}));
<?php endforeach; ?>
<?php else: ?>
document.getElementById('itemBody').appendChild(newRow());
<?php endif; ?>
</script>
+33
View File
@@ -0,0 +1,33 @@
<?php
/** PSI 销售订单打印正文(由 psi_print_shell 包裹) */
/** @var array $o @var array $items */
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
$chn = $o['channel'] === 'export' ? '外贸' : '内贸';
?>
<h2>销售订单</h2>
<div class="sub"><?php echo e($o['order_no']); ?></div>
<div class="meta">
<span><b>客户:</b><?php echo e($o['customer']); ?></span>
<span><b>业务员:</b><?php echo e($o['salesman']); ?></span>
<span><b>渠道:</b><?php echo $chn . ($o['region'] ? ' / ' . e($o['region']) : ''); ?></span>
<span><b>交货日期:</b><?php echo e($o['delivery_date'] ?? '—'); ?></span>
<span><b>下单:</b><?php echo e($o['created_at']); ?></span>
</div>
<table>
<thead><tr><th>商品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<?php foreach ($items as $it): ?>
<tr>
<td><?php echo e($it['name']); ?></td>
<td><?php echo e($it['spec']); ?></td>
<td><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot><tr><th colspan="5" style="text-align:right">合计</th><th>¥<?php echo e(number_format($amt, 2)); ?></th></tr></tfoot>
</table>
<?php if ($o['remark']): ?><p style="font-size:13px;color:#374151;margin-top:10px"><b>备注:</b><?php echo e($o['remark']); ?></p><?php endif; ?>
<div class="sign"><span>制单:<?php echo e($o['salesman']); ?></span><span>客户签字:____________</span></div>
+57
View File
@@ -0,0 +1,57 @@
<?php
/** PSI 销售订单详情 */
/** @var array $o @var array $items */
$soStatus = [
'pending' => ['label' => '待处理', 'cls' => 'tag-gray'],
'partial' => ['label' => '部分交付', 'cls' => 'tag-amber'],
'delivered'=> ['label' => '已交付', 'cls' => 'tag-green'],
'closed' => ['label' => '已关闭', 'cls' => 'tag-gray'],
];
$s = $soStatus[$o['status']] ?? $soStatus['pending'];
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $items));
?>
<div class="page-head">
<div><h1>销售订单详情</h1><div class="desc">订单号 <?php echo e($o['order_no']); ?></div></div>
<div style="display:flex;gap:10px">
<a class="btn-ghost" href="<?php echo site_url('PSI/sales_orders/print/' . $o['id']); ?>" target="_blank"><?php echo admin_icon('printer', 16); ?> 打印</a>
<a class="btn-ghost" href="<?php echo site_url('PSI/sales_orders'); ?>">← 返回</a>
</div>
</div>
<div class="panel two-col">
<table class="tbl">
<tr><th>客户</th><td><?php echo e($o['customer']); ?></td></tr>
<tr><th>业务员</th><td><?php echo e($o['salesman']); ?></td></tr>
<tr><th>渠道</th><td><?php echo $o['channel'] === 'export' ? '外贸' : '内贸'; ?><?php if ($o['region']): ?> · <?php echo e($o['region']); ?><?php endif; ?></td></tr>
<tr><th>状态</th><td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td></tr>
<tr><th>交货日期</th><td><?php echo e($o['delivery_date'] ?? '—'); ?></td></tr>
<tr><th>备注</th><td class="muted"><?php echo e($o['remark'] ?: '—'); ?></td></tr>
</table>
</div>
<div class="panel">
<div class="panel-bar"><h3>商品明细</h3><span class="muted">合计 ¥<?php echo e(number_format($amt, 2)); ?></span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>商品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th><th>已交付</th><th>未交付</th></tr></thead>
<tbody>
<?php foreach ($items as $it): $remain = max(0, (int)($it['qty'] ?? 0) - (int)($it['delivered_qty'] ?? 0)); ?>
<tr>
<td><?php echo e($it['name']); ?></td>
<td class="muted"><?php echo e($it['spec']); ?></td>
<td class="muted"><?php echo e($it['unit']); ?></td>
<td><?php echo e($it['qty']); ?></td>
<td>¥<?php echo e(number_format((float)($it['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format((float)($it['amount'] ?? 0), 2)); ?></td>
<td><?php echo e($it['delivered_qty'] ?? 0); ?></td>
<td><?php echo $remain; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div style="margin-top:16px;display:flex;gap:10px">
<a class="btn-primary" href="<?php echo site_url('PSI/sales_orders/edit/' . $o['id']); ?>">编辑</a>
<a class="btn-ghost" href="<?php echo site_url('PSI/outbounds/create?so=' . $o['order_no']); ?>"><?php echo admin_icon('package', 16); ?> 据此出库</a>
</div>
</div>
+52
View File
@@ -0,0 +1,52 @@
<?php
/** PSI 销售订单列表 */
/** @var array $orders */
$soStatus = [
'pending' => ['label' => '待处理', 'cls' => 'tag-gray'],
'partial' => ['label' => '部分交付', 'cls' => 'tag-amber'],
'delivered'=> ['label' => '已交付', 'cls' => 'tag-green'],
'closed' => ['label' => '已关闭', 'cls' => 'tag-gray'],
];
?>
<div class="page-head">
<div><h1>销售订单</h1><div class="desc">录入客户销售订单,可关联出库单进行交付(直接打印)</div></div>
<a class="btn-primary" href="<?php echo site_url('PSI/sales_orders/create'); ?>"><?php echo admin_icon('plus', 16); ?> 新建销售订单</a>
</div>
<div class="panel">
<div class="table-wrap">
<table class="tbl">
<thead><tr>
<th>订单号</th><th>客户</th><th>业务员</th><th>渠道</th><th>明细</th>
<th>金额</th><th>状态</th><th>交货日期</th><th>操作</th>
</tr></thead>
<tbody>
<?php foreach ($orders as $o):
$amt = array_sum(array_map(fn($i) => (float)($i['amount'] ?? 0), $o['_items'] ?? []));
$s = $soStatus[$o['status']] ?? $soStatus['pending'];
?>
<tr>
<td><?php echo e($o['order_no']); ?></td>
<td><?php echo e($o['customer']); ?></td>
<td><?php echo e($o['salesman']); ?></td>
<td><?php echo $o['channel'] === 'export' ? '外贸' : '内贸'; ?></td>
<td class="muted"><?php echo count($o['_items'] ?? []); ?> 项</td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
<td><span class="tag-mini <?php echo $s['cls']; ?>"><?php echo $s['label']; ?></span></td>
<td class="muted"><?php echo e($o['delivery_date'] ?? '—'); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/sales_orders/show/' . $o['id']); ?>">详情</a>
<a href="<?php echo site_url('PSI/sales_orders/print/' . $o['id']); ?>" target="_blank">打印</a>
<a href="<?php echo site_url('PSI/sales_orders/edit/' . $o['id']); ?>">编辑</a>
<a href="<?php echo site_url('PSI/outbounds/create?so=' . $o['order_no']); ?>" class="link-ok">出库</a>
<form method="post" class="inline-form" action="<?php echo site_url('PSI/sales_orders/destroy/' . $o['id']); ?>" data-confirm="确认删除该销售订单?">
<?php echo csrf_field(); ?><button class="link-danger" type="submit">删除</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($orders)): ?><tr><td colspan="9" class="muted" style="text-align:center;padding:24px">暂无销售订单</td></tr><?php endif; ?>
</tbody>
</table>
</div>
</div>
+30
View File
@@ -0,0 +1,30 @@
<?php
/** PSI 销售出库打印正文(由 psi_print_shell 包裹) */
/** @var array $s @var array $item */
$chn = ($s['channel'] ?? '') === 'export' ? '外贸出口' : '内销';
$amt = (float)($s['qty'] ?? 0) * (float)($s['price'] ?? 0);
?>
<h2>销售出库单</h2>
<div class="sub"><?php echo e($s['order_no']); ?></div>
<div class="meta">
<span><b>客户:</b><?php echo e($s['customer']); ?></span>
<span><b>渠道:</b><?php echo $chn . ($s['region'] ? ' / ' . e($s['region']) : ''); ?></span>
<span><b>批次/缸号:</b><?php echo e($s['batch_no'] ?: '—'); ?></span>
<span><b>出库日期:</b><?php echo e($s['created_at']); ?></span>
</div>
<table>
<thead><tr><th>物品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<tr>
<td><?php echo e($item['name'] ?? '—'); ?></td>
<td><?php echo e($item['spec'] ?? ''); ?></td>
<td><?php echo e($item['unit'] ?? ''); ?></td>
<td><?php echo e($s['qty'] ?? 0); ?></td>
<td>¥<?php echo e(number_format((float)($s['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
</tr>
</tbody>
<tfoot><tr><th colspan="5" style="text-align:right">合计</th><th>¥<?php echo e(number_format($amt, 2)); ?></th></tr></tfoot>
</table>
<?php if ($s['remark']): ?><p style="font-size:13px;color:#374151;margin-top:10px"><b>备注:</b><?php echo e($s['remark']); ?></p><?php endif; ?>
<div class="sign"><span>发货:____________</span><span>收货签字:____________</span></div>
+43
View File
@@ -0,0 +1,43 @@
<?php
/** PSI 销售出库详情 */
/** @var array $s @var array $item */
$chn = ($s['channel'] ?? '') === 'export' ? '外贸出口' : '内销';
$amt = (float)($s['qty'] ?? 0) * (float)($s['price'] ?? 0);
?>
<div class="page-head">
<div><h1>销售出库详情</h1><div class="desc">单号 <?php echo e($s['order_no']); ?></div></div>
<div style="display:flex;gap:10px">
<a class="btn-ghost" href="<?php echo site_url('PSI/sales/print/' . $s['id']); ?>" target="_blank"><?php echo admin_icon('printer', 16); ?> 打印</a>
<a class="btn-ghost" href="<?php echo site_url('PSI/sales'); ?>">← 返回</a>
</div>
</div>
<div class="panel two-col">
<table class="tbl">
<tr><th>客户</th><td><?php echo e($s['customer'] ?? '—'); ?></td></tr>
<tr><th>渠道</th><td><?php echo $chn; ?></td></tr>
<tr><th>区域</th><td><?php echo e($s['region'] ?: '—'); ?></td></tr>
<tr><th>批次/缸号</th><td><?php echo e($s['batch_no'] ?: '—'); ?></td></tr>
<tr><th>出库日期</th><td><?php echo e($s['created_at'] ?? '—'); ?></td></tr>
<tr><th>备注</th><td class="muted"><?php echo e($s['remark'] ?: '—'); ?></td></tr>
</table>
</div>
<div class="panel">
<div class="panel-bar"><h3>出库明细</h3><span class="muted">合计 ¥<?php echo e(number_format($amt, 2)); ?></span></div>
<div class="table-wrap">
<table class="tbl">
<thead><tr><th>物品</th><th>规格</th><th>单位</th><th>数量</th><th>单价</th><th>金额</th></tr></thead>
<tbody>
<tr>
<td><?php echo e($item['name'] ?? '—'); ?></td>
<td class="muted"><?php echo e($item['spec'] ?? ''); ?></td>
<td class="muted"><?php echo e($item['unit'] ?? ''); ?></td>
<td><?php echo e($s['qty'] ?? 0); ?></td>
<td>¥<?php echo e(number_format((float)($s['price'] ?? 0), 2)); ?></td>
<td>¥<?php echo e(number_format($amt, 2)); ?></td>
</tr>
</tbody>
</table>
</div>
</div>
+29
View File
@@ -0,0 +1,29 @@
<?php
/** PSI 库存流水 */
?>
<div class="page-head">
<h1>库存流水</h1>
<p class="sub">所有采购入库 / 销售出库 / 手动调整 的变动记录</p>
</div>
<div class="panel">
<table class="tbl">
<thead><tr><th>时间</th><th>类型</th><th>名称</th><th>方向</th><th>数量</th><th>批次/缸号</th><th>关联单号</th></tr></thead>
<tbody>
<?php foreach ($moves as $mv): ?>
<tr>
<td><?php echo e($mv['created_at'] ?? ''); ?></td>
<td><?php echo $mv['item_type'] === 'product' ? '成品' : '物料'; ?></td>
<td><?php echo e($nameMap[($mv['item_type'] ?? 'product') . ':' . ($mv['item_id'] ?? 0)] ?? ('#' . ($mv['item_id'] ?? ''))); ?></td>
<td>
<?php if (($mv['direction'] ?? '') === 'in'): ?><span class="tag-in">入库 +</span>
<?php else: ?><span class="tag-out">出库 -</span><?php endif; ?>
</td>
<td><?php echo e((float)($mv['qty'] ?? 0)); ?></td>
<td><?php echo e($mv['batch_no'] ?? ''); ?></td>
<td><?php echo e($mv['ref_no'] ?? ''); ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($moves)): ?><tr><td colspan="7" class="muted">暂无库存流水</td></tr><?php endif; ?>
</tbody>
</table>
</div>
+42
View File
@@ -0,0 +1,42 @@
<?php
/** PSI 供应商表单 */
$s = $supplier;
$isEdit = !empty($s);
$typeOpts = ['面料商' => '面料商', '辅料商' => '辅料商', '成衣加工厂' => '成衣加工厂', 'OEM' => 'OEM', '物流' => '物流', '其他' => '其他'];
$gradeOpts = ['战略' => '战略', '合格' => '合格', '试用' => '试用', '淘汰' => '淘汰'];
$curType = $s['type'] ?? '';
$curGrade = $s['grade'] ?? '';
?>
<div class="page-head"><h1><?php echo $isEdit ? '编辑供应商' : '新增供应商'; ?></h1></div>
<div class="panel">
<form method="post" action="<?php echo site_url($isEdit ? 'PSI/suppliers/update/' . $s['id'] : 'PSI/suppliers/store'); ?>">
<?php echo csrf_field(); ?>
<div class="form-grid">
<div class="field"><label>名称 *</label><input name="name" value="<?php echo e($s['name'] ?? ''); ?>" required></div>
<div class="field"><label>供应商类型</label>
<select name="type">
<option value="">未设置</option>
<?php foreach ($typeOpts as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo $curType === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>等级</label>
<select name="grade">
<option value="">未设置</option>
<?php foreach ($gradeOpts as $k => $v): ?>
<option value="<?php echo $k; ?>" <?php echo $curGrade === $k ? 'selected' : ''; ?>><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="field"><label>联系人</label><input name="contact" value="<?php echo e($s['contact'] ?? ''); ?>"></div>
<div class="field"><label>电话</label><input name="phone" value="<?php echo e($s['phone'] ?? ''); ?>"></div>
<div class="field"><label>国家/地区</label><input name="country" value="<?php echo e($s['country'] ?? ''); ?>"></div>
<div class="field"><label>交期达成率(%)</label><input name="ontime_rate" type="number" step="0.01" value="<?php echo e($s['ontime_rate'] ?? '0'); ?>"></div>
<div class="field"><label>质检合格率(%)</label><input name="qc_rate" type="number" step="0.01" value="<?php echo e($s['qc_rate'] ?? '0'); ?>"></div>
</div>
<div class="field"><label>备注</label><textarea name="remark" rows="2"><?php echo e($s['remark'] ?? ''); ?></textarea></div>
<button class="btn-primary" type="submit">保存</button>
<a class="btn-soft" href="<?php echo site_url('PSI/suppliers'); ?>">取消</a>
</form>
</div>
+33
View File
@@ -0,0 +1,33 @@
<?php
/** PSI 供应商列表(面料商/辅料商/成衣加工厂/OEM) */
?>
<div class="page-head">
<h1>供应商管理</h1>
<a class="btn-primary" href="<?php echo site_url('PSI/suppliers/create'); ?>">+ 新增供应商</a>
</div>
<div class="panel">
<table class="tbl">
<thead><tr><th>ID</th><th>名称</th><th>类型</th><th>等级</th><th>联系人</th><th>电话</th><th>国家/地区</th><th>交期达成率</th><th>质检合格率</th><th>备注</th><th>操作</th></tr></thead>
<tbody>
<?php foreach ($suppliers as $s): ?>
<tr>
<td><?php echo e($s['id']); ?></td>
<td><?php echo e($s['name']); ?></td>
<td><?php echo e($s['type'] ?? ''); ?></td>
<td><?php echo e($s['grade'] ?? ''); ?></td>
<td><?php echo e($s['contact'] ?? ''); ?></td>
<td><?php echo e($s['phone'] ?? ''); ?></td>
<td><?php echo e($s['country'] ?? ''); ?></td>
<td><?php echo ($s['ontime_rate'] !== '' && (float)$s['ontime_rate'] != 0) ? e($s['ontime_rate']) . '%' : '—'; ?></td>
<td><?php echo ($s['qc_rate'] !== '' && (float)$s['qc_rate'] != 0) ? e($s['qc_rate']) . '%' : '—'; ?></td>
<td><?php echo e(mb_substr($s['remark'] ?? '', 0, 30)); ?></td>
<td class="row-actions">
<a href="<?php echo site_url('PSI/suppliers/edit/' . $s['id']); ?>">编辑</a>
<a href="<?php echo site_url('PSI/suppliers/destroy/' . $s['id']); ?>" data-confirm="确认删除?">删除</a>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($suppliers)): ?><tr><td colspan="11" class="muted">暂无供应商</td></tr><?php endif; ?>
</tbody>
</table>
</div>