-
request_quote
-
报价列表正在配置中
+
+
+
+ @if ($quoteSnapshot['available'])
+
+ 共 {{ count($quotes) }} 个报价版本
+
+ verified_user
+ 原始报价规则保留,当前页面不重新计算金额
+
+
+
+
+
+
+
+ | 报价版本 |
+ 快递公司 |
+ 报价类型 |
+ 原始范围 |
+ 数据规模 |
+ 执行日期 |
+ 签章 |
+ 资料状态 |
+ 操作 |
+
+
+
+
+
+
+
+
+
filter_alt_off
+
没有符合当前条件的报价
+
重置筛选后可查看全部已导入版本。
+
+
+
+
+ @else
+
+
+
file_present
+
{{ $quoteSnapshot['message'] }}
+
报价页面仍可访问,重新导入后会显示工作表列表。
+
+
+ @endif
+
+ @if ($quoteSnapshot['available'])
+
+
+
+
+ - 版本号
+ - 快递公司
+ - 报价类型
+ - 原始范围
+ - 执行日期
+ - 公式单元格
+
+
+
+
+
+
+ @endif
diff --git a/tests/Feature/Business/QuoteManagementPageTest.php b/tests/Feature/Business/QuoteManagementPageTest.php
new file mode 100644
index 00000000..36f59b9f
--- /dev/null
+++ b/tests/Feature/Business/QuoteManagementPageTest.php
@@ -0,0 +1,142 @@
+fixturePath = storage_path('framework/testing/quote-management-' . uniqid('', true) . '.json');
+ file_put_contents($this->fixturePath, json_encode([
+ 'sourcePath' => 'C:/private/报价单合并.xlsx',
+ 'sheets' => [
+ [
+ 'index' => 0,
+ 'name' => '新北中通报价',
+ 'address' => 'A1:D4',
+ 'values' => [
+ ['省份', '面单', '费率', "备注:\n执行时间:2025.12.01"],
+ [null, null, null, null],
+ ['江苏省', 3.8, 0.5, null],
+ ['安徽省', 3.8, 0.5, null],
+ ],
+ 'formulas' => [[], [], ['', '', '=B3/2', ''], []],
+ ],
+ [
+ 'index' => 1,
+ 'name' => '常州圆通-上楼',
+ 'address' => 'A1:H2',
+ 'values' => [
+ ['报价表', '常州圆通'],
+ ['江苏省', 4.2],
+ ],
+ 'formulas' => [[], []],
+ ],
+ [
+ 'index' => 2,
+ 'name' => '新德邦快递超长报价',
+ 'address' => 'A1:F2',
+ 'values' => [
+ ['0-1kg', '1kg以上'],
+ ['江苏省', 5.5],
+ ],
+ 'formulas' => [[], []],
+ ],
+ ],
+ ], JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
+
+ app()->instance(QuoteManagementSnapshot::class, new QuoteManagementSnapshot($this->fixturePath));
+ }
+
+ protected function tearDown(): void
+ {
+ if (isset($this->fixturePath) && is_file($this->fixturePath)) {
+ unlink($this->fixturePath);
+ }
+
+ parent::tearDown();
+ }
+
+ public function testQuoteManagementPageRendersImportedWorkbookVersions(): void
+ {
+ $this->user->attachPermission(
+ Permission::where('name', 'read-admin-panel')->firstOrFail()
+ );
+
+ $this->loginAs()
+ ->get(route('business.pages.show', [
+ 'section' => 'courier-payables',
+ 'page' => 'quote-management',
+ ]))
+ ->assertOk()
+ ->assertSeeText('报价管理')
+ ->assertSeeText('报价单合并.xlsx')
+ ->assertSeeText('报价名称')
+ ->assertSeeText('快递公司')
+ ->assertSeeText('资料状态')
+ ->assertSeeText('报价历史')
+ ->assertSeeText('发起报价变更')
+ ->assertSee('
', false)
+ ->assertSee('
', false)
+ ->assertSee('新北中通报价', false)
+ ->assertSee('常州圆通-上楼', false)
+ ->assertSee('2025-12-01', false)
+ ->assertSee('=B3/2', false)
+ ->assertSeeText('原始报价规则保留,当前页面不重新计算金额')
+ ->assertDontSee('报价列表正在配置中');
+ }
+
+ public function testQuoteManagementPageKeepsTheShellWhenThePrivateSnapshotIsMissing(): void
+ {
+ app()->instance(
+ QuoteManagementSnapshot::class,
+ new QuoteManagementSnapshot(storage_path('framework/testing/missing-quote-snapshot.json'))
+ );
+
+ $this->loginAs()
+ ->get(route('business.pages.show', [
+ 'section' => 'courier-payables',
+ 'page' => 'quote-management',
+ ]))
+ ->assertOk()
+ ->assertSeeText('尚未导入本机报价文件。')
+ ->assertSeeText('报价页面仍可访问')
+ ->assertDontSee('class="business-blank-page"', false);
+ }
+
+ public function testQuoteManagementPageRejectsUsersWithoutItsSidebarPermission(): void
+ {
+ $subject = 'user_' . $this->user->id;
+
+ setting()->set('system.sidebar_permissions', json_encode([
+ 'configured' => [$subject],
+ 'subjects' => [
+ $subject => ['courier-payables/freight-reconciliation'],
+ ],
+ ], JSON_UNESCAPED_UNICODE));
+
+ try {
+ $this->loginAs()->get(route('business.pages.show', [
+ 'section' => 'courier-payables',
+ 'page' => 'quote-management',
+ ]));
+ $this->fail('缺少报价管理页面权限的用户不应访问该页面。');
+ } catch (HttpException|HttpResponseException $exception) {
+ $status = method_exists($exception, 'getStatusCode')
+ ? $exception->getStatusCode()
+ : $exception->getResponse()->getStatusCode();
+
+ $this->assertSame(404, $status);
+ }
+ }
+}
--
2.47.2
From 833f2937165fb85191e2c2004385e48cd0b19857 Mon Sep 17 00:00:00 2001
From: limeng <1131177064@qq.com>
Date: Thu, 13 Aug 2026 10:18:57 +0800
Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8A=A5=E4=BB=B7?=
=?UTF-8?q?=E5=8F=98=E6=9B=B4=E5=85=A5=E5=8F=A3=E4=BA=A4=E4=BA=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../quote-management.blade.php | 277 +++++++++++++++++-
.../Business/QuoteManagementPageTest.php | 5 +
2 files changed, 278 insertions(+), 4 deletions(-)
diff --git a/resources/views/business/pages/courier-payables/quote-management.blade.php b/resources/views/business/pages/courier-payables/quote-management.blade.php
index 302f1094..582e9cd3 100644
--- a/resources/views/business/pages/courier-payables/quote-management.blade.php
+++ b/resources/views/business/pages/courier-payables/quote-management.blade.php
@@ -424,6 +424,16 @@
box-shadow: 0 4px 8px rgba(23, 23, 23, 0.10);
}
+ .quote-change-modal__panel {
+ grid-template-rows: auto minmax(0, 1fr);
+ width: min(42rem, calc(100vw - 3rem));
+ height: auto;
+ max-height: min(42rem, calc(100vh - 3rem));
+ margin: auto 1.5rem auto auto;
+ border: 1px solid var(--quote-border);
+ border-radius: 12px;
+ }
+
.quote-modal__header {
display: flex;
min-width: 0;
@@ -519,6 +529,86 @@
font-size: 0.7rem;
}
+ .quote-change-form {
+ display: grid;
+ min-height: 0;
+ grid-template-rows: minmax(0, 1fr) auto;
+ }
+
+ .quote-change-form__body {
+ display: grid;
+ gap: 1rem;
+ min-height: 0;
+ overflow-y: auto;
+ padding: 1.25rem;
+ }
+
+ .quote-change-form__grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 1rem;
+ }
+
+ .quote-change-form__field {
+ display: grid;
+ gap: 0.4rem;
+ min-width: 0;
+ }
+
+ .quote-change-form__field--full {
+ grid-column: 1 / -1;
+ }
+
+ .quote-change-form__label {
+ color: var(--quote-muted);
+ font-size: 0.75rem;
+ font-weight: 500;
+ }
+
+ .quote-change-form__required {
+ color: #B80000;
+ }
+
+ .quote-change-form__textarea {
+ min-height: 8rem;
+ resize: vertical;
+ padding: 0.65rem 0.75rem;
+ line-height: 1.5;
+ }
+
+ .quote-change-form__notice {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.5rem;
+ padding: 0.7rem 0.8rem;
+ border: 1px solid var(--quote-border);
+ border-radius: 8px;
+ background: var(--quote-accent-soft);
+ color: var(--quote-accent);
+ font-size: 0.75rem;
+ line-height: 1.5;
+ }
+
+ .quote-change-form__notice .material-icons-outlined {
+ flex: 0 0 auto;
+ font-size: 18px;
+ }
+
+ .quote-change-form__status {
+ min-height: 1.25rem;
+ color: #53793E;
+ font-size: 0.75rem;
+ }
+
+ .quote-change-form__footer {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ gap: 0.5rem;
+ padding: 0.85rem 1.25rem;
+ border-top: 1px solid var(--quote-border);
+ }
+
[hidden] {
display: none !important;
}
@@ -610,6 +700,29 @@
.quote-modal__panel {
width: 100%;
}
+
+ .quote-change-modal__panel {
+ width: calc(100% - 1rem);
+ max-height: calc(100vh - 1rem);
+ margin: auto 0.5rem;
+ }
+
+ .quote-change-form__grid {
+ grid-template-columns: 1fr;
+ }
+
+ .quote-change-form__field--full {
+ grid-column: auto;
+ }
+
+ .quote-change-form__footer {
+ flex-direction: column-reverse;
+ align-items: stretch;
+ }
+
+ .quote-change-form__footer .quote-button {
+ width: 100%;
+ }
}
@@ -681,7 +794,7 @@
history
报价历史
-