提交
This commit is contained in:
1 parent
cdaa0ac273
commit
b7cd657f32
32 files changed
+2885
-1936
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
56839
|
||||
35093
|
||||
@@ -2811,7 +2811,7 @@ def align_fq_payment_details_payload(
|
||||
pay: BizProtocolPayment,
|
||||
details: Optional[list],
|
||||
) -> list:
|
||||
if pay.pay_mode != "fq" or not pay.installment_count or int(pay.installment_count) < 1:
|
||||
if pay.pay_mode not in ("fq", "djfq") or not pay.installment_count or int(pay.installment_count) < 1:
|
||||
return list(details or [])
|
||||
count = int(pay.installment_count)
|
||||
rows = [_normalize_fields(dict(d)) for d in (details or [])]
|
||||
|
||||
@@ -48,22 +48,16 @@ def validate_payment_details_for_save(
|
||||
yjf_rows = [r for r in rows if (r.get("pay_status") or r.get("payStatus")) == "yjf"]
|
||||
|
||||
if pay_mode == "dj":
|
||||
if len(dfj_rows) > 1:
|
||||
raise ValueError("趸交模式仅允许一条待缴费明细")
|
||||
remaining = round(contract - paid_sum, 2)
|
||||
if dfj_rows:
|
||||
due = _dec(
|
||||
dfj_rows[0].get("due_amount")
|
||||
if dfj_rows[0].get("due_amount") is not None
|
||||
else dfj_rows[0].get("dueAmount")
|
||||
total_due = sum(
|
||||
_dec(r.get("due_amount") if r.get("due_amount") is not None else r.get("dueAmount"))
|
||||
for r in rows
|
||||
)
|
||||
if contract and abs(total_due - contract) > 0.015:
|
||||
raise ValueError(
|
||||
f"趸交各明细应缴金额之和应为 {contract:.2f},当前为 {total_due:.2f}"
|
||||
)
|
||||
expected = remaining if yjf_rows else contract
|
||||
if abs(due - expected) > 0.015:
|
||||
raise ValueError(
|
||||
f"趸交待缴金额应为 {expected:.2f},当前为 {due:.2f}"
|
||||
)
|
||||
|
||||
elif pay_mode == "fq":
|
||||
elif pay_mode in ("fq", "djfq"):
|
||||
count = int(installment_count or 0)
|
||||
if count < 1:
|
||||
raise ValueError("分期模式须填写分期期数")
|
||||
@@ -76,8 +70,6 @@ def validate_payment_details_for_save(
|
||||
if is_legacy_installment_ratios(values, Decimal(str(contract)) if contract else None):
|
||||
if abs(sum(values) - 100.0) > 0.01:
|
||||
raise ValueError("缴费比例之和须等于 100%")
|
||||
elif contract and abs(sum(values) - contract) > 0.015:
|
||||
raise ValueError("分期金额合计须等于合同金额")
|
||||
if len(rows) != count:
|
||||
raise ValueError(f"分期明细条数应等于分期期数({count})")
|
||||
fq_forbidden = frozenset({"jfqrz", "tfqrz"})
|
||||
@@ -85,12 +77,6 @@ def validate_payment_details_for_save(
|
||||
status = (r.get("pay_status") or r.get("payStatus") or "dfj").strip()
|
||||
if status in fq_forbidden:
|
||||
raise ValueError("分期模式下存在不可保存的缴费状态")
|
||||
total_due = sum(
|
||||
_dec(r.get("due_amount") if r.get("due_amount") is not None else r.get("dueAmount"))
|
||||
for r in rows
|
||||
)
|
||||
if contract and abs(total_due - contract) > 0.015:
|
||||
raise ValueError("分期各期应缴金额之和应等于合同金额")
|
||||
if yjf_rows:
|
||||
max_paid_no = max(
|
||||
int(r.get("installment_no") or r.get("installmentNo") or 0)
|
||||
|
||||
@@ -14,7 +14,7 @@ from app.models.models import (
|
||||
BizProtocolPaymentDetail,
|
||||
)
|
||||
|
||||
_PAY_MODE_LABELS = {"dj": "趸交", "fq": "分期"}
|
||||
_PAY_MODE_LABELS = {"dj": "趸交", "fq": "分期", "djfq": "趸交+分期"}
|
||||
_PAY_STATUS_LABELS = {
|
||||
"dfj": "待缴费",
|
||||
"jfqrz": "缴费确认中",
|
||||
@@ -57,7 +57,7 @@ def _protocol_status_hint(pay_mode: str, statuses: List[str]) -> str:
|
||||
paid = counts.get("yjf", 0)
|
||||
confirm = counts.get("jfqrz", 0)
|
||||
pending = counts.get("dfj", 0)
|
||||
if pay_mode == "fq":
|
||||
if pay_mode in ("fq", "djfq"):
|
||||
parts: List[str] = ["分期"]
|
||||
if paid:
|
||||
parts.append(f"{paid} 期已缴")
|
||||
@@ -105,7 +105,7 @@ def _fmt_ymd(val: Any) -> str:
|
||||
def _payment_detail_row(d: BizProtocolPaymentDetail, pay_mode: str, idx: int) -> Dict[str, Any]:
|
||||
st = (d.pay_status or "").strip()
|
||||
inst_no = d.installment_no
|
||||
if pay_mode == "fq" and inst_no is not None:
|
||||
if pay_mode in ("fq", "djfq") and inst_no is not None:
|
||||
label = f"第{inst_no}期"
|
||||
else:
|
||||
label = f"缴费{idx + 1}"
|
||||
@@ -153,7 +153,7 @@ def build_protocol_payment_summary(
|
||||
"receivedAmount": received,
|
||||
"pendingAmount": pending,
|
||||
"statusHint": hint,
|
||||
"installmentCount": len(detail_rows) if pay_mode == "fq" else None,
|
||||
"installmentCount": len(detail_rows) if pay_mode in ("fq", "djfq") else None,
|
||||
"paymentDetails": detail_rows,
|
||||
**overall,
|
||||
}
|
||||
|
||||
@@ -14,18 +14,29 @@ class TestValidatePaymentDetailsForSave(unittest.TestCase):
|
||||
[{"payStatus": "dfj", "dueAmount": 10000}],
|
||||
)
|
||||
|
||||
def test_dj_rejects_multiple_dfj(self):
|
||||
def test_dj_allows_multiple_dfj_when_sum_matches(self):
|
||||
validate_payment_details_for_save(
|
||||
"dj",
|
||||
10000,
|
||||
None,
|
||||
[
|
||||
{"payStatus": "dfj", "dueAmount": 2000},
|
||||
{"payStatus": "dfj", "dueAmount": 8000},
|
||||
],
|
||||
)
|
||||
|
||||
def test_dj_rejects_multiple_dfj_wrong_sum(self):
|
||||
with self.assertRaises(ValueError) as ctx:
|
||||
validate_payment_details_for_save(
|
||||
"dj",
|
||||
10000,
|
||||
None,
|
||||
[
|
||||
{"payStatus": "dfj", "dueAmount": 5000},
|
||||
{"payStatus": "dfj", "dueAmount": 5000},
|
||||
{"payStatus": "dfj", "dueAmount": 2000},
|
||||
{"payStatus": "dfj", "dueAmount": 7000},
|
||||
],
|
||||
)
|
||||
self.assertIn("仅允许一条待缴费", str(ctx.exception))
|
||||
self.assertIn("之和应为", str(ctx.exception))
|
||||
|
||||
def test_dj_partial_paid_remaining(self):
|
||||
validate_payment_details_for_save(
|
||||
@@ -50,6 +61,20 @@ class TestValidatePaymentDetailsForSave(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
def test_djfq_same_as_fq(self):
|
||||
validate_payment_details_for_save(
|
||||
"djfq",
|
||||
41000,
|
||||
4,
|
||||
[
|
||||
{"payStatus": "dfj", "installmentNo": 1, "dueAmount": 29360},
|
||||
{"payStatus": "dfj", "installmentNo": 2, "dueAmount": 3880},
|
||||
{"payStatus": "dfj", "installmentNo": 3, "dueAmount": 3880},
|
||||
{"payStatus": "dfj", "installmentNo": 4, "dueAmount": 3880},
|
||||
],
|
||||
installment_ratios=[29360, 3880, 3880, 3880],
|
||||
)
|
||||
|
||||
def test_fq_count_mismatch(self):
|
||||
with self.assertRaises(ValueError):
|
||||
validate_payment_details_for_save(
|
||||
|
||||
@@ -0,0 +1,596 @@
|
||||
# 采集协议单 · 缴费默认定价 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 按「样本数 × 缴费模式」在新建/首次选模式时填充默认合同金额与分期模板;支持双样本 `djfq`(趸交+分期);趸交允许多条缴费明细;样本数/样本价变化不再自动改合同金额。
|
||||
|
||||
**Architecture:** 前端新增 `protocol-payment-presets.ts` 集中定价表与 `applyPaymentPreset()`;`PayMode` 扩展为 `dj | fq | djfq`,分期逻辑通过 `isInstallmentPayMode()` 统一处理 `fq` 与 `djfq`;后端校验放宽趸交多 `dfj`、合计校验,`djfq` 走分期分支;方案 B 用 `paymentDefaultsApplied` 标记避免重复填默认。
|
||||
|
||||
**Tech Stack:** Vue 3 · TypeScript · Element Plus · FastAPI · Python unittest · `tsx`(前端纯函数冒烟)
|
||||
|
||||
**Design spec:** `docs/superpowers/specs/2026-07-06-protocol-payment-defaults-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| 文件 | 职责 |
|
||||
|------|------|
|
||||
| `web-admin/src/utils/protocol-payment-presets.ts` | **新建** 定价表、`getActiveSampleCount`、`applyPaymentPreset`、`isInstallmentPayMode` |
|
||||
| `web-admin/scripts/test-protocol-payment-presets.ts` | **新建** 定价表冒烟脚本(`tsx` 运行) |
|
||||
| `web-admin/src/utils/protocol-pay-mode-switch.ts` | `PayMode` 含 `djfq`;趸交多明细;切换时用 preset 重建 |
|
||||
| `web-admin/src/utils/protocol-payment-installment.ts` | `alignFq*` / `syncFq*` 识别 `djfq` |
|
||||
| `web-admin/src/utils/status-tag-registry.ts` | `djfq` 标签 |
|
||||
| `web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue` | 模式 UI、首次默认、去掉样本价联动、保存校验 |
|
||||
| `web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue` | `djfq` 只读展示 |
|
||||
| `web-admin/src/components/business/protocol-payment-detail-readonly/index.vue` | 分期字段展示含 `djfq` |
|
||||
| `web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue` | 摘要 `djfq` 按分期展示 |
|
||||
| `web-admin/src/utils/protocol-standard-import-parse.ts` | (P1)识别「趸交+分期」 |
|
||||
| `backend/app/services/protocol_pay_mode_switch.py` | 趸交多明细合计校验;`djfq`→分期分支 |
|
||||
| `backend/app/crud/collection_protocol.py` | `align_fq_*` 等 `djfq` 与 `fq` 同等 |
|
||||
| `backend/app/services/qc_work_order_fee_summary.py` | `djfq` 标签与分期摘要 |
|
||||
| `backend/tests/test_protocol_pay_mode_switch.py` | 更新/新增校验单测 |
|
||||
| `backend/tests/test_protocol_payment_presets.py` | **新建**(可选)后端不依赖 preset,本任务以前端脚本为主 |
|
||||
|
||||
---
|
||||
|
||||
## 依赖顺序
|
||||
|
||||
```text
|
||||
Task 1 (presets 纯函数)
|
||||
→ Task 2 (后端校验)
|
||||
→ Task 3 (pay-mode-switch + installment 工具)
|
||||
→ Task 4 (标签/只读组件)
|
||||
→ Task 5 (ProtocolFormDialog 主改动)
|
||||
→ Task 6 (导入 P1 + 收尾 QA)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 定价表纯函数与冒烟测试
|
||||
|
||||
**Files:**
|
||||
- Create: `web-admin/src/utils/protocol-payment-presets.ts`
|
||||
- Create: `web-admin/scripts/test-protocol-payment-presets.ts`
|
||||
|
||||
- [ ] **Step 1: 创建 `protocol-payment-presets.ts`**
|
||||
|
||||
```typescript
|
||||
// web-admin/src/utils/protocol-payment-presets.ts
|
||||
export type PayMode = 'dj' | 'fq' | 'djfq'
|
||||
|
||||
export type PaymentPreset = {
|
||||
contractAmount: number
|
||||
installmentCount?: number
|
||||
installmentAmounts?: number[]
|
||||
}
|
||||
|
||||
const PRESETS: Record<1 | 2, Partial<Record<PayMode, PaymentPreset>>> = {
|
||||
1: {
|
||||
dj: { contractAmount: 22880 },
|
||||
fq: {
|
||||
contractAmount: 25880,
|
||||
installmentCount: 6,
|
||||
installmentAmounts: [6480, 3880, 3880, 3880, 3880, 3880]
|
||||
}
|
||||
},
|
||||
2: {
|
||||
dj: { contractAmount: 37880 },
|
||||
djfq: {
|
||||
contractAmount: 41000,
|
||||
installmentCount: 5,
|
||||
installmentAmounts: [22880, 6480, 3880, 3880, 3880]
|
||||
},
|
||||
fq: {
|
||||
contractAmount: 44000,
|
||||
installmentCount: 5,
|
||||
installmentAmounts: [12960, 7760, 7760, 7760, 7760]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveSampleCount(
|
||||
samples: Array<{ sampleStatus?: string }>
|
||||
): 1 | 2 {
|
||||
const n = samples.filter((s) => String(s.sampleStatus || '') !== 'yzf').length
|
||||
return (n >= 2 ? 2 : 1) as 1 | 2
|
||||
}
|
||||
|
||||
export function resolvePaymentPreset(
|
||||
sampleCount: 1 | 2,
|
||||
payMode: PayMode
|
||||
): PaymentPreset | null {
|
||||
return PRESETS[sampleCount]?.[payMode] ?? null
|
||||
}
|
||||
|
||||
export function isInstallmentPayMode(payMode: string): boolean {
|
||||
return payMode === 'fq' || payMode === 'djfq'
|
||||
}
|
||||
|
||||
export function availablePayModes(sampleCount: 1 | 2): PayMode[] {
|
||||
return sampleCount === 2 ? ['dj', 'djfq', 'fq'] : ['dj', 'fq']
|
||||
}
|
||||
|
||||
/** 校验双样本才能用 djfq */
|
||||
export function isPayModeValidForSampleCount(
|
||||
payMode: PayMode,
|
||||
sampleCount: 1 | 2
|
||||
): boolean {
|
||||
return availablePayModes(sampleCount).includes(payMode)
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 创建冒烟脚本**
|
||||
|
||||
```typescript
|
||||
// web-admin/scripts/test-protocol-payment-presets.ts
|
||||
import assert from 'node:assert/strict'
|
||||
import {
|
||||
resolvePaymentPreset,
|
||||
getActiveSampleCount,
|
||||
isInstallmentPayMode,
|
||||
isPayModeValidForSampleCount
|
||||
} from '../src/utils/protocol-payment-presets'
|
||||
|
||||
const fq1 = resolvePaymentPreset(1, 'fq')!
|
||||
assert.equal(fq1.contractAmount, 25880)
|
||||
assert.deepEqual(fq1.installmentAmounts, [6480, 3880, 3880, 3880, 3880, 3880])
|
||||
assert.equal(
|
||||
fq1.installmentAmounts!.reduce((s, v) => s + v, 0),
|
||||
fq1.contractAmount
|
||||
)
|
||||
|
||||
const djfq2 = resolvePaymentPreset(2, 'djfq')!
|
||||
assert.equal(djfq2.contractAmount, 41000)
|
||||
assert.equal(djfq2.installmentCount, 5)
|
||||
|
||||
assert.equal(getActiveSampleCount([{ sampleStatus: 'ycj' }]), 1)
|
||||
assert.equal(getActiveSampleCount([{ sampleStatus: 'ycj' }, { sampleStatus: 'yzf' }]), 1)
|
||||
assert.equal(
|
||||
getActiveSampleCount([{ sampleStatus: 'ycj' }, { sampleStatus: 'ycj' }]),
|
||||
2
|
||||
)
|
||||
|
||||
assert.equal(isInstallmentPayMode('djfq'), true)
|
||||
assert.equal(isInstallmentPayMode('dj'), false)
|
||||
assert.equal(isPayModeValidForSampleCount('djfq', 1), false)
|
||||
assert.equal(isPayModeValidForSampleCount('djfq', 2), true)
|
||||
|
||||
console.log('protocol-payment-presets: OK')
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 运行冒烟**
|
||||
|
||||
```bash
|
||||
cd web-admin && pnpm exec tsx scripts/test-protocol-payment-presets.ts
|
||||
```
|
||||
|
||||
Expected: 输出 `protocol-payment-presets: OK`,exit 0。
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 后端保存校验(趸交多明细 + djfq)
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/app/services/protocol_pay_mode_switch.py`
|
||||
- Modify: `backend/tests/test_protocol_pay_mode_switch.py`
|
||||
|
||||
- [ ] **Step 1: 修改 `validate_payment_details_for_save` 趸交分支**
|
||||
|
||||
将 `dj` 分支中「仅 1 条 dfj」改为「全部明细应缴合计 = 合同金额」:
|
||||
|
||||
```python
|
||||
# backend/app/services/protocol_pay_mode_switch.py — pay_mode == "dj" 分支替换为:
|
||||
|
||||
if pay_mode == "dj":
|
||||
total_due = sum(
|
||||
_dec(r.get("due_amount") if r.get("due_amount") is not None else r.get("dueAmount"))
|
||||
for r in rows
|
||||
)
|
||||
if contract and abs(total_due - contract) > 0.015:
|
||||
raise ValueError(
|
||||
f"趸交各明细应缴金额之和应为 {contract:.2f},当前为 {total_due:.2f}"
|
||||
)
|
||||
# 保留:存在 yjf 时,dfj 行 due 之和应等于 remaining(可选细化为与 total 一致即可)
|
||||
```
|
||||
|
||||
删除:
|
||||
|
||||
```python
|
||||
if len(dfj_rows) > 1:
|
||||
raise ValueError("趸交模式仅允许一条待缴费明细")
|
||||
```
|
||||
|
||||
以及单条 `dfj` 的 `expected` 校验(已由 `total_due` 覆盖)。
|
||||
|
||||
- [ ] **Step 2: `djfq` 走分期分支**
|
||||
|
||||
```python
|
||||
installment_modes = ("fq", "djfq")
|
||||
# ...
|
||||
elif pay_mode in installment_modes:
|
||||
# 原 fq 逻辑不变
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 更新单测**
|
||||
|
||||
`test_dj_rejects_multiple_dfj` 改名为 `test_dj_allows_multiple_dfj_when_sum_matches`:
|
||||
|
||||
```python
|
||||
def test_dj_allows_multiple_dfj_when_sum_matches(self):
|
||||
validate_payment_details_for_save(
|
||||
"dj",
|
||||
10000,
|
||||
None,
|
||||
[
|
||||
{"payStatus": "dfj", "dueAmount": 2000},
|
||||
{"payStatus": "dfj", "dueAmount": 8000},
|
||||
],
|
||||
)
|
||||
|
||||
def test_dj_rejects_multiple_dfj_wrong_sum(self):
|
||||
with self.assertRaises(ValueError) as ctx:
|
||||
validate_payment_details_for_save(
|
||||
"dj",
|
||||
10000,
|
||||
None,
|
||||
[
|
||||
{"payStatus": "dfj", "dueAmount": 2000},
|
||||
{"payStatus": "dfj", "dueAmount": 7000},
|
||||
],
|
||||
)
|
||||
self.assertIn("之和应为", str(ctx.exception))
|
||||
```
|
||||
|
||||
新增:
|
||||
|
||||
```python
|
||||
def test_djfq_same_as_fq(self):
|
||||
validate_payment_details_for_save(
|
||||
"djfq",
|
||||
41000,
|
||||
5,
|
||||
[
|
||||
{"payStatus": "dfj", "installmentNo": 1, "dueAmount": 22880},
|
||||
{"payStatus": "dfj", "installmentNo": 2, "dueAmount": 6480},
|
||||
{"payStatus": "dfj", "installmentNo": 3, "dueAmount": 3880},
|
||||
{"payStatus": "dfj", "installmentNo": 4, "dueAmount": 3880},
|
||||
{"payStatus": "dfj", "installmentNo": 5, "dueAmount": 3880},
|
||||
],
|
||||
installment_ratios=[22880, 6480, 3880, 3880, 3880],
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行后端单测**
|
||||
|
||||
```bash
|
||||
cd backend && source venv/bin/activate && python -m pytest tests/test_protocol_pay_mode_switch.py -v
|
||||
```
|
||||
|
||||
Expected: 全部 PASS。
|
||||
|
||||
- [ ] **Step 5: 修改 `collection_protocol.py` 分期对齐**
|
||||
|
||||
约 L2814,将:
|
||||
|
||||
```python
|
||||
if pay.pay_mode != "fq" or not pay.installment_count:
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```python
|
||||
if pay.pay_mode not in ("fq", "djfq") or not pay.installment_count:
|
||||
```
|
||||
|
||||
全文检索 `pay_mode != "fq"` / `pay_mode == "fq"` 在同文件内一并调整。
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 前端工具层(pay-mode-switch + installment)
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/utils/protocol-pay-mode-switch.ts`
|
||||
- Modify: `web-admin/src/utils/protocol-payment-installment.ts`
|
||||
|
||||
- [ ] **Step 1: 扩展 `PayMode` 并导入 preset**
|
||||
|
||||
```typescript
|
||||
// protocol-pay-mode-switch.ts 顶部
|
||||
import {
|
||||
type PayMode,
|
||||
isInstallmentPayMode,
|
||||
resolvePaymentPreset,
|
||||
getActiveSampleCount
|
||||
} from '@/utils/protocol-payment-presets'
|
||||
export type { PayMode }
|
||||
```
|
||||
|
||||
- [ ] **Step 2: `canAddPaymentDetail` 趸交始终可添加**
|
||||
|
||||
```typescript
|
||||
export function canAddPaymentDetail(payMode: string, _details: DetailLike[]): boolean {
|
||||
if (isInstallmentPayMode(payMode)) return true
|
||||
return true // dj:允许多条明细
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: `evaluatePayModeSwitch` / `applyPayModeSwitch` 支持 `djfq`**
|
||||
|
||||
- `dj` → `djfq`:与 `dj` → `fq` 相同(无已缴才允许)
|
||||
- `djfq` → `dj`:与 `fq` → `dj`
|
||||
- `djfq` ↔ `fq`:按分期规则处理
|
||||
- `applyPayModeSwitch` 重建分期明细时,从 `resolvePaymentPreset(sampleCount, toMode)` 取 `installmentAmounts`,无 preset 时回退 `defaultInstallmentAmounts`
|
||||
|
||||
- [ ] **Step 4: `protocol-payment-installment.ts`**
|
||||
|
||||
将所有 `payment.payMode !== 'fq'` / `=== 'fq'` 改为使用 `isInstallmentPayMode(payment.payMode as string)`(从 presets 导入)。
|
||||
|
||||
- [ ] **Step 5: 类型检查**
|
||||
|
||||
```bash
|
||||
cd web-admin && pnpm exec vue-tsc --noEmit 2>&1 | head -40
|
||||
```
|
||||
|
||||
Expected: 无新增 error(允许既有 warning)。
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 标签与只读展示
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/utils/status-tag-registry.ts`
|
||||
- Modify: `web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue`
|
||||
- Modify: `web-admin/src/components/business/protocol-payment-detail-readonly/index.vue`
|
||||
- Modify: `web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue`
|
||||
- Modify: `backend/app/services/qc_work_order_fee_summary.py`
|
||||
|
||||
- [ ] **Step 1: `status-tag-registry.ts` 增加**
|
||||
|
||||
```typescript
|
||||
djfq: { label: '趸交+分期', tagType: 'warning' } // 或 primary,与 fq 区分即可
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 只读组件分期条件**
|
||||
|
||||
`payment?.payMode === 'fq'` → `isInstallmentPayMode(payment?.payMode || '')`(ViewDialog、readonly、QcWorkOrderProtocolPaymentPanel)。
|
||||
|
||||
- [ ] **Step 3: 后端 `_PAY_MODE_LABELS`**
|
||||
|
||||
```python
|
||||
_PAY_MODE_LABELS = {"dj": "趸交", "fq": "分期", "djfq": "趸交+分期"}
|
||||
```
|
||||
|
||||
`build_protocol_payment_summary` 内 `pay_mode == "fq"` 改为 `pay_mode in ("fq", "djfq")`。
|
||||
|
||||
---
|
||||
|
||||
### Task 5: ProtocolFormDialog 主改动
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue`
|
||||
|
||||
- [ ] **Step 1: 缴费模式单选 UI**
|
||||
|
||||
```vue
|
||||
<el-radio-group v-model="formData.payMode" @change="onPayModeChange">
|
||||
<el-radio label="dj">趸交</el-radio>
|
||||
<el-radio v-if="activeSampleCount === 2" label="djfq">趸交+分期</el-radio>
|
||||
<el-radio label="fq">分期</el-radio>
|
||||
</el-radio-group>
|
||||
```
|
||||
|
||||
`activeSampleCount` = `computed(() => getActiveSampleCount(formData.samples))`。
|
||||
|
||||
- [ ] **Step 2: 分期区块条件**
|
||||
|
||||
`formData.payMode === 'fq'` → `isInstallmentPayMode(formData.payMode)`(模板内所有分期表单项、分期金额行)。
|
||||
|
||||
- [ ] **Step 3: 新增状态 `paymentDefaultsApplied`**
|
||||
|
||||
```typescript
|
||||
const paymentDefaultsApplied = ref<Record<PayMode, boolean>>({
|
||||
dj: false,
|
||||
fq: false,
|
||||
djfq: false
|
||||
})
|
||||
|
||||
function applyPaymentPresetForMode(payMode: PayMode) {
|
||||
const preset = resolvePaymentPreset(getActiveSampleCount(formData.samples), payMode)
|
||||
if (!preset) return
|
||||
formData.contractAmount = preset.contractAmount
|
||||
if (isInstallmentPayMode(payMode) && preset.installmentCount) {
|
||||
formData.installmentCount = preset.installmentCount
|
||||
formData.installmentIntervalMonths = formData.installmentIntervalMonths ?? 6
|
||||
formData.installmentStartDate =
|
||||
formData.installmentStartDate || defaultInstallmentStartDateYmd()
|
||||
formData.installmentAdvanceDays =
|
||||
formData.installmentAdvanceDays ?? DEFAULT_INSTALLMENT_ADVANCE_DAYS
|
||||
formData.installmentRatios = [...(preset.installmentAmounts || [])]
|
||||
formData.paymentDetails = generateInitialFqDetails(
|
||||
getFqParamsFromForm(),
|
||||
preset.contractAmount
|
||||
)
|
||||
initPaymentDetailExpandFlags(formData.paymentDetails)
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
syncLastConfirmedFqParams()
|
||||
} else {
|
||||
formData.paymentDetails = [
|
||||
createPaymentDetailRow({
|
||||
dueAmount: preset.contractAmount,
|
||||
installmentDueDate: formData.lumpSumDeadline || '',
|
||||
expanded: true
|
||||
})
|
||||
]
|
||||
}
|
||||
paymentDefaultsApplied.value[payMode] = true
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 改造 `onPayModeChange`**
|
||||
|
||||
在既有 `evaluatePayModeSwitch` 之前/之后:
|
||||
|
||||
```typescript
|
||||
async function onPayModeChange(newMode: PayMode) {
|
||||
const oldMode = lastConfirmedPayMode.value
|
||||
// ... 既有 evaluate + apply 逻辑 ...
|
||||
|
||||
if (!paymentDefaultsApplied.value[newMode]) {
|
||||
applyPaymentPresetForMode(newMode)
|
||||
}
|
||||
lastConfirmedPayMode.value = newMode
|
||||
}
|
||||
```
|
||||
|
||||
新建弹窗 `resetForm` / `openCreate` 时重置 `paymentDefaultsApplied` 全 `false`;编辑加载详情后全部标 `true`(不覆盖库内数据)。
|
||||
|
||||
- [ ] **Step 5: 去掉样本价 → 合同额自动联动**
|
||||
|
||||
`onSamplePriceChange` 改为空实现或仅刷新弱提示:
|
||||
|
||||
```typescript
|
||||
function onSamplePriceChange() {
|
||||
// 方案 B:不调用 syncContractAmount()
|
||||
}
|
||||
```
|
||||
|
||||
删除或停用 `syncContractAmount()` 内对 `formData.contractAmount` 的写入;保留函数供「恢复默认」P1 使用时可再启用。
|
||||
|
||||
可选弱提示(缴费 Tab):
|
||||
|
||||
```typescript
|
||||
const samplePriceContractHint = computed(() => {
|
||||
const sampleTotal = formData.samples
|
||||
.filter((s) => s.sampleStatus !== 'yzf')
|
||||
.reduce((sum, s) => sum + (Number(s.price) || 0), 0)
|
||||
if (formData.contractAmount == null) return ''
|
||||
if (Math.abs(sampleTotal - Number(formData.contractAmount)) > 0.01) {
|
||||
return `样本价格合计 ${fmtMoney(sampleTotal)} 与合同金额不一致,请核对`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 保存前校验 `djfq` 样本数**
|
||||
|
||||
在 `handleSubmit` 缴费校验段:
|
||||
|
||||
```typescript
|
||||
if (
|
||||
formData.payMode === 'djfq' &&
|
||||
getActiveSampleCount(formData.samples) !== 2
|
||||
) {
|
||||
await ElMessageBox.alert('「趸交+分期」仅适用于 2 个样本,请切换缴费模式', '无法保存', {
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!isPayModeValidForSampleCount(formData.payMode as PayMode, getActiveSampleCount(formData.samples))) {
|
||||
await ElMessageBox.alert('当前缴费模式与样本数量不匹配', '无法保存', { type: 'warning' })
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 7: 标准导入后标记默认已应用**
|
||||
|
||||
`applyPaymentFromImport` 末尾:
|
||||
|
||||
```typescript
|
||||
paymentDefaultsApplied.value = { dj: true, fq: true, djfq: true }
|
||||
```
|
||||
|
||||
- [ ] **Step 8: 编辑加载 `lastConfirmedPayMode`**
|
||||
|
||||
```typescript
|
||||
lastConfirmedPayMode.value = (['fq', 'djfq'].includes(formData.payMode)
|
||||
? formData.payMode
|
||||
: 'dj') as PayMode
|
||||
```
|
||||
|
||||
- [ ] **Step 9: 手动验证(开发环境)**
|
||||
|
||||
1. 新建 → 添加 1 样本 → 首次选「分期」→ 合同 25880、6 期金额正确
|
||||
2. 再添加第 2 样本 → 合同/明细**不变**
|
||||
3. 新建 2 样本 → 选「趸交+分期」→ 41000、5 期
|
||||
4. 趸交 → 添加 2 条明细 2000+20880 → 保存成功
|
||||
5. 2 样本 `djfq` 删 1 样本 → 保存拦截
|
||||
|
||||
---
|
||||
|
||||
### Task 6: 标准导入(P1)与收尾
|
||||
|
||||
**Files:**
|
||||
- Modify: `web-admin/src/utils/protocol-standard-import-parse.ts`
|
||||
- Run: `./scripts/update-graph.sh frontend`
|
||||
|
||||
- [ ] **Step 1: 导入识别 `djfq`**
|
||||
|
||||
`parsePayMode` 中:
|
||||
|
||||
```typescript
|
||||
if (/趸交\s*[++]\s*分期|趸交.*分期/.test(v)) return { payMode: 'djfq' }
|
||||
```
|
||||
|
||||
`ProtocolStandardImportParsed.payMode` 类型改为 `'dj' | 'fq' | 'djfq'`。
|
||||
|
||||
- [ ] **Step 2: 更新知识图谱**
|
||||
|
||||
```bash
|
||||
./scripts/update-graph.sh frontend
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Lint**
|
||||
|
||||
```bash
|
||||
cd web-admin && pnpm lint
|
||||
cd backend && python -m pytest tests/test_protocol_pay_mode_switch.py -v
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 更新 design spec 状态**
|
||||
|
||||
`docs/superpowers/specs/2026-07-06-protocol-payment-defaults-design.md` 表头 `状态` → `已实现`。
|
||||
|
||||
---
|
||||
|
||||
## Spec 覆盖自检
|
||||
|
||||
| Spec § | Task |
|
||||
|--------|------|
|
||||
| §3 默认定价表 | Task 1 |
|
||||
| §4 方案 B 填充时机 | Task 5 Step 3–4、7 |
|
||||
| §5 趸交多明细 | Task 2、3、5 |
|
||||
| §5.2 djfq 分期 | Task 2–5 |
|
||||
| §6 模式切换修订 | Task 3、5 |
|
||||
| §7 pay_mode=djfq | Task 2、4 |
|
||||
| §8 UI | Task 4、5 |
|
||||
| §8.3 样本价解耦 | Task 5 Step 5 |
|
||||
| §9–10 前后端摘要 | Task 2–5 |
|
||||
| §11 测试要点 | 各 Task Step 验证 |
|
||||
| §4.3 恢复默认 P1 | **范围外**(未列入 Task) |
|
||||
|
||||
---
|
||||
|
||||
## 人工回归清单(提测)
|
||||
|
||||
- [ ] 新建 1 样本首次 `fq`:25880 / 6 期模板
|
||||
- [ ] 新建 2 样本首次 `djfq`:41000 / 5 期
|
||||
- [ ] 样本数 1→2 后金额不变
|
||||
- [ ] 趸交 2+ 条 `dfj` 保存成功
|
||||
- [ ] 分期合计 ≠ 合同额:前后端拦截
|
||||
- [ ] 已缴锁定 + 模式切换:仍符合 2026-06-04
|
||||
- [ ] 查看弹窗 / 质检费用摘要:`djfq` 标签与期次表
|
||||
- [ ] 标准导入多笔趸交转账保存成功
|
||||
|
||||
---
|
||||
|
||||
## 执行方式
|
||||
|
||||
**Plan 已保存至** `docs/superpowers/plans/2026-07-06-protocol-payment-defaults.md`。
|
||||
|
||||
**两种执行方式:**
|
||||
|
||||
1. **Subagent-Driven(推荐)** — 每 Task 派发独立子代理,Task 间人工/代理复核
|
||||
2. **Inline Execution** — 本会话按 Task 1→6 连续实现,每 Task 末 checkpoint
|
||||
|
||||
告知选用哪种方式即可开始实现。
|
||||
@@ -0,0 +1,214 @@
|
||||
# 采集协议单 · 缴费默认定价与明细规则设计
|
||||
|
||||
**日期**:2026-07-06
|
||||
**范围**:`web-admin` 采集协议单新增/编辑(`ProtocolFormDialog.vue`)、标准信息导入、后端缴费保存校验
|
||||
**前置 spec**:[2026-06-04-protocol-pay-mode-switch-design.md](./2026-06-04-protocol-pay-mode-switch-design.md)、[2026-06-10-protocol-installment-config-design.md](./2026-06-10-protocol-installment-config-design.md)
|
||||
**状态**:已实现
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
业务方给出「样本数 × 缴费模式」下的**默认合同金额、默认期数、默认各期金额**。这些数值仅作录入辅助;用户可自由修改合同金额、分期期数、各期金额;趸交也可拆成多条缴费明细(如预付款 + 尾款)。
|
||||
|
||||
当前实现与目标的主要差距:
|
||||
|
||||
| 维度 | 现状 | 目标 |
|
||||
|------|------|------|
|
||||
| 合同金额来源 | 非作废样本 `price` 之和 | 按定价表填**默认**,用户可改;样本数变化**不**自动改金额 |
|
||||
| 分期默认金额 | 均分或历史 50/10/10… | 固定模板(6,480 / 3,880…) |
|
||||
| 分期默认期数 | 一律 6 期 | 1 样本 6 期;2 样本分期/混合 5 期 |
|
||||
| 缴费模式 | `dj` / `fq` | 增加双样本 **趸交+分期** `djfq` |
|
||||
| 趸交明细条数 | 后端禁止多条 `dfj` | 允许多条,合计 = 合同金额 |
|
||||
| 默认填充时机 | 切分期、改样本价等会联动 | **方案 B**:仅新建或**首次**选缴费模式时填默认 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 决策记录
|
||||
|
||||
| 议题 | 决定 |
|
||||
|------|------|
|
||||
| 默认值性质 | 仅初始填充,**不锁定**;用户可改合同金额、期数、各期金额 |
|
||||
| 样本数变化 | **不**自动改合同金额、期数、明细(方案 B) |
|
||||
| 缴费模式变化 | **首次**从空/未选切到某模式时填该模式默认;已选过且用户已编辑后,再次切换仍走既有「模式切换」确认流(见 §6) |
|
||||
| 单样本分期默认合同额 | **25,880**(6,480 + 3,880×5) |
|
||||
| 趸交默认合同额 | 优惠价:1 样本 **22,880**;2 样本 **37,880** |
|
||||
| 双样本「趸交+分期」 | 新模式 `djfq`,默认 **41,000**,5 期:22,880、6,480、3,880、3,880、3,880 |
|
||||
| 双样本纯分期 | 默认 **44,000**,5 期:12,960、7,760、7,760、7,760、7,760 |
|
||||
| 趸交多条明细 | 允许;`Σ dueAmount(全部明细)= contractAmount`;保存时不再限制「仅 1 条 dfj」 |
|
||||
| 样本 `price` 字段 | 仍维护样本单价;与合同默认**解耦**;导入/保存时可提示样本价合计与合同额不一致,**不阻断** |
|
||||
| 定价表存放 | 前端 `protocol-payment-presets.ts`(常量);后端镜像校验逻辑不依赖默认表,只校验合计与条数 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 默认定价表
|
||||
|
||||
有效样本数 = 当前协议单内 `sampleStatus !== 'yzf'` 的样本条数,取值 **1** 或 **2**(与现网一致,不支持 0 样本保存缴费)。
|
||||
|
||||
| 样本数 | `pay_mode` | 默认合同金额 | 默认期数 | 默认各期金额(元) |
|
||||
|--------|------------|-------------|----------|-------------------|
|
||||
| 1 | `dj` | 22,880 | — | 单条明细 `dueAmount = 22,880`(用户可拆多条) |
|
||||
| 1 | `fq` | 25,880 | 6 | 6,480、3,880、3,880、3,880、3,880、3,880 |
|
||||
| 2 | `dj` | 37,880 | — | 单条明细 `dueAmount = 37,880`(用户可拆多条) |
|
||||
| 2 | `djfq` | 41,000 | 5 | 22,880、6,480、3,880、3,880、3,880 |
|
||||
| 2 | `fq` | 44,000 | 5 | 12,960、7,760、7,760、7,760、7,760 |
|
||||
|
||||
**标签**:`djfq` 展示为「趸交+分期」;字典 `status-tag-registry` / 后端摘要增加 `djfq` → `趸交+分期`。
|
||||
|
||||
**双样本时缴费模式选项**:`dj`、`djfq`、`fq`(隐藏或禁用 `djfq` 当样本数 ≠ 2)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 默认填充时机(方案 B)
|
||||
|
||||
### 4.1 会填充默认的场景
|
||||
|
||||
1. **新建协议单**,用户**第一次**选择缴费模式(`pay_mode` 从初始 `dj` 切到 `fq` / `djfq`,或新建后首次进入缴费 Tab 且明细为空时的初始化,与产品确认以「首次 `onPayModeChange` 且该模式从未应用过」为准)。
|
||||
2. **新建协议单**,打开时若默认 `pay_mode=dj` 且 `paymentDetails` 为空:按 **当前样本数** 填趸交默认(合同额 + 1 条明细)。若此时样本数仍为 0,待用户添加第 1 个样本后**不**自动重填(方案 B);用户选模式或手动点「套用默认」时再填。
|
||||
|
||||
> **实现建议**:维护 `paymentDefaultsApplied: Record<PayMode, boolean>`(或 `lastAppliedPresetKey: string | null`)。某 `pay_mode` 第一次生效时调用 `applyPaymentPreset(sampleCount, payMode)`,并标记已应用。
|
||||
|
||||
### 4.2 不会自动改金额的场景
|
||||
|
||||
- 增删样本、样本作废/恢复
|
||||
- 修改样本 `price`
|
||||
- 修改合同金额后回头改样本
|
||||
|
||||
用户自行改合同额、期数、明细;仅触发**合计校验**与既有「分期参数变更 / 模式切换」确认流。
|
||||
|
||||
### 4.3 可选辅助(P1,非本期必须)
|
||||
|
||||
缴费主表旁「恢复默认」按钮:按当前样本数 + 当前 `pay_mode` 重新套用 §3 定价表,**需二次确认**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 缴费明细与校验
|
||||
|
||||
### 5.1 趸交 `dj`
|
||||
|
||||
- 明细 **≥ 1** 条;用户可通过「添加明细」增加(含预付款场景)。
|
||||
- `canAddPaymentDetail`:改为在 `dj` 下**始终允许**添加(或:待缴条数无硬上限,仅校验合计)。
|
||||
- 保存校验:
|
||||
- `Σ dueAmount(全部明细)` 与 `contractAmount` 差额 ≤ 0.01;
|
||||
- 允许多条 `dfj`;
|
||||
- 若存在 `yjf`:`Σ yjf.dueAmount + Σ dfj.dueAmount` 仍须等于 `contractAmount`(与现 `remaining` 逻辑一致,但允许多条 `dfj` 分摊剩余)。
|
||||
|
||||
### 5.2 分期 `fq` 与混合 `djfq`
|
||||
|
||||
- 明细条数 **=** `installment_count`(与现 `fq` 一致)。
|
||||
- `installment_ratios` 存**各期金额(元)**,非百分比(与现网一致)。
|
||||
- `Σ 各期 dueAmount = contractAmount`。
|
||||
- `djfq` 在数据层按分期处理:每期有 `installmentNo`、应缴日;第 1 期金额语义为「趸交部分」,不做单独子表。
|
||||
|
||||
### 5.3 与标准信息导入
|
||||
|
||||
- 导入解析到的 `contractAmount`、多笔 `transfer` **覆盖**默认填充(与 [2026-07-02-protocol-standard-import-design.md](./2026-07-02-protocol-standard-import-design.md) 一致)。
|
||||
- 导入后标记 `paymentDefaultsApplied` 全部为已应用,避免再自动覆盖。
|
||||
|
||||
---
|
||||
|
||||
## 6. 缴费模式切换(在 2026-06-04 上的修订)
|
||||
|
||||
既有切换规则(已缴锁定、确认流)**保留**。下列条目**修订**原 spec:
|
||||
|
||||
| 原规则 | 新规则 |
|
||||
|--------|--------|
|
||||
| 趸交仅 1 条有效明细 | 趸交可多条;切换生成时仍可合并为 1 条**默认**,用户随后可拆 |
|
||||
| `pay_mode` 仅 `dj`/`fq` | 增加 `djfq`;`djfq` ↔ `fq` 按分期规则;`djfq` → `dj` 同 `fq` → `dj` |
|
||||
| 切换后分期金额均分 | 切换后若走「重建明细」,使用 §3 对应默认各期金额(非均分) |
|
||||
|
||||
**双样本 → 单样本**(或反向):不自动改合同/明细(方案 B);若当前 `pay_mode=djfq` 且样本数变为 1,**阻断保存**并提示「请切换缴费模式」,或自动要求用户改模式(推荐:**保存前校验**样本数与 `djfq` 一致)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 数据模型
|
||||
|
||||
### 7.1 `biz_protocol_payment.pay_mode`
|
||||
|
||||
| 值 | 含义 |
|
||||
|----|------|
|
||||
| `dj` | 趸交 |
|
||||
| `fq` | 分期 |
|
||||
| `djfq` | 趸交+分期(仅双样本) |
|
||||
|
||||
字段长度 `varchar(8)` 足够。无需新列;`installment_count` / `installment_ratios` 在 `djfq` 与 `fq` 用法相同。
|
||||
|
||||
### 7.2 迁移
|
||||
|
||||
- 字典项(若缴费模式走 dict):增加 `djfq`。
|
||||
- 历史数据无 `djfq`,只读展示兼容即可。
|
||||
|
||||
---
|
||||
|
||||
## 8. UI
|
||||
|
||||
### 8.1 缴费模式
|
||||
|
||||
```text
|
||||
[ 趸交 ] [ 分期 ] // 1 样本
|
||||
[ 趸交 ] [ 趸交+分期 ] [ 分期 ] // 2 样本
|
||||
```
|
||||
|
||||
### 8.2 分期金额区
|
||||
|
||||
- `fq` / `djfq`:展示期数、间隔、开始时间、各期金额输入格;默认期数/金额来自 §3。
|
||||
- 合计行:`合计 xxx / 合同 xxx`(已有)。
|
||||
|
||||
### 8.3 样本价格
|
||||
|
||||
- 样本 Tab 的「价格」保留;**移除** `syncContractAmount()` 在样本价变更时对 `contractAmount` 的自动写入(方案 B)。
|
||||
- 可选弱提示:样本价合计 ≠ 合同金额时展示 `form-tip`(不阻断保存)。
|
||||
|
||||
---
|
||||
|
||||
## 9. 后端改动摘要
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `protocol_pay_mode_switch.py` | `dj`:删除「仅 1 条 dfj」;改为明细总额校验;支持 `djfq` 走 `fq` 分支 |
|
||||
| `collection_protocol.py` | 读写 `pay_mode=djfq`;列表/详情标签 |
|
||||
| `qc_work_order_fee_summary.py` 等 | `djfq` 标签与分期展示 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端改动摘要
|
||||
|
||||
| 文件 | 改动 |
|
||||
|------|------|
|
||||
| `protocol-payment-presets.ts` | **新建**,§3 定价表 + `applyPaymentPreset()` |
|
||||
| `protocol-payment-installment.ts` | 默认金额生成改为调用 preset(均分仅作无 preset 时的兜底) |
|
||||
| `protocol-pay-mode-switch.ts` | `dj` 多明细;`PayMode` 含 `djfq` |
|
||||
| `ProtocolFormDialog.vue` | 模式 UI、首次填充、去掉样本价→合同额联动 |
|
||||
| `ProtocolViewDialog.vue` | `djfq` 展示 |
|
||||
| `status-tag-registry.ts` | `djfq` |
|
||||
| `protocol-standard-import-parse.ts` | 识别「趸交+分期」文案 → `djfq`(P1) |
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试要点
|
||||
|
||||
- [ ] 新建 1 样本,首次选 `fq` → 合同 25,880,6 期金额正确
|
||||
- [ ] 新建 2 样本,首次选 `djfq` → 41,000,5 期正确
|
||||
- [ ] 改样本数 1→2,合同/明细**不变**
|
||||
- [ ] 趸交添加 2 条明细,合计 = 合同额,保存成功
|
||||
- [ ] 趸交 2 条 `dfj` 预付款场景,保存成功
|
||||
- [ ] 修改各期金额后合计 ≠ 合同额,前后端均拦截
|
||||
- [ ] 模式切换 + 已缴锁定,仍符合 2026-06-04
|
||||
- [ ] 2 样本 `djfq` 删至 1 样本,保存提示改模式
|
||||
- [ ] 标准导入多笔转账 + 趸交,保存成功
|
||||
|
||||
---
|
||||
|
||||
## 12. 范围外
|
||||
|
||||
- 定价表后台可配置化(本期写死常量)
|
||||
- 3 个及以上样本
|
||||
- 按样本绑定不同缴费模式(每样本独立主表)
|
||||
|
||||
---
|
||||
|
||||
## 13. 修订记录
|
||||
|
||||
| 日期 | 说明 |
|
||||
|------|------|
|
||||
| 2026-07-06 | 初稿:默认定价表、方案 B、djfq、趸交多明细 |
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,10 +1,10 @@
|
||||
# Graph Report - src (2026-07-06)
|
||||
|
||||
## Corpus Check
|
||||
- Large corpus: 850 files · ~561,909 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
- Large corpus: 851 files · ~562,525 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
|
||||
|
||||
## Summary
|
||||
- 2845 nodes · 3968 edges · 58 communities detected
|
||||
- 2839 nodes · 3960 edges · 58 communities detected
|
||||
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 881 edges (avg confidence: 0.8)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
@@ -46,22 +46,22 @@
|
||||
- [[_COMMUNITY_Community 34|Community 34]]
|
||||
- [[_COMMUNITY_Community 35|Community 35]]
|
||||
- [[_COMMUNITY_Community 36|Community 36]]
|
||||
- [[_COMMUNITY_Community 37|Community 37]]
|
||||
- [[_COMMUNITY_Community 38|Community 38]]
|
||||
- [[_COMMUNITY_Community 39|Community 39]]
|
||||
- [[_COMMUNITY_Community 40|Community 40]]
|
||||
- [[_COMMUNITY_Community 41|Community 41]]
|
||||
- [[_COMMUNITY_Community 44|Community 44]]
|
||||
- [[_COMMUNITY_Community 45|Community 45]]
|
||||
- [[_COMMUNITY_Community 46|Community 46]]
|
||||
- [[_COMMUNITY_Community 47|Community 47]]
|
||||
- [[_COMMUNITY_Community 48|Community 48]]
|
||||
- [[_COMMUNITY_Community 49|Community 49]]
|
||||
- [[_COMMUNITY_Community 50|Community 50]]
|
||||
- [[_COMMUNITY_Community 51|Community 51]]
|
||||
- [[_COMMUNITY_Community 52|Community 52]]
|
||||
- [[_COMMUNITY_Community 53|Community 53]]
|
||||
- [[_COMMUNITY_Community 54|Community 54]]
|
||||
- [[_COMMUNITY_Community 55|Community 55]]
|
||||
- [[_COMMUNITY_Community 57|Community 57]]
|
||||
- [[_COMMUNITY_Community 59|Community 59]]
|
||||
- [[_COMMUNITY_Community 56|Community 56]]
|
||||
- [[_COMMUNITY_Community 58|Community 58]]
|
||||
- [[_COMMUNITY_Community 60|Community 60]]
|
||||
- [[_COMMUNITY_Community 63|Community 63]]
|
||||
- [[_COMMUNITY_Community 65|Community 65]]
|
||||
- [[_COMMUNITY_Community 73|Community 73]]
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `get()` - 279 edges
|
||||
2. `push()` - 77 edges
|
||||
2. `push()` - 75 edges
|
||||
3. `WebSocketClient` - 26 edges
|
||||
4. `emit()` - 24 edges
|
||||
5. `set()` - 20 edges
|
||||
@@ -81,14 +81,14 @@
|
||||
10. `TableCache` - 14 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
|
||||
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
|
||||
- `buildInboundMetaFields()` --calls--> `push()` [INFERRED]
|
||||
utils/production-work-order-card-meta.ts → views/operations/storage-facility/index.vue
|
||||
- `dash()` --calls--> `formatDisplayOrDash()` [INFERRED]
|
||||
components/business/infusion-schedule-outbound-chain-view/index.vue → utils/datetime-display.ts
|
||||
components/business/clinical-schedule-payment-detail/index.vue → utils/datetime-display.ts
|
||||
- `fmtMoney()` --calls--> `formatMoneyDisplay()` [INFERRED]
|
||||
components/business/clinical-schedule-payment-detail/index.vue → utils/money-format.ts
|
||||
- `handleAttachmentDownload()` --calls--> `downloadAttachmentFile()` [INFERRED]
|
||||
components/business/infusion-schedule-outbound-chain-view/index.vue → utils/download-attachment.ts
|
||||
- `subscribeTokenRefresh()` --calls--> `push()` [INFERRED]
|
||||
utils/http/index.ts → views/operations/storage-facility/index.vue
|
||||
|
||||
@@ -96,91 +96,91 @@
|
||||
|
||||
### Community 0 - "Community 0"
|
||||
Cohesion: 0.01
|
||||
Nodes (156): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+148 more)
|
||||
Nodes (167): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+159 more)
|
||||
|
||||
### Community 1 - "Community 1"
|
||||
Cohesion: 0.03
|
||||
Nodes (83): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), markPilotCheckupChecked() (+75 more)
|
||||
Cohesion: 0.02
|
||||
Nodes (95): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), markPilotCheckupChecked() (+87 more)
|
||||
|
||||
### Community 2 - "Community 2"
|
||||
Cohesion: 0.03
|
||||
Nodes (78): fetchUploadAttachment(), FireworkSystem, handleReportUpload(), handleReportUpload(), walk(), buildBaseFields(), buildFeeSection(), buildInboundBasicSection() (+70 more)
|
||||
Nodes (54): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTemporaryViewSections(), buildTransportSection(), resolveInboundProtocolStatus(), appendTaskResultSections() (+46 more)
|
||||
|
||||
### Community 3 - "Community 3"
|
||||
Cohesion: 0.03
|
||||
Nodes (62): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+54 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.03
|
||||
Nodes (33): fetchGetMenuList(), ComponentLoader, IframeRouteManager, MenuProcessor, RouteRegistry, RouteTransformer, useAppMode(), useAuth() (+25 more)
|
||||
|
||||
### Community 4 - "Community 4"
|
||||
Cohesion: 0.04
|
||||
Nodes (65): fetchUploadAttachment(), handleReportUpload(), handleReportUpload(), walk(), async(), for(), handleAttachmentChange(), for() (+57 more)
|
||||
|
||||
### Community 5 - "Community 5"
|
||||
Cohesion: 0.03
|
||||
Nodes (58): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+50 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.02
|
||||
Nodes (28): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllEquipments(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents() (+20 more)
|
||||
|
||||
### Community 6 - "Community 6"
|
||||
Cohesion: 0.03
|
||||
Nodes (42): handleBlur(), handleFocus(), handleInput(), fetchEthnicList(), formatNowDatetime(), formatAmount(), formatAmount(), formatProtocolAmount() (+34 more)
|
||||
|
||||
### Community 7 - "Community 7"
|
||||
Cohesion: 0.03
|
||||
Nodes (48): buildTemporaryViewSections(), appendTaskResultSections(), batchTasksForPanelSlot(), buildConfiguredOnlySection(), for(), for(), set(), allTabInboundAnchorId() (+40 more)
|
||||
Nodes (54): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), shouldApplyTriggerSourceFilter(), buildMineTableRows(), buildPresetTasksMap(), buildWorkOrderFromTasks() (+46 more)
|
||||
|
||||
### Community 8 - "Community 8"
|
||||
Cohesion: 0.04
|
||||
Nodes (49): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitution(), fetchUpdateCheckupInstitutionInvoice(), fetchUpdateCheckupInstitutionProject() (+41 more)
|
||||
Nodes (50): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitution(), fetchUpdateCheckupInstitutionInvoice(), fetchUpdateCheckupInstitutionProject() (+42 more)
|
||||
|
||||
### Community 9 - "Community 9"
|
||||
Cohesion: 0.03
|
||||
Nodes (41): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions() (+33 more)
|
||||
Cohesion: 0.04
|
||||
Nodes (42): buildBaseFields(), buildFeeSection(), buildInboundBasicSection(), buildInboundCellStorageProductionViewSections(), buildInboundResearchDonationProductionViewSections(), buildOutboundBasicExperimentProductionViewSections(), buildOutboundClinicalProductionViewSections(), buildOutboundDetail() (+34 more)
|
||||
|
||||
### Community 10 - "Community 10"
|
||||
Cohesion: 0.04
|
||||
Nodes (50): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), shouldApplyTriggerSourceFilter(), buildMineTableRows(), buildPresetTasksMap(), buildWorkOrderFromTasks() (+42 more)
|
||||
Nodes (40): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), if(), walk() (+32 more)
|
||||
|
||||
### Community 11 - "Community 11"
|
||||
Cohesion: 0.04
|
||||
Nodes (43): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), if(), collectAllPostBindDeptIds() (+35 more)
|
||||
Cohesion: 0.05
|
||||
Nodes (53): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), fetchUpdateProfile(), fetchUploadProfileAvatar(), toLogin(), fetchUserInfo() (+45 more)
|
||||
|
||||
### Community 12 - "Community 12"
|
||||
Cohesion: 0.04
|
||||
Nodes (45): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleBatchDelete() (+37 more)
|
||||
Nodes (44): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleDelete() (+36 more)
|
||||
|
||||
### Community 13 - "Community 13"
|
||||
Cohesion: 0.04
|
||||
Nodes (36): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTransportSection(), resolveInboundProtocolStatus(), protocolStatusDisplay(), maskIdCard() (+28 more)
|
||||
Nodes (26): handleBlur(), handleFocus(), handleInput(), fetchEthnicList(), formatAmount(), formatAmount(), formatProtocolAmount(), applyDonationBundleToForm() (+18 more)
|
||||
|
||||
### Community 14 - "Community 14"
|
||||
Cohesion: 0.04
|
||||
Nodes (31): dash(), fmtMoney(), auditorDisplay(), dash(), ensureUnitsInOptions(), expressName(), formatYm(), formatYmd() (+23 more)
|
||||
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.05
|
||||
Nodes (34): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+26 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
### Community 15 - "Community 15"
|
||||
Cohesion: 0.06
|
||||
Nodes (37): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit() (+29 more)
|
||||
|
||||
### Community 16 - "Community 16"
|
||||
Cohesion: 0.05
|
||||
Nodes (25): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchRoleOptions(), fetchUpdateMenu(), collectIds(), postorder(), preorder() (+17 more)
|
||||
|
||||
### Community 17 - "Community 17"
|
||||
Cohesion: 0.08
|
||||
Nodes (37): formatDatetimeToMinute(), handleChineseDatetimePaste(), parseChineseDatetimeText(), parseBirthOrder(), parseChineseNumeral(), addSampleHint(), earliestCollectTime(), isMaternalBloodEmpty() (+29 more)
|
||||
|
||||
### Community 18 - "Community 18"
|
||||
Cohesion: 0.1
|
||||
Nodes (2): WebSocketClient, TableCache
|
||||
Cohesion: 0.06
|
||||
Nodes (21): fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString(), for() (+13 more)
|
||||
|
||||
### Community 19 - "Community 19"
|
||||
Cohesion: 0.06
|
||||
Nodes (20): fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString(), ensureTabMounted() (+12 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (36): attachmentFullUrl(), dash(), handleAttachmentDownload(), handleAttachmentPreview(), buildPaymentFlowSteps(), dash(), formatAmount(), hasFinanceReceipt() (+28 more)
|
||||
|
||||
### Community 20 - "Community 20"
|
||||
Cohesion: 0.08
|
||||
Nodes (32): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+24 more)
|
||||
Cohesion: 0.06
|
||||
Nodes (13): fetchProductionWorkOrderQcInfo(), dash(), fmtMoney(), auditorDisplay(), dash(), ensureUnitsInOptions(), expressName(), formatYm() (+5 more)
|
||||
|
||||
### Community 21 - "Community 21"
|
||||
Cohesion: 0.07
|
||||
Nodes (24): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderQcInfo(), fetchProductionWorkOrderTabStepCounts() (+16 more)
|
||||
Cohesion: 0.1
|
||||
Nodes (2): WebSocketClient, TableCache
|
||||
|
||||
### Community 22 - "Community 22"
|
||||
Cohesion: 0.09
|
||||
@@ -188,44 +188,44 @@ Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, get
|
||||
|
||||
### Community 23 - "Community 23"
|
||||
Cohesion: 0.08
|
||||
Nodes (18): fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), onUserSelectVisible(), remoteSearchUsers(), buildPayload(), ensureDefaultHandler(), initDialog() (+10 more)
|
||||
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
|
||||
|
||||
### Community 24 - "Community 24"
|
||||
Cohesion: 0.08
|
||||
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
|
||||
Nodes (18): fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), onUserSelectVisible(), remoteSearchUsers(), buildPayload(), ensureDefaultHandler(), initDialog() (+10 more)
|
||||
|
||||
### Community 25 - "Community 25"
|
||||
Cohesion: 0.07
|
||||
Nodes (19): fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions(), fetchMaterialList(), fetchMaterialOptions(), fetchUpdateMaterialBatch(), fetchMaterialUsageList(), fetchMyMaterialUsageList() (+11 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.09
|
||||
Nodes (28): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+20 more)
|
||||
|
||||
### Community 26 - "Community 26"
|
||||
Cohesion: 0.11
|
||||
Nodes (21): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), fetchUpdateProfile(), fetchUploadProfileAvatar(), fetchUserInfo(), buildWebEncryptedLoginBody() (+13 more)
|
||||
|
||||
### Community 27 - "Community 27"
|
||||
Cohesion: 0.09
|
||||
Nodes (22): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderTabStepCounts(), fetchProductionWorkOrderTabStepCountsDeduped() (+14 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
Cohesion: 0.09
|
||||
Nodes (11): fetchMineQcWorkOrderTabUnfinishedCounts(), fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList(), fetchQcWorkOrderTabUnfinishedCounts(), reload(), reloadTabCounts(), handleMenuJump() (+3 more)
|
||||
|
||||
### Community 28 - "Community 28"
|
||||
### Community 29 - "Community 29"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
|
||||
|
||||
### Community 29 - "Community 29"
|
||||
### Community 30 - "Community 30"
|
||||
Cohesion: 0.11
|
||||
Nodes (11): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), handleToggleSelect(), loadData() (+3 more)
|
||||
|
||||
### Community 30 - "Community 30"
|
||||
### Community 31 - "Community 31"
|
||||
Cohesion: 0.13
|
||||
Nodes (18): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchDeleteCellSampleType(), fetchUpdateCellSampleType(), handleAdd(), handleDelete(), handleDropdownCommand(), handleEdit() (+10 more)
|
||||
|
||||
### Community 31 - "Community 31"
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.19
|
||||
Nodes (15): fetchAttachmentDownloadUrl(), attachmentFullUrl(), ensureUniqueZipEntryName(), fetchAttachmentBlob(), getAttachmentExtension(), resolveAttachmentFileName(), sanitizeZipPathSegment(), applyInboundLabStorageCodePrefix() (+7 more)
|
||||
|
||||
### Community 32 - "Community 32"
|
||||
Cohesion: 0.12
|
||||
Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
|
||||
|
||||
### Community 33 - "Community 33"
|
||||
Cohesion: 0.16
|
||||
Nodes (14): fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList(), fetchEnvDetectItemsActive(), fetchUpdateEnvDetectItem(), handleAdd(), handleBatchDelete() (+6 more)
|
||||
@@ -239,73 +239,73 @@ Cohesion: 0.27
|
||||
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
|
||||
|
||||
### Community 36 - "Community 36"
|
||||
Cohesion: 0.33
|
||||
Nodes (13): buildProtocolPaymentFlowSteps(), dash(), financeReceiptTime(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit() (+5 more)
|
||||
|
||||
### Community 37 - "Community 37"
|
||||
Cohesion: 0.19
|
||||
Nodes (6): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData(), switchTab()
|
||||
|
||||
### Community 39 - "Community 39"
|
||||
### Community 38 - "Community 38"
|
||||
Cohesion: 0.24
|
||||
Nodes (8): fullFileUrl(), handlePreviewAttachment(), isVideoFile(), normalizeDisplayValue(), resolveReviewCellType(), resolveReviewQuantity(), resolveReviewSpecText(), uniqueJoined()
|
||||
|
||||
### Community 40 - "Community 40"
|
||||
### Community 39 - "Community 39"
|
||||
Cohesion: 0.24
|
||||
Nodes (4): addMaterialRow(), nextMaterialRowKey(), onRequisitionSelect(), removeMaterialRow()
|
||||
|
||||
### Community 41 - "Community 41"
|
||||
### Community 40 - "Community 40"
|
||||
Cohesion: 0.25
|
||||
Nodes (2): handleTouchEnd(), setTransition()
|
||||
|
||||
### Community 44 - "Community 44"
|
||||
### Community 41 - "Community 41"
|
||||
Cohesion: 0.28
|
||||
Nodes (4): fetchMyProductionMaterialConsumptions(), handleReset(), handleSearch(), loadData()
|
||||
Nodes (1): FireworkSystem
|
||||
|
||||
### Community 46 - "Community 46"
|
||||
### Community 45 - "Community 45"
|
||||
Cohesion: 0.39
|
||||
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
|
||||
|
||||
### Community 47 - "Community 47"
|
||||
### Community 46 - "Community 46"
|
||||
Cohesion: 0.36
|
||||
Nodes (1): TableHeightCalculator
|
||||
|
||||
### Community 49 - "Community 49"
|
||||
### Community 48 - "Community 48"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): logApiCryptoBootInfo(), maskSecret()
|
||||
|
||||
### Community 50 - "Community 50"
|
||||
### Community 49 - "Community 49"
|
||||
Cohesion: 0.38
|
||||
Nodes (4): handleFocus(), handleInput(), parseDecimalToNumber(), sanitizeDecimalInput()
|
||||
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 0.29
|
||||
Nodes (2): fetchLeaveDetail(), fetchLeaveList()
|
||||
|
||||
### Community 52 - "Community 52"
|
||||
### Community 50 - "Community 50"
|
||||
Cohesion: 0.4
|
||||
Nodes (2): isUnfinishedQcWorkOrder(), resolveQcWorkOrderUnfinishedBadgeCount()
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
### Community 51 - "Community 51"
|
||||
Cohesion: 0.47
|
||||
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
|
||||
|
||||
### Community 54 - "Community 54"
|
||||
### Community 52 - "Community 52"
|
||||
Cohesion: 0.33
|
||||
Nodes (2): fetchEnvDetectRecordDetail(), fetchEnvDetectRecordList()
|
||||
|
||||
### Community 53 - "Community 53"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): formatProtocolDocDeleteConfirm(), formatProtocolDocSubject()
|
||||
|
||||
### Community 55 - "Community 55"
|
||||
### Community 54 - "Community 54"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): parseEquipmentIds(), syncEquipmentNamesFromOptions()
|
||||
|
||||
### Community 57 - "Community 57"
|
||||
### Community 56 - "Community 56"
|
||||
Cohesion: 0.5
|
||||
Nodes (2): focusInput(), handleKeydown()
|
||||
|
||||
### Community 59 - "Community 59"
|
||||
### Community 58 - "Community 58"
|
||||
Cohesion: 0.67
|
||||
Nodes (2): if(), logSidebarMenu()
|
||||
|
||||
### Community 60 - "Community 60"
|
||||
Cohesion: 0.5
|
||||
Nodes (1): fetchQcSmsList()
|
||||
|
||||
### Community 63 - "Community 63"
|
||||
Cohesion: 1.0
|
||||
Nodes (2): getSettingDefaults(), resetToDefaults()
|
||||
@@ -327,25 +327,29 @@ Cohesion: 1.0
|
||||
Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
|
||||
|
||||
## Knowledge Gaps
|
||||
- **Thin community `Community 18`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
|
||||
- **Thin community `Community 21`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 41`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
|
||||
- **Thin community `Community 40`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 47`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
- **Thin community `Community 41`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 49`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
- **Thin community `Community 46`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 51`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
|
||||
- **Thin community `Community 48`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 52`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
|
||||
- **Thin community `Community 50`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 54`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
- **Thin community `Community 52`** (6 nodes): `fetchCreateEnvDetectRecord()`, `fetchDeleteEnvDetectRecord()`, `fetchEnvDetectRecordDetail()`, `fetchEnvDetectRecordList()`, `fetchUpdateEnvDetectRecord()`, `env-detect-record.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 55`** (5 nodes): `equipmentOptionLabel()`, `joinEquipmentIds()`, `parseEquipmentIds()`, `syncEquipmentNamesFromOptions()`, `equipment-select.ts`
|
||||
- **Thin community `Community 53`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 57`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
- **Thin community `Community 54`** (5 nodes): `equipmentOptionLabel()`, `joinEquipmentIds()`, `parseEquipmentIds()`, `syncEquipmentNamesFromOptions()`, `equipment-select.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 59`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
- **Thin community `Community 56`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 58`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 60`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
- **Thin community `Community 63`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
|
||||
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
|
||||
@@ -361,16 +365,16 @@ Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 15`, `Community 16`, `Community 19`, `Community 21`, `Community 23`, `Community 25`, `Community 26`, `Community 27`, `Community 29`, `Community 30`, `Community 32`, `Community 33`, `Community 37`, `Community 44`, `Community 51`?**
|
||||
_High betweenness centrality (0.277) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 2` to `Community 0`, `Community 1`, `Community 3`, `Community 6`, `Community 7`, `Community 8`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 20`, `Community 21`, `Community 24`, `Community 25`, `Community 27`, `Community 31`, `Community 40`?**
|
||||
_High betweenness centrality (0.256) - this node is a cross-community bridge._
|
||||
- **Why does `fetchNotDeletedRegions()` connect `Community 0` to `Community 2`?**
|
||||
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 18`, `Community 20`, `Community 24`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 30`, `Community 31`, `Community 33`, `Community 36`, `Community 52`, `Community 60`?**
|
||||
_High betweenness centrality (0.308) - this node is a cross-community bridge._
|
||||
- **Why does `push()` connect `Community 4` to `Community 0`, `Community 1`, `Community 2`, `Community 5`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 15`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 21`, `Community 23`, `Community 26`, `Community 27`, `Community 28`, `Community 32`, `Community 39`, `Community 41`?**
|
||||
_High betweenness centrality (0.269) - this node is a cross-community bridge._
|
||||
- **Why does `fetchNotDeletedRegions()` connect `Community 0` to `Community 4`?**
|
||||
_High betweenness centrality (0.035) - this node is a cross-community bridge._
|
||||
- **Are the 278 inferred relationships involving `get()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
|
||||
_`get()` has 278 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 76 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
|
||||
_`push()` has 76 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 74 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
|
||||
_`push()` has 74 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 23 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleDialogClose()`) actually correct?**
|
||||
_`emit()` has 23 INFERRED edges - model-reasoned connections that need verification._
|
||||
- **Are the 19 inferred relationships involving `set()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
</div>
|
||||
<div id="legend"></div>
|
||||
</div>
|
||||
<div id="stats">2845 nodes · 3968 edges · 336 communities</div>
|
||||
<div id="stats">2839 nodes · 3960 edges · 336 communities</div>
|
||||
</div>
|
||||
<script>
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 49, "community_name": "Community 49", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 49, "community_name": "Community 49", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 112, "community_name": "Community 112", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 113, "community_name": "Community 113", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 28, "community_name": "Community 28", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 28, "community_name": "Community 28", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
|
||||
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 435}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 114}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 110}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 95}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 94}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 88}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 88}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 88}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 81}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 78}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 77}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 76}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 70}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 69}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 65}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 61}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 50}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 47}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 42}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 42}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 40}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 38}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 37}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 36}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 36}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 35}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 29}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 24}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 22}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 22}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 22}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 20}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 19}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 19}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 17}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 16}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 14}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 14}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 13}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 13}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 10}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 9}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 9}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 8}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 8}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 7}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 7}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 7}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 6}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 6}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 5}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 5}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 3}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 3}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "cLine truncated
|
||||
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 48, "community_name": "Community 48", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 48, "community_name": "Community 48", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 112, "community_name": "Community 112", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 113, "community_name": "Community 113", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 29, "community_name": "Community 29", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 29, "community_name": "Community 29", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 29, "community_name": "Community 29", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 29, "community_name": "Community 29", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 29, "community_name": "Community 29", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
|
||||
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
|
||||
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 451}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 133}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 96}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 94}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 90}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 89}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 88}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 85}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 82}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 72}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 71}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 69}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 69}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 64}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 61}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 50}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 48}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 47}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 45}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 43}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 43}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 42}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 37}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 36}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 36}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 35}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 35}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 34}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 24}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 22}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 22}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 22}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 20}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 19}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 17}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 16}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 14}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 13}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 13}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 10}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 9}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 9}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 9}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 9}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 9}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 8}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 8}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 8}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 7}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 7}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 6}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 6}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 6}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 5}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 5}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 4}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 3}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 3}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 3}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 3}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "Community 70", "couLine truncated
|
||||
|
||||
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
|
||||
function esc(s) {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1781272556.3597305,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1781272556.3601494,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1781272556.3606477,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1783327276.2077293,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1783327119.615712,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1783328469.3642685,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1783327938.8278427,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1781272556.364766,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1782394569.8806834,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/composables/useAttachmentDropZone.ts": 1782873161.9839864,
|
||||
@@ -59,7 +59,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-mine-task-groups.ts": 1783327864.4037368,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/expected-cell-count.ts": 1782705039.2515786,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-labels.ts": 1782893910.9937537,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1783303672.6673675,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts": 1783329871.573473,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-work-order-card-meta.ts": 1783306636.6246853,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fetch-paged-list.ts": 1781272556.3903377,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/decimal-input-format.ts": 1782807247.117702,
|
||||
@@ -92,9 +92,10 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/money-format.ts": 1782807264.1686463,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/category-path-display.ts": 1781272556.411347,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/transfer-type-dict.ts": 1782713881.7742825,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts": 1782961760.3056056,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts": 1783330000.923092,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/cell-product-spec.ts": 1782709946.3419836,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-selection-expand.ts": 1783322120.2724662,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts": 1783329823.1067264,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-labels.ts": 1781272556.4115942,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-step-assignee.ts": 1782472559.244021,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/process-material-ui.ts": 1781528129.339137,
|
||||
@@ -103,8 +104,8 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/loginRsa.ts": 1781272556.4129546,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/chinese-datetime-parse.ts": 1782958233.483039,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-task-editor-cache.ts": 1782602746.754815,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts": 1781431995.482862,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts": 1781432316.9136086,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts": 1783329869.6204023,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts": 1783329873.2829163,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/download-attachment.ts": 1781272556.4160507,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/ui/colors.ts": 1781272556.3798137,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/ui/emojo.ts": 1781272556.3802173,
|
||||
@@ -242,7 +243,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/sample-qc-batch-readonly/index.vue": 1782893851.9487352,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/outbound-material-form-sections/index.vue": 1782893851.934857,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/attachment-zip-progress-dialog/index.vue": 1782893851.6959429,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-payment-detail-readonly/index.vue": 1782893922.525934,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-payment-detail-readonly/index.vue": 1783330021.0864918,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/sample-code-with-special-display/index.vue": 1782893851.6283524,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/qc-item-param-select-editor/index.vue": 1782893851.5957565,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/system-view-dialog/index.vue": 1782893851.578115,
|
||||
@@ -314,9 +315,9 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/my-material-usage/index.vue": 1782893854.311591,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/index.vue": 1783326448.8937888,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolStatusChangeDialog.vue": 1782894806.0188534,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue": 1782894754.993778,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue": 1783330003.107557,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue": 1782893854.403395,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue": 1782982745.3279839,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue": 1783329986.6830297,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolAuditDialog.vue": 1782893854.3675368,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/index.vue": 1782893854.321358,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-reception-info/index.vue": 1782893854.265202,
|
||||
@@ -409,7 +410,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskPaperAttachmentsPanel.vue": 1782893853.2361045,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue": 1782893853.2094715,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue": 1782893853.1137185,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue": 1783306631.8896008,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue": 1783328174.4363172,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ForwardTaskDialog.vue": 1782893852.8302743,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderQcViewDialog.vue": 1782893852.7941833,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskStepSubList.vue": 1782893852.736343,
|
||||
@@ -469,7 +470,7 @@
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTabBar.vue": 1782893854.0314786,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderBatchSubList.vue": 1782893854.0134735,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue": 1783327877.2203474,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue": 1782893853.9119349,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue": 1783330023.9447763,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/tabs/OutboundPilotTab.vue": 1782893854.159883,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/tabs/InboundCellStorageTab.vue": 1782893854.1357596,
|
||||
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/tabs/QcWorkOrderTabPanel.vue": 1783327002.974947,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import {
|
||||
resolvePaymentPreset,
|
||||
getActiveSampleCount,
|
||||
isInstallmentPayMode,
|
||||
isPayModeValidForSampleCount
|
||||
} from '../src/utils/protocol-payment-presets'
|
||||
|
||||
const fq1 = resolvePaymentPreset(1, 'fq')!
|
||||
assert.equal(fq1.contractAmount, 25880)
|
||||
assert.deepEqual(fq1.installmentAmounts, [6480, 3880, 3880, 3880, 3880, 3880])
|
||||
assert.equal(
|
||||
fq1.installmentAmounts!.reduce((s, v) => s + v, 0),
|
||||
fq1.contractAmount
|
||||
)
|
||||
|
||||
const djfq2 = resolvePaymentPreset(2, 'djfq')!
|
||||
assert.equal(djfq2.contractAmount, 41000)
|
||||
assert.equal(djfq2.installmentCount, 4)
|
||||
assert.deepEqual(djfq2.installmentAmounts, [29360, 3880, 3880, 3880])
|
||||
assert.equal(
|
||||
djfq2.installmentAmounts!.reduce((s, v) => s + v, 0),
|
||||
djfq2.contractAmount
|
||||
)
|
||||
|
||||
assert.equal(getActiveSampleCount([{ sampleStatus: 'ycj' }]), 1)
|
||||
assert.equal(getActiveSampleCount([{ sampleStatus: 'ycj' }, { sampleStatus: 'yzf' }]), 1)
|
||||
assert.equal(
|
||||
getActiveSampleCount([{ sampleStatus: 'ycj' }, { sampleStatus: 'ycj' }]),
|
||||
2
|
||||
)
|
||||
|
||||
assert.equal(isInstallmentPayMode('djfq'), true)
|
||||
assert.equal(isInstallmentPayMode('dj'), false)
|
||||
assert.equal(isPayModeValidForSampleCount('djfq', 1), false)
|
||||
assert.equal(isPayModeValidForSampleCount('djfq', 2), true)
|
||||
|
||||
console.log('protocol-payment-presets: OK')
|
||||
@@ -37,11 +37,11 @@
|
||||
<dd>{{ maskIdCard(String(detail?.newbornIdCard || '')) }}</dd>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="detail?.payMode === 'fq'" class="view-kv">
|
||||
<div v-if="isInstallmentPayMode(String(detail?.payMode || ''))" class="view-kv">
|
||||
<dt>分期期序号</dt>
|
||||
<dd>{{ dash(detail?.installmentNo) }}</dd>
|
||||
</div>
|
||||
<div v-if="detail?.payMode === 'fq'" class="view-kv">
|
||||
<div v-if="isInstallmentPayMode(String(detail?.payMode || ''))" class="view-kv">
|
||||
<dt>应缴费时间</dt>
|
||||
<dd>{{ formatPaymentDueDate(detail?.installmentDueDate) }}</dd>
|
||||
</div>
|
||||
@@ -116,6 +116,7 @@
|
||||
loadTransferTypeDict,
|
||||
transferTypeLabel
|
||||
} from '@/utils/protocol-payment-labels'
|
||||
import { isInstallmentPayMode } from '@/utils/protocol-payment-presets'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry_ts", "label": "status-tag-registry.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L1"}, {"id": "utils_status_tag_registry_createlabelgetter", "label": "createLabelGetter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L23"}, {"id": "utils_status_tag_registry_createtagtypegetter", "label": "createTagTypeGetter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L27"}, {"id": "utils_status_tag_registry_isinactiveprotocolstatus", "label": "isInactiveProtocolStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L47"}, {"id": "utils_status_tag_registry_protocolstatusdisplaylabel", "label": "protocolStatusDisplayLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L55"}, {"id": "utils_status_tag_registry_donationstatusdisplaylabel", "label": "donationStatusDisplayLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L74"}, {"id": "utils_status_tag_registry_protocolstatusdisplaylabelbysource", "label": "protocolStatusDisplayLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L82"}, {"id": "utils_status_tag_registry_joinworkorderstatusfilter", "label": "joinWorkOrderStatusFilter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L203"}, {"id": "utils_status_tag_registry_matchesworkorderstatusfilter", "label": "matchesWorkOrderStatusFilter()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L208"}, {"id": "utils_status_tag_registry_txntypelabel", "label": "txnTypeLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L482"}, {"id": "utils_status_tag_registry_txntypetagtype", "label": "txnTypeTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L493"}, {"id": "utils_status_tag_registry_txnstatuslabel", "label": "txnStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L505"}, {"id": "utils_status_tag_registry_txnstatustagtype", "label": "txnStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L515"}, {"id": "utils_status_tag_registry_applicationstatuslabel", "label": "applicationStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L526"}, {"id": "utils_status_tag_registry_applicationstatustagtype", "label": "applicationStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L530"}, {"id": "utils_status_tag_registry_checkupstatuslabel", "label": "checkupStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L543"}, {"id": "utils_status_tag_registry_checkupstatustagtype", "label": "checkupStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L551"}, {"id": "utils_status_tag_registry_feestatuslabel", "label": "feeStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L559"}, {"id": "utils_status_tag_registry_feestatustagtype", "label": "feeStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L567"}, {"id": "utils_status_tag_registry_schedulestatuslabel", "label": "scheduleStatusLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L576"}, {"id": "utils_status_tag_registry_schedulestatustagtype", "label": "scheduleStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/status-tag-registry.ts", "source_location": "L585"}, {"id": "utils_sLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment_ts", "label": "protocol-payment-installment.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L1"}, {"id": "utils_protocol_payment_installment_defaultinstallmentratios", "label": "defaultInstallmentRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L10"}, {"id": "utils_protocol_payment_installment_resizeinstallmentratios", "label": "resizeInstallmentRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L19"}, {"id": "utils_protocol_payment_installment_finalizeinstallmentratios", "label": "finalizeInstallmentRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L31"}, {"id": "utils_protocol_payment_installment_isinstallmentratiosvalid", "label": "isInstallmentRatiosValid()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L39"}, {"id": "utils_protocol_payment_installment_islegacyinstallmentratios", "label": "isLegacyInstallmentRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L49"}, {"id": "utils_protocol_payment_installment_normalizeinstallmentamounts", "label": "normalizeInstallmentAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L64"}, {"id": "utils_protocol_payment_installment_defaultinstallmentamounts", "label": "defaultInstallmentAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L82"}, {"id": "utils_protocol_payment_installment_resizeinstallmentamounts", "label": "resizeInstallmentAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L89"}, {"id": "utils_protocol_payment_installment_isinstallmentamountsvalid", "label": "isInstallmentAmountsValid()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L115"}, {"id": "utils_protocol_payment_installment_suminstallmentamounts", "label": "sumInstallmentAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L125"}, {"id": "utils_protocol_payment_installment_scaleinstallmentamountstocontract", "label": "scaleInstallmentAmountsToContract()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L131"}, {"id": "utils_protocol_payment_installment_addmonthsymd", "label": "addMonthsYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L156"}, {"id": "utils_protocol_payment_installment_adddaysymd", "label": "addDaysYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L170"}, {"id": "utils_protocol_payment_installment_addintervalmonthsymd", "label": "addIntervalMonthsYmd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L185"}, {"id": "utils_protocol_payment_installment_calcfqinstallmentduedate", "label": "calcFqInstallmentDueDate()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L206"}, {"id": "utils_protocol_payment_installment_calcinstallmentdueamounts", "label": "calcInstallmentDueAmounts()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L219"}, {"id": "utils_protocol_payment_installment_calcinstallmentdueamountsbyratios", "label": "calcInstallmentDueAmountsByRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L239"}, {"id": "utils_protocol_payment_installment_calcunpaidamountsbyratios", "label": "calcUnpaidAmountsByRatios()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-installment.ts", "source_location": "L259"}, {"id": "utils_protocol_pLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolviewdialog_vue", "label": "ProtocolViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "label": "financeConfirmAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1659"}, {"id": "protocol_protocolviewdialog_refundattachmentfiles", "label": "refundAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1666"}, {"id": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "label": "refundFinanceConfirmAttachmentFiles()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1673"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolviewdialog_vue", "target": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1659", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolviewdialog_vue", "target": "protocol_protocolviewdialog_refundattachmentfiles", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1666", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolviewdialog_vue", "target": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1673", "weight": 1.0}], "raw_calls": [{"caller_nid": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1660"}, {"caller_nid": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "callee": "urlsToAttachmentFiles", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1663"}, {"caller_nid": "protocol_protocolviewdialog_financeconfirmattachmentfiles", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1663"}, {"caller_nid": "protocol_protocolviewdialog_refundattachmentfiles", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1667"}, {"caller_nid": "protocol_protocolviewdialog_refundattachmentfiles", "callee": "urlsToAttachmentFiles", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1670"}, {"caller_nid": "protocol_protocolviewdialog_refundattachmentfiles", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1670"}, {"caller_nid": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "callee": "isArray", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1674"}, {"caller_nid": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "callee": "urlsToAttachmentFiles", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1677"}, {"caller_nid": "protocol_protocolviewdialog_refundfinanceconfirmattachmentfiles", "callee": "String", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolViewDialog.vue", "source_location": "L1677"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_protocol_payment_detail_readonly_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/components/business/protocol-payment-detail-readonly/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "label": "protocol-payment-presets.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L1"}, {"id": "utils_protocol_payment_presets_getactivesamplecount", "label": "getActiveSampleCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L35"}, {"id": "utils_protocol_payment_presets_resolvepaymentpreset", "label": "resolvePaymentPreset()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L40"}, {"id": "utils_protocol_payment_presets_isinstallmentpaymode", "label": "isInstallmentPayMode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L47"}, {"id": "utils_protocol_payment_presets_availablepaymodes", "label": "availablePayModes()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L51"}, {"id": "utils_protocol_payment_presets_ispaymodevalidforsamplecount", "label": "isPayModeValidForSampleCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L56"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "target": "utils_protocol_payment_presets_getactivesamplecount", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L35", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "target": "utils_protocol_payment_presets_resolvepaymentpreset", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L40", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "target": "utils_protocol_payment_presets_isinstallmentpaymode", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L47", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "target": "utils_protocol_payment_presets_availablepaymodes", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L51", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets_ts", "target": "utils_protocol_payment_presets_ispaymodevalidforsamplecount", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L56", "weight": 1.0}, {"source": "utils_protocol_payment_presets_ispaymodevalidforsamplecount", "target": "utils_protocol_payment_presets_availablepaymodes", "relation": "calls", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L57", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_protocol_payment_presets_getactivesamplecount", "callee": "filter", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L36"}, {"caller_nid": "utils_protocol_payment_presets_ispaymodevalidforsamplecount", "callee": "includes", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-presets.ts", "source_location": "L57"}]}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "label": "QcWorkOrderProtocolPaymentPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L177", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L178", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_money_format", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L179", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L180", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L185", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L186", "weight": 1.0}], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "label": "ProtocolFormDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1"}, {"id": "protocol_protocolformdialog_ensuretransfertypeoptions", "label": "ensureTransferTypeOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1015"}, {"id": "protocol_protocolformdialog_fmtmoney", "label": "fmtMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1021"}, {"id": "protocol_protocolformdialog_pad", "label": "pad()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1414"}, {"id": "protocol_protocolformdialog_applypaymentpresetformode", "label": "applyPaymentPresetForMode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1715"}, {"id": "protocol_protocolformdialog_if", "label": "if()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1964"}, {"id": "protocol_protocolformdialog_for", "label": "for()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L1986"}, {"id": "protocol_protocolformdialog_applyfqpaymentdefaults", "label": "applyFqPaymentDefaults()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L2690"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_components_business_sample_transport_form_section_index_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L911", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L912", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L913", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_collection_protocol", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L926", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L932", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_download_attachment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L933", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_composables_useattachmentdropzone", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue", "source_location": "L934", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_cell_storage_protocol_protocolformdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_chinesLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_standard_import_parse_ts", "label": "protocol-standard-import-parse.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L1"}, {"id": "utils_protocol_standard_import_parse_normalizeline", "label": "normalizeLine()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L85"}, {"id": "utils_protocol_standard_import_parse_splitkeyvalue", "label": "splitKeyValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L91"}, {"id": "utils_protocol_standard_import_parse_normalizechinesedatetimeliteral", "label": "normalizeChineseDatetimeLiteral()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L97"}, {"id": "utils_protocol_standard_import_parse_parsedatetime", "label": "parseDatetime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L106"}, {"id": "utils_protocol_standard_import_parse_parsesex", "label": "parseSex()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L117"}, {"id": "utils_protocol_standard_import_parse_parsedeliverymode", "label": "parseDeliveryMode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L125"}, {"id": "utils_protocol_standard_import_parse_parsemoney", "label": "parseMoney()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L133"}, {"id": "utils_protocol_standard_import_parse_parsescore", "label": "parseScore()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L140"}, {"id": "utils_protocol_standard_import_parse_ismaternalbloodempty", "label": "isMaternalBloodEmpty()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L144"}, {"id": "utils_protocol_standard_import_parse_resolvesamplecollecthint", "label": "resolveSampleCollectHint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L150"}, {"id": "utils_protocol_standard_import_parse_resolvesamplecodehint", "label": "resolveSampleCodeHint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L161"}, {"id": "utils_protocol_standard_import_parse_upsertsamplehint", "label": "upsertSampleHint()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L177"}, {"id": "utils_protocol_standard_import_parse_earliestcollecttime", "label": "earliestCollectTime()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L190"}, {"id": "utils_protocol_standard_import_parse_parsepaymodefromtext", "label": "parsePayModeFromText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L197"}, {"id": "utils_protocol_standard_import_parse_parsepaymenttransfersegments", "label": "parsePaymentTransferSegments()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L211"}, {"id": "utils_protocol_standard_import_parse_resolvetransfertypecode", "label": "resolveTransferTypeCode()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L260"}, {"id": "utils_protocol_standard_import_parse_extractcarriernamefromtransport", "label": "extractCarrierNameFromTransport()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L289"}, {"id": "utils_protocol_standard_import_parse_parseprotocolstandardimporttext", "label": "parseProtocolStandardImportText()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-standard-import-parse.ts", "source_location": "L296"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_standard_imLine truncated
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "label": "protocol-pay-mode-switch.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L1"}, {"id": "utils_protocol_pay_mode_switch_ispaydetaillocked", "label": "isPayDetailLocked()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L34"}, {"id": "utils_protocol_pay_mode_switch_markpaydetaillocks", "label": "markPayDetailLocks()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L39"}, {"id": "utils_protocol_pay_mode_switch_sumpaidamount", "label": "sumPaidAmount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L45"}, {"id": "utils_protocol_pay_mode_switch_calcremainingamount", "label": "calcRemainingAmount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L51"}, {"id": "utils_protocol_pay_mode_switch_formatmoneysummary", "label": "formatMoneySummary()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L57"}, {"id": "utils_protocol_pay_mode_switch_activedetails", "label": "activeDetails()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L61"}, {"id": "utils_protocol_pay_mode_switch_hasblockingstatus", "label": "hasBlockingStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L65"}, {"id": "utils_protocol_pay_mode_switch_countbystatus", "label": "countByStatus()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L69"}, {"id": "utils_protocol_pay_mode_switch_buildinstallmentdetails", "label": "buildInstallmentDetails()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L73"}, {"id": "utils_protocol_pay_mode_switch_createpaymentdetailrow", "label": "createPaymentDetailRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L102"}, {"id": "utils_protocol_pay_mode_switch_evaluatepaymodeswitch", "label": "evaluatePayModeSwitch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L126"}, {"id": "utils_protocol_pay_mode_switch_applypaymodeswitch", "label": "applyPayModeSwitch()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L208"}, {"id": "utils_protocol_pay_mode_switch_canaddpaymentdetail", "label": "canAddPaymentDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L244"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_installment", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L6", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_payment_presets", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L11", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "target": "utils_protocol_pay_mode_switch_ispaydetaillocked", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L34", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "target": "utils_protocol_pay_mode_switch_markpaydetaillocks", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-pay-mode-switch.ts", "source_location": "L39", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_protocol_pay_mode_switch_ts", "target": "utils_protocol_payLine truncated
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 采集协议单 · 缴费模式切换(dj ↔ fq)
|
||||
* 采集协议单 · 缴费模式切换(dj / fq / djfq)
|
||||
* 规则见 docs/superpowers/specs/2026-06-04-protocol-pay-mode-switch-design.md
|
||||
*/
|
||||
|
||||
@@ -8,8 +8,9 @@ import {
|
||||
DEFAULT_INSTALLMENT_ADVANCE_DAYS,
|
||||
defaultInstallmentAmounts
|
||||
} from '@/utils/protocol-payment-installment'
|
||||
import { type PayMode, isInstallmentPayMode } from '@/utils/protocol-payment-presets'
|
||||
|
||||
export type PayMode = 'dj' | 'fq'
|
||||
export type { PayMode }
|
||||
export type DetailLike = Record<string, any>
|
||||
|
||||
const LOCKED_STATUSES = new Set(['jfqrz', 'yjf', 'tfqrz', 'ytf'])
|
||||
@@ -69,6 +70,35 @@ function countByStatus(details: DetailLike[], status: string): number {
|
||||
return details.filter((d) => String(d.payStatus || 'dfj') === status).length
|
||||
}
|
||||
|
||||
function buildInstallmentDetails(
|
||||
ctx: PayModeSwitchContext,
|
||||
rows: DetailLike[]
|
||||
): DetailLike[] {
|
||||
const count = Number(ctx.installmentCount) || 6
|
||||
const interval = Number(ctx.installmentIntervalMonths) || 6
|
||||
const startDate = ctx.installmentStartDate || ''
|
||||
const advanceDays = Number(ctx.installmentAdvanceDays ?? DEFAULT_INSTALLMENT_ADVANCE_DAYS)
|
||||
const amounts =
|
||||
ctx.installmentRatios?.length && sumPaidAmount(rows) === 0
|
||||
? ctx.installmentRatios.map((v) => Number(v || 0))
|
||||
: defaultInstallmentAmounts(ctx.contractAmount, count)
|
||||
const result: DetailLike[] = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
result.push(
|
||||
createPaymentDetailRow({
|
||||
dueAmount: amounts[i] ?? null,
|
||||
installmentNo: i + 1,
|
||||
installmentDueDate:
|
||||
startDate && interval
|
||||
? calcFqInstallmentDueDate(startDate, i, interval, advanceDays)
|
||||
: '',
|
||||
expanded: i === 0
|
||||
})
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function createPaymentDetailRow(options: {
|
||||
dueAmount: number | null
|
||||
installmentDueDate?: string
|
||||
@@ -110,7 +140,7 @@ export function evaluatePayModeSwitch(
|
||||
}
|
||||
}
|
||||
|
||||
if (fromMode === 'dj' && toMode === 'fq') {
|
||||
if (fromMode === 'dj' && isInstallmentPayMode(toMode)) {
|
||||
if (rows.some((d) => isPayDetailLocked(d))) {
|
||||
return {
|
||||
action: 'blocked',
|
||||
@@ -118,13 +148,14 @@ export function evaluatePayModeSwitch(
|
||||
}
|
||||
}
|
||||
const count = ctx.installmentCount || 6
|
||||
const label = toMode === 'djfq' ? '趸交+分期' : '分期'
|
||||
return {
|
||||
action: 'confirm',
|
||||
summary: `将清除当前趸交计划,按 ${count} 期分期重新生成缴费明细。是否继续?`
|
||||
summary: `将清除当前趸交计划,按 ${count} 期${label}重新生成缴费明细。是否继续?`
|
||||
}
|
||||
}
|
||||
|
||||
if (fromMode === 'fq' && toMode === 'dj') {
|
||||
if (isInstallmentPayMode(fromMode) && toMode === 'dj') {
|
||||
const dfjCount = countByStatus(rows, 'dfj')
|
||||
const yjfCount = countByStatus(rows, 'yjf')
|
||||
|
||||
@@ -156,6 +187,21 @@ export function evaluatePayModeSwitch(
|
||||
}
|
||||
}
|
||||
|
||||
if (isInstallmentPayMode(fromMode) && isInstallmentPayMode(toMode) && fromMode !== toMode) {
|
||||
if (rows.some((d) => isPayDetailLocked(d))) {
|
||||
return {
|
||||
action: 'blocked',
|
||||
reason: '分期已有缴费记录,无法切换分期类型。'
|
||||
}
|
||||
}
|
||||
const count = ctx.installmentCount || 6
|
||||
const label = toMode === 'djfq' ? '趸交+分期' : '分期'
|
||||
return {
|
||||
action: 'confirm',
|
||||
summary: `将按 ${count} 期${label}重新生成缴费明细。是否继续?`
|
||||
}
|
||||
}
|
||||
|
||||
return { action: 'noop' }
|
||||
}
|
||||
|
||||
@@ -167,33 +213,11 @@ export function applyPayModeSwitch(
|
||||
): DetailLike[] {
|
||||
const rows = activeDetails(details)
|
||||
|
||||
if (fromMode === 'dj' && toMode === 'fq') {
|
||||
const count = Number(ctx.installmentCount) || 6
|
||||
const interval = Number(ctx.installmentIntervalMonths) || 6
|
||||
const startDate = ctx.installmentStartDate || ''
|
||||
const advanceDays = Number(ctx.installmentAdvanceDays ?? DEFAULT_INSTALLMENT_ADVANCE_DAYS)
|
||||
const amounts =
|
||||
ctx.installmentRatios?.length && sumPaidAmount(rows) === 0
|
||||
? ctx.installmentRatios.map((v) => Number(v || 0))
|
||||
: defaultInstallmentAmounts(ctx.contractAmount, count)
|
||||
const result: DetailLike[] = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
result.push(
|
||||
createPaymentDetailRow({
|
||||
dueAmount: amounts[i] ?? null,
|
||||
installmentNo: i + 1,
|
||||
installmentDueDate:
|
||||
startDate && interval
|
||||
? calcFqInstallmentDueDate(startDate, i, interval, advanceDays)
|
||||
: '',
|
||||
expanded: i === 0
|
||||
})
|
||||
)
|
||||
}
|
||||
return result
|
||||
if (fromMode === 'dj' && isInstallmentPayMode(toMode)) {
|
||||
return buildInstallmentDetails(ctx, rows)
|
||||
}
|
||||
|
||||
if (fromMode === 'fq' && toMode === 'dj') {
|
||||
if (isInstallmentPayMode(fromMode) && toMode === 'dj') {
|
||||
const yjfRows = rows
|
||||
.filter((d) => String(d.payStatus) === 'yjf')
|
||||
.map((d) => ({ ...d, _payModeLocked: true }))
|
||||
@@ -209,14 +233,14 @@ export function applyPayModeSwitch(
|
||||
return [...yjfRows, newDjRow]
|
||||
}
|
||||
|
||||
if (isInstallmentPayMode(fromMode) && isInstallmentPayMode(toMode) && fromMode !== toMode) {
|
||||
return buildInstallmentDetails(ctx, rows)
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
/** 趸交模式下是否还可添加待缴明细 */
|
||||
export function canAddPaymentDetail(payMode: string, details: DetailLike[]): boolean {
|
||||
if (payMode === 'fq') return true
|
||||
const dfjCount = details.filter(
|
||||
(d) => !isPayDetailLocked(d) && String(d.payStatus || 'dfj') === 'dfj'
|
||||
).length
|
||||
return dfjCount < 1
|
||||
/** 趸交与分期均允许多条缴费明细(合计须等于合同金额) */
|
||||
export function canAddPaymentDetail(_payMode: string, _details: DetailLike[]): boolean {
|
||||
return true
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
/** 分期缴费:期数对齐、应缴日/金额计算(与 ProtocolFormDialog 逻辑一致) */
|
||||
|
||||
import { isInstallmentPayMode } from '@/utils/protocol-payment-presets'
|
||||
|
||||
const DAYS_PER_MONTH = 30
|
||||
|
||||
export const DEFAULT_INSTALLMENT_ADVANCE_DAYS = 30
|
||||
@@ -311,7 +313,7 @@ export function alignFqPaymentDetailsForDisplay(
|
||||
payment: PaymentLike,
|
||||
details: DetailLike[]
|
||||
): DetailLike[] {
|
||||
if (!payment || payment.payMode !== 'fq') return details
|
||||
if (!payment || !isInstallmentPayMode(String(payment.payMode || ''))) return details
|
||||
const count = Number(payment.installmentCount)
|
||||
if (!count || count < 1) return details
|
||||
|
||||
@@ -396,7 +398,7 @@ export function syncFqPaymentDetailRowCount(
|
||||
},
|
||||
paymentDetails: DetailLike[]
|
||||
): void {
|
||||
if (payment.payMode !== 'fq') return
|
||||
if (!isInstallmentPayMode(payment.payMode)) return
|
||||
const count = Number(payment.installmentCount)
|
||||
if (!count || count < 1) return
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/** 采集协议单 · 缴费默认定价表(样本数 × 缴费模式) */
|
||||
|
||||
export type PayMode = 'dj' | 'fq' | 'djfq'
|
||||
|
||||
export type PaymentPreset = {
|
||||
contractAmount: number
|
||||
installmentCount?: number
|
||||
installmentAmounts?: number[]
|
||||
}
|
||||
|
||||
const PRESETS: Record<1 | 2, Partial<Record<PayMode, PaymentPreset>>> = {
|
||||
1: {
|
||||
dj: { contractAmount: 22880 },
|
||||
fq: {
|
||||
contractAmount: 25880,
|
||||
installmentCount: 6,
|
||||
installmentAmounts: [6480, 3880, 3880, 3880, 3880, 3880]
|
||||
}
|
||||
},
|
||||
2: {
|
||||
dj: { contractAmount: 37880 },
|
||||
djfq: {
|
||||
contractAmount: 41000,
|
||||
installmentCount: 4,
|
||||
installmentAmounts: [29360, 3880, 3880, 3880]
|
||||
},
|
||||
fq: {
|
||||
contractAmount: 44000,
|
||||
installmentCount: 5,
|
||||
installmentAmounts: [12960, 7760, 7760, 7760, 7760]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveSampleCount(samples: Array<{ sampleStatus?: string }>): 1 | 2 {
|
||||
const n = samples.filter((s) => String(s.sampleStatus || '') !== 'yzf').length
|
||||
return (n >= 2 ? 2 : 1) as 1 | 2
|
||||
}
|
||||
|
||||
export function resolvePaymentPreset(
|
||||
sampleCount: 1 | 2,
|
||||
payMode: PayMode
|
||||
): PaymentPreset | null {
|
||||
return PRESETS[sampleCount]?.[payMode] ?? null
|
||||
}
|
||||
|
||||
export function isInstallmentPayMode(payMode: string): boolean {
|
||||
return payMode === 'fq' || payMode === 'djfq'
|
||||
}
|
||||
|
||||
export function availablePayModes(sampleCount: 1 | 2): PayMode[] {
|
||||
return sampleCount === 2 ? ['dj', 'djfq', 'fq'] : ['dj', 'fq']
|
||||
}
|
||||
|
||||
/** 校验缴费模式与样本数是否匹配(如 djfq 仅双样本) */
|
||||
export function isPayModeValidForSampleCount(payMode: PayMode, sampleCount: 1 | 2): boolean {
|
||||
return availablePayModes(sampleCount).includes(payMode)
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export type ProtocolStandardImportParsed = {
|
||||
medicalStaff?: string
|
||||
hospitalName?: string
|
||||
salesUserName?: string
|
||||
payMode: 'dj' | 'fq'
|
||||
payMode: 'dj' | 'fq' | 'djfq'
|
||||
contractAmount?: number | null
|
||||
transferTypeLabel?: string
|
||||
paymentTransfers: ProtocolPaymentTransferHint[]
|
||||
@@ -193,12 +193,13 @@ function earliestCollectTime(hints: ProtocolSampleImportHint[]): string | undefi
|
||||
return times.sort((a, b) => a.localeCompare(b))[0]
|
||||
}
|
||||
|
||||
/** 缴费方式:仅「分期」为 fq,其余(含微信/趸交)均为 dj */
|
||||
/** 缴费方式:趸交+分期 → djfq;仅「分期」→ fq;其余 → dj */
|
||||
export function parsePayModeFromText(value: string): {
|
||||
payMode: 'dj' | 'fq'
|
||||
payMode: 'dj' | 'fq' | 'djfq' | 'djfq'
|
||||
transferLabel?: string
|
||||
} {
|
||||
const v = (value || '').trim()
|
||||
if (/趸交\s*[++]\s*分期|趸交.*分期/.test(v)) return { payMode: 'djfq' }
|
||||
if (/分期/.test(v)) return { payMode: 'fq' }
|
||||
if (/微信|支付宝|银行卡|银行|现金/.test(v)) {
|
||||
return { payMode: 'dj', transferLabel: v }
|
||||
|
||||
@@ -117,7 +117,8 @@ export const auditStatusTagType = createTagTypeGetter(auditStatus)
|
||||
|
||||
export const payMode: StatusRegistry = {
|
||||
dj: { label: '趸交', tagType: 'primary' },
|
||||
fq: { label: '分期', tagType: 'warning' }
|
||||
fq: { label: '分期', tagType: 'warning' },
|
||||
djfq: { label: '趸交+分期', tagType: 'warning' }
|
||||
}
|
||||
export const payModeLabel = createLabelGetter(payMode)
|
||||
export const payModeTagType = createTagTypeGetter(payMode)
|
||||
|
||||
@@ -529,10 +529,19 @@
|
||||
<div class="section-subtitle">缴费主表</div>
|
||||
<div class="form-grid form-grid--col6">
|
||||
<el-form-item label="缴费模式">
|
||||
<el-radio-group v-model="formData.payMode" @change="onPayModeChange">
|
||||
<el-radio label="dj">趸交</el-radio>
|
||||
<el-radio label="fq">分期</el-radio>
|
||||
</el-radio-group>
|
||||
<el-select
|
||||
v-model="formData.payMode"
|
||||
placeholder="请选择缴费模式"
|
||||
style="width: 100%"
|
||||
@change="onPayModeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in payModeOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="合同金额(元)">
|
||||
<AmountInput
|
||||
@@ -556,7 +565,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="formData.payMode === 'fq'">
|
||||
<template v-if="isInstallmentPayMode(formData.payMode)">
|
||||
<el-form-item label="分期期数">
|
||||
<el-input
|
||||
v-model="formData.installmentCount"
|
||||
@@ -602,39 +611,6 @@
|
||||
</el-form-item>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="formData.payMode === 'fq'" class="installment-amounts-row">
|
||||
<el-form-item label="分期金额(元)" class="installment-amounts-field">
|
||||
<div class="installment-amounts-cells">
|
||||
<div
|
||||
v-for="(_amount, rIdx) in formData.installmentRatios"
|
||||
:key="rIdx"
|
||||
class="installment-amount-cell"
|
||||
>
|
||||
<span class="installment-amount-cell-no">{{ rIdx + 1 }}期</span>
|
||||
<AmountInput
|
||||
v-model="formData.installmentRatios[rIdx]"
|
||||
:min="0"
|
||||
placeholder="金额"
|
||||
@change="onInstallmentAmountChange(rIdx)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<div class="installment-amounts-summary-row">
|
||||
<span
|
||||
class="installment-amounts-sum"
|
||||
:class="{ 'is-error': !!installmentAmountsError }"
|
||||
>
|
||||
合计 {{ fmtMoney(installmentAmountsSum) }}
|
||||
<template v-if="formData.contractAmount != null">
|
||||
/ 合同 {{ fmtMoney(formData.contractAmount) }}
|
||||
</template>
|
||||
</span>
|
||||
<div v-if="installmentAmountsError" class="form-tip form-tip--error">
|
||||
{{ installmentAmountsError }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 缴费明细 -->
|
||||
@@ -693,7 +669,7 @@
|
||||
type="danger"
|
||||
size="small"
|
||||
class="detail-delete"
|
||||
@click.stop="formData.paymentDetails.splice(dIdx, 1)"
|
||||
@click.stop="removePaymentDetail(dIdx)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
@@ -963,22 +939,28 @@
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import {
|
||||
DEFAULT_INSTALLMENT_ADVANCE_DAYS,
|
||||
isInstallmentAmountsValid,
|
||||
normalizeInstallmentAmounts,
|
||||
resizeInstallmentAmounts,
|
||||
scaleInstallmentAmountsToContract,
|
||||
sumInstallmentAmounts,
|
||||
syncFqPaymentDetailRowCount
|
||||
} from '@/utils/protocol-payment-installment'
|
||||
import {
|
||||
applyPayModeSwitch,
|
||||
canAddPaymentDetail,
|
||||
createPaymentDetailRow,
|
||||
evaluatePayModeSwitch,
|
||||
isPayDetailLocked,
|
||||
markPayDetailLocks,
|
||||
sumPaidAmount,
|
||||
type PayMode
|
||||
} from '@/utils/protocol-pay-mode-switch'
|
||||
import {
|
||||
availablePayModes,
|
||||
getActiveSampleCount,
|
||||
isInstallmentPayMode,
|
||||
isPayModeValidForSampleCount,
|
||||
resolvePaymentPreset,
|
||||
type PayMode as PresetPayMode
|
||||
} from '@/utils/protocol-payment-presets'
|
||||
import {
|
||||
applyFqParamsChange,
|
||||
evaluateFqParamsChange,
|
||||
@@ -1019,6 +1001,21 @@
|
||||
/** 上次确认生效的缴费模式(用于切换取消/拦截时回滚) */
|
||||
const lastConfirmedPayMode = ref<PayMode>('dj')
|
||||
|
||||
const activeSampleCount = computed(() => getActiveSampleCount(formData.samples))
|
||||
|
||||
const payModeOptions = computed(() => {
|
||||
const modes = [...availablePayModes(activeSampleCount.value)]
|
||||
const current = String(formData.payMode || '') as PresetPayMode
|
||||
if (current && !modes.includes(current)) {
|
||||
modes.push(current)
|
||||
}
|
||||
return modes.map((value) => ({ value, label: payModeLabel(value) }))
|
||||
})
|
||||
|
||||
function hasLockedPaymentDetails() {
|
||||
return formData.paymentDetails.some((d) => isPayDetailLocked(d))
|
||||
}
|
||||
|
||||
/** 上次确认生效的分期参数(用于编辑时修改期数/间隔/开始时间回滚) */
|
||||
const lastConfirmedFqParams = ref<FqParams>({
|
||||
installmentCount: null,
|
||||
@@ -1357,6 +1354,9 @@
|
||||
|
||||
function scrollToSection(key: string) {
|
||||
activeFormTab.value = key
|
||||
if (key === 'payment') {
|
||||
maybeApplyPaymentPresetOnTabEnter()
|
||||
}
|
||||
const el = document.getElementById(`form-section-${key}`)
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
@@ -1386,6 +1386,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
function removePaymentDetail(dIdx: number) {
|
||||
const detail = formData.paymentDetails[dIdx]
|
||||
if (detail && isPayDetailLocked(detail)) return
|
||||
formData.paymentDetails.splice(dIdx, 1)
|
||||
syncContractAmountFromPaymentDetails()
|
||||
}
|
||||
|
||||
function addPaymentDetail() {
|
||||
if (!canAddPaymentDetail(formData.payMode, formData.paymentDetails)) return
|
||||
const now = new Date()
|
||||
@@ -1446,8 +1453,13 @@
|
||||
*/
|
||||
function applyFqPaymentDefaults(options?: { resetCountInterval?: boolean }) {
|
||||
const reset = options?.resetCountInterval ?? false
|
||||
const sampleCount = getActiveSampleCount(formData.samples)
|
||||
const preset = resolvePaymentPreset(sampleCount, formData.payMode as PresetPayMode)
|
||||
if (preset?.contractAmount != null) {
|
||||
formData.contractAmount = preset.contractAmount
|
||||
}
|
||||
if (reset || isFqNumericFieldEmpty(formData.installmentCount)) {
|
||||
formData.installmentCount = 6
|
||||
formData.installmentCount = preset?.installmentCount ?? 6
|
||||
}
|
||||
if (reset || isFqNumericFieldEmpty(formData.installmentIntervalMonths)) {
|
||||
formData.installmentIntervalMonths = 6
|
||||
@@ -1459,11 +1471,58 @@
|
||||
formData.installmentAdvanceDays = DEFAULT_INSTALLMENT_ADVANCE_DAYS
|
||||
}
|
||||
const count = toIntOrUndefined(formData.installmentCount) || 6
|
||||
formData.installmentRatios = normalizeInstallmentAmounts(
|
||||
formData.installmentRatios || [],
|
||||
formData.contractAmount,
|
||||
count
|
||||
)
|
||||
if (preset?.installmentAmounts?.length) {
|
||||
formData.installmentRatios = [...preset.installmentAmounts]
|
||||
} else {
|
||||
formData.installmentRatios = normalizeInstallmentAmounts(
|
||||
formData.installmentRatios || [],
|
||||
formData.contractAmount,
|
||||
count
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function applyPaymentPresetForMode(payMode: PresetPayMode) {
|
||||
const sampleCount = getActiveSampleCount(formData.samples)
|
||||
const preset = resolvePaymentPreset(sampleCount, payMode)
|
||||
if (!preset) return
|
||||
formData.contractAmount = preset.contractAmount
|
||||
if (isInstallmentPayMode(payMode) && preset.installmentCount) {
|
||||
formData.installmentCount = preset.installmentCount
|
||||
if (isFqNumericFieldEmpty(formData.installmentIntervalMonths)) {
|
||||
formData.installmentIntervalMonths = 6
|
||||
}
|
||||
if (!formData.installmentStartDate) {
|
||||
formData.installmentStartDate = defaultInstallmentStartDateYmd()
|
||||
}
|
||||
if (formData.installmentAdvanceDays == null) {
|
||||
formData.installmentAdvanceDays = DEFAULT_INSTALLMENT_ADVANCE_DAYS
|
||||
}
|
||||
formData.installmentRatios = [...(preset.installmentAmounts || [])]
|
||||
formData.paymentDetails = generateInitialFqDetails(
|
||||
getFqParamsFromForm(),
|
||||
preset.contractAmount
|
||||
)
|
||||
initPaymentDetailExpandFlags(formData.paymentDetails)
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
syncLastConfirmedFqParams()
|
||||
} else {
|
||||
formData.paymentDetails = [
|
||||
createPaymentDetailRow({
|
||||
dueAmount: preset.contractAmount,
|
||||
installmentDueDate: formData.lumpSumDeadline || '',
|
||||
expanded: true
|
||||
})
|
||||
]
|
||||
initPaymentDetailExpandFlags(formData.paymentDetails)
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
}
|
||||
}
|
||||
|
||||
function maybeApplyPaymentPresetOnTabEnter() {
|
||||
if (hasLockedPaymentDetails()) return
|
||||
if (formData.paymentDetails.length > 0) return
|
||||
applyPaymentPresetForMode(formData.payMode as PresetPayMode)
|
||||
}
|
||||
|
||||
function toIntOrUndefined(val: unknown): number | undefined {
|
||||
@@ -1529,7 +1588,7 @@
|
||||
* 与缴费模式切换独立;保留 yjf 已缴行,作废原 dfj 后按剩余金额重建。
|
||||
*/
|
||||
async function handleFqParamsChange() {
|
||||
if (formData.payMode !== 'fq') return
|
||||
if (formData.payMode !== 'fq' && formData.payMode !== 'djfq') return
|
||||
|
||||
const newParams = getFqParamsFromForm()
|
||||
const oldParams = lastConfirmedFqParams.value
|
||||
@@ -1625,25 +1684,35 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (toMode === 'fq') {
|
||||
applyFqPaymentDefaults({ resetCountInterval: false })
|
||||
if (!hasLockedPaymentDetails()) {
|
||||
applyPaymentPresetForMode(toMode as PresetPayMode)
|
||||
} else {
|
||||
if (isInstallmentPayMode(toMode)) {
|
||||
applyFqPaymentDefaults({ resetCountInterval: fromMode === 'dj' })
|
||||
}
|
||||
formData.paymentDetails = applyPayModeSwitch(
|
||||
fromMode,
|
||||
toMode,
|
||||
formData.paymentDetails,
|
||||
payModeSwitchContext()
|
||||
)
|
||||
initPaymentDetailExpandFlags(formData.paymentDetails)
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
const preset = resolvePaymentPreset(
|
||||
getActiveSampleCount(formData.samples),
|
||||
toMode as PresetPayMode
|
||||
)
|
||||
if (preset?.contractAmount != null) {
|
||||
formData.contractAmount = preset.contractAmount
|
||||
}
|
||||
}
|
||||
|
||||
formData.paymentDetails = applyPayModeSwitch(
|
||||
fromMode,
|
||||
toMode,
|
||||
formData.paymentDetails,
|
||||
payModeSwitchContext()
|
||||
)
|
||||
initPaymentDetailExpandFlags(formData.paymentDetails)
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
|
||||
if (toMode === 'dj') {
|
||||
syncLumpSumDueDate()
|
||||
}
|
||||
|
||||
lastConfirmedPayMode.value = toMode
|
||||
if (toMode === 'fq') {
|
||||
if (isInstallmentPayMode(toMode)) {
|
||||
syncLastConfirmedFqParams()
|
||||
}
|
||||
}
|
||||
@@ -1770,7 +1839,7 @@
|
||||
if (loadedAmounts.length) {
|
||||
formData.installmentRatios = loadedAmounts.map((v: unknown) => Number(v))
|
||||
}
|
||||
if (formData.payMode === 'fq') {
|
||||
if (isInstallmentPayMode(formData.payMode)) {
|
||||
applyFqPaymentDefaults()
|
||||
const count = toIntOrUndefined(formData.installmentCount) || 6
|
||||
formData.installmentRatios = normalizeInstallmentAmounts(
|
||||
@@ -1793,7 +1862,9 @@
|
||||
markPayDetailLocks(formData.paymentDetails)
|
||||
}
|
||||
syncFqPaymentDetailRowCount(fqPaymentContext(), formData.paymentDetails)
|
||||
lastConfirmedPayMode.value = (formData.payMode === 'fq' ? 'fq' : 'dj') as PayMode
|
||||
lastConfirmedPayMode.value = (
|
||||
['fq', 'djfq'].includes(formData.payMode) ? formData.payMode : 'dj'
|
||||
) as PayMode
|
||||
|
||||
const pa =
|
||||
(row as any).protocolAttachments || (bundle.protocol as any)?.protocolAttachments || ''
|
||||
@@ -1880,16 +1951,16 @@
|
||||
async function handleSubmit() {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate()
|
||||
if (formData.payMode === 'fq') {
|
||||
if (installmentAmountsError.value) {
|
||||
await ElMessageBox.alert(installmentAmountsError.value, '分期金额无效', { type: 'warning' })
|
||||
return
|
||||
}
|
||||
const amounts = (formData.installmentRatios || []).map((v) => Number(v || 0))
|
||||
if (!isInstallmentAmountsValid(amounts, formData.contractAmount)) {
|
||||
await ElMessageBox.alert('分期金额合计须等于合同金额', '分期金额无效', { type: 'warning' })
|
||||
return
|
||||
}
|
||||
const sampleCount = getActiveSampleCount(formData.samples)
|
||||
if (!isPayModeValidForSampleCount(formData.payMode as PresetPayMode, sampleCount)) {
|
||||
await ElMessageBox.alert(
|
||||
formData.payMode === 'djfq'
|
||||
? '「趸交+分期」仅适用于 2 个样本,请切换缴费模式'
|
||||
: '当前缴费模式与样本数量不匹配,请切换缴费模式',
|
||||
'无法保存',
|
||||
{ type: 'warning' }
|
||||
)
|
||||
return
|
||||
}
|
||||
if (!isEdit.value) {
|
||||
for (const sampleRow of formData.samples) {
|
||||
@@ -1969,8 +2040,7 @@
|
||||
installmentIntervalMonths: toFloatOrUndefined(formData.installmentIntervalMonths),
|
||||
installmentStartDate: formData.installmentStartDate || undefined,
|
||||
installmentAdvanceDays: toIntOrUndefined(formData.installmentAdvanceDays),
|
||||
installmentRatios:
|
||||
formData.payMode === 'fq'
|
||||
installmentRatios: isInstallmentPayMode(formData.payMode)
|
||||
? (formData.installmentRatios || []).map((v) => Number(v || 0))
|
||||
: undefined
|
||||
},
|
||||
@@ -2596,7 +2666,7 @@
|
||||
formData.payMode = parsed.payMode || 'dj'
|
||||
lastConfirmedPayMode.value = formData.payMode as PayMode
|
||||
|
||||
if (parsed.payMode === 'fq') {
|
||||
if (isInstallmentPayMode(parsed.payMode || 'dj')) {
|
||||
applyFqPaymentDefaults()
|
||||
}
|
||||
|
||||
@@ -3111,38 +3181,32 @@
|
||||
handleFqParamsChange()
|
||||
}
|
||||
|
||||
function onInstallmentAmountChange(_changedIdx: number) {
|
||||
syncPaymentDueAmounts()
|
||||
handleFqParamsChange()
|
||||
/** 缴费明细应缴金额之和回写合同金额 */
|
||||
function syncContractAmountFromPaymentDetails() {
|
||||
if (!formData.paymentDetails.length) return
|
||||
const total = formData.paymentDetails.reduce(
|
||||
(sum, d) => sum + (Number(d.dueAmount) || 0),
|
||||
0
|
||||
)
|
||||
formData.contractAmount = Math.round(total * 100) / 100
|
||||
}
|
||||
|
||||
/** 缴费明细应缴金额变更:分期模式下回写分期金额,保持与主表一致 */
|
||||
/** 缴费明细应缴金额变更:分期回写 installmentRatios,并同步合同金额 */
|
||||
function onPaymentDetailDueAmountChange(dIdx: number) {
|
||||
if (formData.payMode !== 'fq') return
|
||||
const detail = formData.paymentDetails[dIdx]
|
||||
if (!detail || isPayDetailLocked(detail)) return
|
||||
const installmentNo = Number(detail.installmentNo)
|
||||
const ratioIdx = installmentNo >= 1 ? installmentNo - 1 : dIdx
|
||||
if (!formData.installmentRatios) formData.installmentRatios = []
|
||||
while (formData.installmentRatios.length <= ratioIdx) {
|
||||
formData.installmentRatios.push(0)
|
||||
if (formData.payMode === 'fq' || formData.payMode === 'djfq') {
|
||||
const installmentNo = Number(detail.installmentNo)
|
||||
const ratioIdx = installmentNo >= 1 ? installmentNo - 1 : dIdx
|
||||
if (!formData.installmentRatios) formData.installmentRatios = []
|
||||
while (formData.installmentRatios.length <= ratioIdx) {
|
||||
formData.installmentRatios.push(0)
|
||||
}
|
||||
formData.installmentRatios[ratioIdx] = Number(detail.dueAmount) || 0
|
||||
}
|
||||
formData.installmentRatios[ratioIdx] = Number(detail.dueAmount) || 0
|
||||
syncContractAmountFromPaymentDetails()
|
||||
}
|
||||
|
||||
const installmentAmountsError = computed(() => {
|
||||
const amounts = formData.installmentRatios || []
|
||||
if (!amounts.length || formData.contractAmount == null) return ''
|
||||
if (amounts.some((v) => Number(v) < 0)) return '分期金额不能为负数'
|
||||
const sum = sumInstallmentAmounts(amounts)
|
||||
if (Math.abs(sum - Number(formData.contractAmount)) > 0.01) {
|
||||
return `分期金额合计须等于合同金额(${fmtMoney(formData.contractAmount)})`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const installmentAmountsSum = computed(() => sumInstallmentAmounts(formData.installmentRatios || []))
|
||||
|
||||
/** 按缴费模式同步各明细应缴费金额(跳过已锁定明细) */
|
||||
function syncPaymentDueAmounts() {
|
||||
const contract = formData.contractAmount
|
||||
@@ -3159,14 +3223,14 @@
|
||||
})
|
||||
return
|
||||
}
|
||||
if (formData.payMode === 'fq') {
|
||||
const count = formData.installmentCount || formData.paymentDetails.length
|
||||
if (formData.payMode === 'fq' || formData.payMode === 'djfq') {
|
||||
const count = Number(formData.installmentCount || formData.paymentDetails.length)
|
||||
if (!count) return
|
||||
const amounts = normalizeInstallmentAmounts(
|
||||
formData.installmentRatios || [],
|
||||
contract,
|
||||
Number(count)
|
||||
)
|
||||
const ratios = formData.installmentRatios || []
|
||||
const amounts =
|
||||
ratios.length === count
|
||||
? ratios.map((v) => Number(v || 0))
|
||||
: normalizeInstallmentAmounts(ratios, null, count)
|
||||
const paidRows = formData.paymentDetails.filter((d) => String(d.payStatus) === 'yjf')
|
||||
paidRows.forEach((d) => {
|
||||
const no = Number(d.installmentNo)
|
||||
@@ -3179,37 +3243,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** 合同金额手动变更:等比缩放分期金额并同步应缴费金额 */
|
||||
/** 合同金额手动变更:趸交时同步待缴明细应缴金额 */
|
||||
function onContractAmountChange() {
|
||||
if (formData.payMode === 'fq' && (formData.installmentRatios || []).length) {
|
||||
formData.installmentRatios = scaleInstallmentAmountsToContract(
|
||||
formData.installmentRatios,
|
||||
formData.contractAmount
|
||||
)
|
||||
if (formData.payMode === 'dj') {
|
||||
syncPaymentDueAmounts()
|
||||
}
|
||||
syncPaymentDueAmounts()
|
||||
}
|
||||
|
||||
/** 根据非作废样本价格之和同步合同金额,并联动应缴费金额 */
|
||||
function syncContractAmount() {
|
||||
const total = formData.samples.reduce((sum, s) => {
|
||||
if (s.sampleStatus === 'yzf') return sum
|
||||
return sum + (Number(s.price) || 0)
|
||||
}, 0)
|
||||
const nextContract = Math.round(total * 100) / 100
|
||||
if (formData.payMode === 'fq' && (formData.installmentRatios || []).length) {
|
||||
formData.installmentRatios = scaleInstallmentAmountsToContract(
|
||||
formData.installmentRatios,
|
||||
nextContract
|
||||
)
|
||||
}
|
||||
formData.contractAmount = nextContract
|
||||
syncPaymentDueAmounts()
|
||||
}
|
||||
|
||||
/** 样本价格或状态变更 */
|
||||
/** 样本价格或状态变更(不自动改合同金额) */
|
||||
function onSamplePriceChange() {
|
||||
syncContractAmount()
|
||||
// 保留样本价格字段,不与合同金额联动
|
||||
}
|
||||
|
||||
/* ====== 母亲身份证号 ↔ 出生年月联动 ====== */
|
||||
@@ -3232,6 +3275,22 @@
|
||||
() => calcBirthFromIdCard()
|
||||
)
|
||||
|
||||
/** 样本数变化时按当前缴费模式刷新默认定价(新增单;无已缴锁定明细时整单重填) */
|
||||
watch(activeSampleCount, () => {
|
||||
if (isEdit.value) return
|
||||
if (hasLockedPaymentDetails()) {
|
||||
const preset = resolvePaymentPreset(
|
||||
getActiveSampleCount(formData.samples),
|
||||
formData.payMode as PresetPayMode
|
||||
)
|
||||
if (preset?.contractAmount != null) {
|
||||
formData.contractAmount = preset.contractAmount
|
||||
}
|
||||
return
|
||||
}
|
||||
applyPaymentPresetForMode(formData.payMode as PresetPayMode)
|
||||
})
|
||||
|
||||
/* ====== 趸交截止时间联动 ====== */
|
||||
watch(
|
||||
() => formData.lumpSumDeadline,
|
||||
|
||||
@@ -642,7 +642,7 @@
|
||||
><div class="pm-value">{{ formatYmd(payment?.lumpSumDeadline) }}</div></div
|
||||
>
|
||||
</template>
|
||||
<template v-if="payment?.payMode === 'fq'">
|
||||
<template v-if="isInstallmentPayMode(String(payment?.payMode || ''))">
|
||||
<div class="payment-metric"
|
||||
><div class="pm-label">分期期数</div
|
||||
><div class="pm-value">{{ dash(payment?.installmentCount) }}</div></div
|
||||
@@ -720,11 +720,11 @@
|
||||
<span class="info-label">转账时间</span>
|
||||
<span class="info-value">{{ dash(detail.transferTime) }}</span>
|
||||
</div>
|
||||
<div v-if="payment?.payMode === 'fq'" class="pdc-info-item">
|
||||
<div v-if="isInstallmentPayMode(String(payment?.payMode || ''))" class="pdc-info-item">
|
||||
<span class="info-label">应缴费时间</span>
|
||||
<span class="info-value">{{ formatYmd(detail.installmentDueDate) }}</span>
|
||||
</div>
|
||||
<div v-if="payment?.payMode === 'fq'" class="pdc-info-item">
|
||||
<div v-if="isInstallmentPayMode(String(payment?.payMode || ''))" class="pdc-info-item">
|
||||
<span class="info-label">分期期序号</span>
|
||||
<span class="info-value">{{ dash(detail.installmentNo) }}</span>
|
||||
</div>
|
||||
@@ -1111,6 +1111,7 @@
|
||||
import { loadTransferTypeDict, transferTypeLabel } from '@/utils/protocol-payment-labels'
|
||||
import { loadVoidTypeDict, voidTypeLabel } from '@/utils/void-type-dict'
|
||||
import { formatProtocolDocSubject } from '@/utils/protocol-doc-label'
|
||||
import { isInstallmentPayMode } from '@/utils/protocol-payment-presets'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -1492,7 +1493,9 @@
|
||||
const steps: OverviewTimelineStep[] = details.map((d, i) => {
|
||||
const s = String(d.payStatus || '')
|
||||
const name =
|
||||
payment.value?.payMode === 'fq' ? `第${d.installmentNo || i + 1}期` : `缴费${i + 1}`
|
||||
isInstallmentPayMode(String(payment.value?.payMode || ''))
|
||||
? `第${d.installmentNo || i + 1}期`
|
||||
: `缴费${i + 1}`
|
||||
|
||||
if (s === 'ytf') {
|
||||
return {
|
||||
|
||||
+2
-1
@@ -183,6 +183,7 @@
|
||||
payStatusTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import type { TagType } from '@/utils/status-tag-registry'
|
||||
import { isInstallmentPayMode } from '@/utils/protocol-payment-presets'
|
||||
|
||||
defineOptions({ name: 'QcWorkOrderProtocolPaymentPanel' })
|
||||
|
||||
@@ -198,7 +199,7 @@
|
||||
hideInstallmentDetailAmounts?: boolean
|
||||
}>()
|
||||
|
||||
const isInstallment = computed(() => props.summary?.payMode === 'fq')
|
||||
const isInstallment = computed(() => isInstallmentPayMode(props.summary?.payMode || ''))
|
||||
|
||||
const isLumpSum = computed(() => props.summary?.payMode === 'dj')
|
||||
|
||||
|
||||
Reference in new issue
Block a user