@@ -1618,7 +1643,7 @@
-
选择快递公司后自动带出工作平台的“电子签章经办人”(dzqzjbr);如资料未维护,可手工填写对方在 E 签宝实名绑定的手机号或邮箱。
+
选择快递公司后自动带出工作平台的“电子签章经办人”(dzqzjbr);如资料未维护,可手工填写对方在 E 签宝实名绑定的手机号或邮箱。
对方签署主体类型 *
@@ -2222,6 +2247,13 @@
var courierOptionsList = root.querySelector('[data-courier-options]');
var courierControl = root.querySelector('[data-courier-control]');
var courierLabel = root.querySelector('label[for="agreement-courier"]');
+ var partnerTypeInputs = Array.prototype.slice.call(root.querySelectorAll('[data-partner-type]'));
+ var supplierControl = root.querySelector('[data-supplier-control]');
+ var documentSelect = form.querySelector('[data-document-type]');
+ var documentOptions = Array.prototype.slice.call(documentSelect.options);
+ var currentPartnerType = 'courier';
+ var sendButton = root.querySelector('[data-sign-request-send]');
+ var esignAvailable = @json($esignConfigured);
var courierOptions = courierSelect ? Array.prototype.filter.call(courierSelect.options, function (option) {
return option.value !== '' && !option.disabled;
}).map(function (option) {
@@ -2712,6 +2744,49 @@
return select.options[select.selectedIndex];
}
+ function syncPartnerType() {
+ var selected = partnerTypeInputs.find(function (input) { return input.checked; });
+ var type = selected ? selected.value : 'courier';
+ var supplier = type === 'supplier';
+ if (type !== currentPartnerType) {
+ closeCourierOptions();
+ courierSelect.value = '';
+ courierSearch.value = '';
+ esignAccountInput.value = '';
+ delete esignAccountInput.dataset.autoFilled;
+ accountOrganizationInput.value = '';
+ operatorNameInput.value = '';
+ secondaryEsignAccountInput.value = '';
+ secondaryOperatorInput.value = '';
+ root.querySelector('[data-request-error]').textContent = '';
+ }
+ currentPartnerType = type;
+ courierControl.hidden = supplier;
+ courierSelect.disabled = supplier;
+ courierSearch.disabled = supplier;
+ supplierControl.hidden = !supplier;
+ courierLabel.htmlFor = supplier ? 'agreement-supplier-search' : courierSearch.id;
+ root.querySelector('[data-partner-name-label]').textContent = supplier ? '供应商名称' : '快递公司';
+ root.querySelector('[data-partner-account-help]').textContent = supplier
+ ? '供应商资料接入后可带出签署账号和经办人;发送前需核对对方 E 签宝实名信息。'
+ : '选择快递公司后自动带出工作平台的“电子签章经办人”(dzqzjbr);如资料未维护,可手工填写对方在 E 签宝实名绑定的手机号或邮箱。';
+ // Rebuild the small template list so unavailable options are absent on every browser.
+ var previousDocument = documentSelect.value;
+ documentSelect.replaceChildren();
+ documentOptions.forEach(function (option) {
+ var types = (option.dataset.partnerTypes || 'courier').split(' ');
+ if (types.indexOf(type) !== -1) documentSelect.appendChild(option);
+ });
+ if (Array.prototype.some.call(documentSelect.options, function (option) { return option.value === previousDocument; })) {
+ documentSelect.value = previousDocument;
+ } else {
+ documentSelect.value = 'account-proof';
+ }
+ sendButton.disabled = supplier || !esignAvailable;
+ sendButton.title = supplier ? '供应商资料尚未接入,暂不能发起签署' : (esignAvailable ? '推送至E签宝' : 'E签宝沙箱应用尚未配置');
+ sendButton.querySelector('span:last-child').textContent = supplier ? '供应商资料待接入' : '推送至E签宝';
+ }
+
function fieldValue(selector, fallback) {
var field = form.querySelector(selector);
return field && field.value.trim() ? field.value.trim() : fallback;
@@ -3159,7 +3234,7 @@
function refreshPreview() {
var documentOption = selectedDocument();
var templateType = documentOption.value;
- var courier = fieldValue('[name="courier_name"]', '快递公司');
+ var courier = currentPartnerType === 'supplier' ? '供应商' : fieldValue('[name="courier_name"]', '快递公司');
var companyName = fieldValue('[name="company_full_name"]', '待填写公司全称');
var accountAgreement = templateType === 'account-proof' || templateType === 'account-change';
var entityChange = templateType === 'entity-change';
@@ -3575,12 +3650,25 @@
announce('协议预览已刷新');
});
+ partnerTypeInputs.forEach(function (input) {
+ input.addEventListener('change', function () {
+ syncPartnerType();
+ refreshPreview();
+ announce(currentPartnerType === 'supplier' ? '已切换到供应商,资料尚未接入' : '已切换到快递公司');
+ });
+ });
+
form.querySelectorAll('input, select, textarea').forEach(function (control) {
control.addEventListener('input', refreshPreview);
control.addEventListener('change', refreshPreview);
});
form.addEventListener('submit', function (event) {
+ if (currentPartnerType === 'supplier') {
+ event.preventDefault();
+ root.querySelector('[data-request-error]').textContent = '供应商资料尚未接入,暂不能发起供应商签署。';
+ return;
+ }
refreshPreview();
if (!form.checkValidity()) {
event.preventDefault();
@@ -3652,6 +3740,7 @@
var initialUrl = new URL(window.location.href);
var initialView = initialUrl.searchParams.get('agreement_view') || 'tasks';
initializeCourierSearch();
+ syncPartnerType();
renderSubjectSelect();
renderSubjectList();
showTab(initialView, { updateUrl: false });
diff --git a/tests/Feature/Business/AgreementSigningPageTest.php b/tests/Feature/Business/AgreementSigningPageTest.php
index bb5b12e7..1e391090 100644
--- a/tests/Feature/Business/AgreementSigningPageTest.php
+++ b/tests/Feature/Business/AgreementSigningPageTest.php
@@ -62,6 +62,10 @@ class AgreementSigningPageTest extends FeatureTestCase
->assertSee('data-sign-request-send', false)
->assertDontSee('data-agreement-step-panel', false)
->assertSeeText('发起签章请求')
+ ->assertSeeText('合作方类型')
+ ->assertSee('name="partner_type" value="courier" checked', false)
+ ->assertSee('name="partner_type" value="supplier"', false)
+ ->assertSeeText('供应商资料尚未接入,暂不能选择或发起签署。')
->assertSeeText('快递公司')
->assertSee('data-courier-search', false)
->assertSee('placeholder="输入快递名称搜索"', false)
@@ -165,6 +169,9 @@ class AgreementSigningPageTest extends FeatureTestCase
]))
->assertOk()
->assertSee('
' . e($this->company->name) . ' | ', false)
+ ->assertSeeText('合作方类型')
+ ->assertSeeText('合作方名称')
+ ->assertSee('快递公司 | ', false)
->assertDontSee('张经理 | ', false);
}
diff --git a/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php b/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php
index e906b06a..9ec73219 100644
--- a/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php
+++ b/tests/Feature/Business/CourierAgreementSignatureWorkflowTest.php
@@ -53,6 +53,8 @@ class CourierAgreementSignatureWorkflowTest extends FeatureTestCase
$this->assertSame('flow-agreement-001', $signature->esign_sign_flow_id);
$this->assertSame('新北中通快递有限公司', $signature->organization_name);
$this->assertSame('2026-09-21', $signature->payload['signature_date']);
+ $this->assertSame('courier', $signature->payload['partner_type']);
+ $this->assertSame('快递公司', $signature->partnerTypeLabel());
Storage::disk('uploads')->assertExists($signature->source_pdf_path);
$this->assertSame('新北中通快递有限公司', $signature->payload['account_proof_account_name']);
@@ -71,6 +73,34 @@ class CourierAgreementSignatureWorkflowTest extends FeatureTestCase
$this->assertSame(1, CourierAgreementSignature::query()->count());
}
+ public function test_supplier_requests_are_rejected_before_creating_or_sending_any_document(): void
+ {
+ Http::preventStrayRequests();
+ $this->withExceptionHandling();
+ $payload = $this->accountProofPayload('supplier-not-connected');
+ $payload['partner_type'] = 'supplier';
+
+ $this->loginAs()->post(route('business.courier-agreement-signatures.store'), $payload)
+ ->assertSessionHasErrors(['partner_type' => '供应商资料尚未接入,暂不能发起供应商签署。请在资料接入后选择供应商。']);
+
+ $this->assertSame(0, CourierAgreementSignature::query()->count());
+ Http::assertNothingSent();
+ }
+
+ public function test_unknown_partner_type_is_rejected_before_sending(): void
+ {
+ Http::preventStrayRequests();
+ $this->withExceptionHandling();
+ $payload = $this->accountProofPayload('unknown-partner-type');
+ $payload['partner_type'] = 'unknown';
+
+ $this->loginAs()->post(route('business.courier-agreement-signatures.store'), $payload)
+ ->assertSessionHasErrors('partner_type');
+
+ $this->assertSame(0, CourierAgreementSignature::query()->count());
+ Http::assertNothingSent();
+ }
+
public function test_account_proof_accepts_private_account_holder_name_different_from_company_name(): void
{
$this->fakeEsign();