Files
loan-pricing/docs/superpowers/plans/2026-05-11-shangyu-pricing-field-adjustment-frontend-plan.md

15 KiB

Shangyu Pricing Field Adjustment Frontend Implementation Plan

For agentic workers: Follow this repository's AGENTS.md: do not invoke using-superpowers or subagents during implementation unless the user explicitly requests them. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Update the personal and corporate workflow create dialogs so the displayed fields, dynamic options, required couponRate, and submitted payload match the approved Shangyu pricing spec.

Architecture: Keep the existing Vue 2 create-dialog components and static Node assertion tests. Update each dialog in place, using computed properties for customer-type-specific collateral options and the 质押 + 存单质押 coupon-rate condition; verify with static tests, production build, and a real Playwright browser check.

Tech Stack: Vue 2, Element UI, RuoYi request wrapper, Node static tests, npm scripts, nvm-controlled frontend runtime, Playwright real browser verification.


File Structure

  • Modify: ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue
    • Change businessType options.
    • Remove loanPurpose and bizProof UI, form fields, rules, reset values, and submit payload handling.
    • Change personal collateralTypeOptions.
    • Add couponRate conditional field and submit cleanup.
  • Modify: ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue
    • Change businessType options.
    • Change corporate collateralTypeOptions.
    • Add couponRate conditional field and submit cleanup.
  • Modify: ruoyi-ui/tests/business-type-history-rate.test.js
    • Update business-type assertions from 新客 to 新增.
    • Add couponRate assertions.
  • Modify: ruoyi-ui/tests/personal-create-input-params.test.js
    • Assert personal removed fields are absent.
    • Assert personal collateral options match the new spec.
  • Modify: ruoyi-ui/tests/corporate-create-input-params.test.js
    • Assert corporate collateral options match the new spec.
  • Modify: doc/implementation-report-2026-05-11-shangyu-pricing-field-adjustment.md
    • Add frontend implementation and Playwright verification notes after execution.

Task 1: Update Frontend Static Assertions First

Files:

  • Modify: ruoyi-ui/tests/business-type-history-rate.test.js

  • Modify: ruoyi-ui/tests/personal-create-input-params.test.js

  • Modify: ruoyi-ui/tests/corporate-create-input-params.test.js

  • Step 1: Update business-type assertions

In business-type-history-rate.test.js, replace old assertions for 新客 with:

;[
  ['个人新增弹窗', personalCreate],
  ['企业新增弹窗', corporateCreate]
].forEach(([name, source]) => {
  assert(source.includes('label="业务种类"'), `${name} 缺少业务种类`)
  assert(source.includes('value="新增"'), `${name} 缺少新增选项`)
  assert(source.includes('value="存量新增"'), `${name} 缺少存量新增选项`)
  assert(source.includes('value="存量转贷"'), `${name} 缺少存量转贷选项`)
  assert(!source.includes('value="新客"'), `${name} 仍保留旧业务种类 新客`)
  assert(source.includes("if (value === '存量转贷')"), `${name} 未保持仅存量转贷查询历史合同`)
})
  • Step 2: Add coupon-rate assertions

In the same test file, add:

;[
  ['个人新增弹窗', personalCreate],
  ['企业新增弹窗', corporateCreate]
].forEach(([name, source]) => {
  assert(source.includes('label="存单票面利率"'), `${name} 缺少存单票面利率字段`)
  assert(source.includes('prop="couponRate"'), `${name} 缺少 couponRate prop`)
  assert(source.includes('isCertificatePledge'), `${name} 缺少存单质押条件计算`)
  assert(source.includes("this.form.guarType === '质押'") && source.includes("this.form.collType === '存单质押'"), `${name} couponRate 条件不正确`)
  assert(source.includes('delete data.couponRate'), `${name} 未在非适用条件删除 couponRate`)
  assert(source.includes('存单票面利率不能为空'), `${name} 缺少 couponRate 必填提示`)
})

This shared business-type-history-rate.test.js is expected to remain failing until both personal and corporate dialogs are updated. Do not use it as a passing checkpoint after only the personal dialog is changed.

  • Step 3: Update personal-field assertions

In personal-create-input-params.test.js, replace old required assertions for loanPurpose and bizProof with absence checks:

assert(
  !personalCreateDialog.includes('label="贷款用途"') &&
    !personalCreateDialog.includes('prop="loanPurpose"') &&
    !personalCreateDialog.includes('loanPurpose:'),
  '个人新增弹窗不应继续保留贷款用途字段'
)

assert(
  !personalCreateDialog.includes('label="是否有经营佐证"') &&
    !personalCreateDialog.includes('prop="bizProof"') &&
    !personalCreateDialog.includes('bizProof:'),
  '个人新增弹窗不应继续保留是否有经营佐证字段'
)

Update personal collateral assertion:

assert(
  personalCreateDialog.includes("return ['一线', '一类', '二类', '三类']") &&
    personalCreateDialog.includes("return ['存单质押', '其他质押']"),
  '个人新增弹窗抵质押类型选项未按新口径动态切换'
)
  • Step 4: Update corporate collateral assertions

In corporate-create-input-params.test.js, replace old collateral assertion with:

assert(
  corporateCreateDialog.includes("return ['一类', '二类', '三类', '四类', '排污权抵押', '设备等其他不动产抵押']") &&
    corporateCreateDialog.includes("return ['存单质押', '股权质押', '其他质押']"),
  '企业新增弹窗抵质押类型选项未按新口径动态切换'
)
  • Step 5: Run frontend static tests and confirm failure

Run:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run test:business-type-history-rate && npm --prefix ruoyi-ui run test:personal-create-input-params && npm --prefix ruoyi-ui run test:corporate-create-input-params'

Expected: FAIL because the UI is not updated yet.

Task 2: Update Personal Create Dialog

Files:

  • Modify: ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue

  • Step 1: Change business type options

Replace the first option:

<el-option label="新增" value="新增"/>
<el-option label="存量新增" value="存量新增"/>
<el-option label="存量转贷" value="存量转贷"/>
  • Step 2: Remove personal fields from template

Delete the 贷款用途 form item and its surrounding column. Delete the 是否有经营佐证 form item. Keep 借款期限(年) and 循环功能.

If a row becomes single-column, leave it as a normal el-row with one el-col :span="12"; do not restructure the whole dialog.

  • Step 3: Remove personal fields from data, rules, and submit payload

Remove these from form initial state and reset():

loanPurpose: undefined,
bizProof: false,

Remove loanPurpose from rules.

Remove this submit conversion:

bizProof: this.form.bizProof ? '1' : '0',

Keep:

loanLoop: this.form.loanLoop ? '1' : '0'
  • Step 4: Update personal collateral options

Change collateralTypeOptions() to:

collateralTypeOptions() {
  if (this.form.guarType === '抵押') {
    return ['一线', '一类', '二类', '三类']
  }
  if (this.form.guarType === '质押') {
    return ['存单质押', '其他质押']
  }
  return []
}
  • Step 5: Add coupon-rate field

Add under the collateral row:

<el-col :span="12" v-if="isCertificatePledge">
  <el-form-item label="存单票面利率" prop="couponRate">
    <el-input v-model="form.couponRate" placeholder="请输入存单票面利率"/>
  </el-form-item>
</el-col>

If the row already has two columns, put this field in the same 抵质押信息 area and keep the existing 900px dialog.

  • Step 6: Add computed condition and validator

Add:

isCertificatePledge() {
  return this.form.guarType === '质押' && this.form.collType === '存单质押'
}

Add a validator in data():

const validateCouponRate = (rule, value, callback) => {
  if (this.isCertificatePledge && !value) {
    callback(new Error('存单票面利率不能为空'))
    return
  }
  callback()
}

Add rule:

couponRate: [
  {validator: validateCouponRate, trigger: "blur"}
]
  • Step 7: Add coupon-rate state cleanup

Add couponRate: undefined to form initial state and reset().

Add watcher:

'form.collType'() {
  this.resetCouponRateIfNotCertificatePledge()
}

Add method:

resetCouponRateIfNotCertificatePledge() {
  if (!this.isCertificatePledge) {
    this.form.couponRate = undefined
    this.$nextTick(() => {
      if (this.$refs.form) {
        this.$refs.form.clearValidate(['couponRate'])
      }
    })
  }
}

Call it at the end of resetCollateralFields().

  • Step 8: Add submit cleanup and front-end guard

In submitForm, before this.submitting = true, add:

if (this.isCertificatePledge && !this.form.couponRate) {
  this.$modal.msgWarning("存单票面利率不能为空")
  return
}

After collateral handling:

if (!this.isCertificatePledge) {
  delete data.couponRate
}
  • Step 9: Run personal static tests

Run:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run test:personal-create-input-params'

Expected: PASS. The shared test:business-type-history-rate is intentionally not run here because it also asserts corporate changes that are implemented in Task 3.

  • Step 10: Commit personal frontend changes
git add ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue \
  ruoyi-ui/tests/personal-create-input-params.test.js
git commit -m "调整上虞对私新增字段口径"

Task 3: Update Corporate Create Dialog

Files:

  • Modify: ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue

  • Modify: ruoyi-ui/tests/corporate-create-input-params.test.js

  • Modify: ruoyi-ui/tests/business-type-history-rate.test.js

  • Step 1: Change business type options

Use:

<el-option label="新增" value="新增"/>
<el-option label="存量新增" value="存量新增"/>
<el-option label="存量转贷" value="存量转贷"/>
  • Step 2: Update corporate collateral options

Change collateralTypeOptions() to:

collateralTypeOptions() {
  if (this.form.guarType === '抵押') {
    return ['一类', '二类', '三类', '四类', '排污权抵押', '设备等其他不动产抵押']
  }
  if (this.form.guarType === '质押') {
    return ['存单质押', '股权质押', '其他质押']
  }
  return []
}
  • Step 3: Add coupon-rate field and state

Mirror the personal dialog implementation:

<el-col :span="12" v-if="isCertificatePledge">
  <el-form-item label="存单票面利率" prop="couponRate">
    <el-input v-model="form.couponRate" placeholder="请输入存单票面利率"/>
  </el-form-item>
</el-col>

Add:

couponRate: undefined

to initial form and reset().

  • Step 4: Add computed condition, validator, watcher, and submit cleanup

Use the same names as personal dialog:

isCertificatePledge() {
  return this.form.guarType === '质押' && this.form.collType === '存单质押'
}

Use the same validateCouponRate, couponRate rule, form.collType watcher, resetCouponRateIfNotCertificatePledge, front-end guard, and:

if (!this.isCertificatePledge) {
  delete data.couponRate
}
  • Step 5: Run corporate static tests

Run:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run test:corporate-create-input-params && npm --prefix ruoyi-ui run test:business-type-history-rate'

Expected: PASS.

  • Step 6: Commit corporate frontend changes
git add ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue \
  ruoyi-ui/tests/corporate-create-input-params.test.js \
  ruoyi-ui/tests/business-type-history-rate.test.js
git commit -m "调整上虞对公新增字段口径"

Task 4: Frontend Build and Real Page Verification

Files:

  • Modify: doc/implementation-report-2026-05-11-shangyu-pricing-field-adjustment.md

  • Step 1: Run all related static tests

Run:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run test:business-type-history-rate && npm --prefix ruoyi-ui run test:personal-create-input-params && npm --prefix ruoyi-ui run test:corporate-create-input-params'

Expected: PASS.

  • Step 2: Run production build

Run:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run build:prod'

Expected: PASS and ruoyi-ui/dist generated.

  • Step 3: Start the local app stack

Use the repository's existing startup scripts if available. If a frontend dev server is needed, run it with Node controlled by nvm:

zsh -lic 'nvm use 14.21.3 >/dev/null && npm --prefix ruoyi-ui run dev'

Record the PID and URL. If the backend also needs restart, use the existing repository backend restart script rather than inventing a new start path.

  • Step 4: Use Playwright on the real page

Open the actual local workflow page, not a prototype. Verify:

  • Personal create dialog:

    • 业务种类 shows 新增/存量新增/存量转贷.
    • 新客 is absent.
    • 贷款用途 is absent.
    • 是否有经营佐证 is absent.
    • 抵押 shows 一线/一类/二类/三类.
    • 质押 + 存单质押 shows 存单票面利率.
    • Leaving 存单票面利率 empty blocks submit.
  • Corporate create dialog:

    • 业务种类 shows 新增/存量新增/存量转贷.
    • 抵押 shows 一类/二类/三类/四类/排污权抵押/设备等其他不动产抵押.
    • 质押 shows 存单质押/股权质押/其他质押.
    • 质押 + 存单质押 shows 存单票面利率.
    • Leaving 存单票面利率 empty blocks submit.
  • History-rate behavior:

    • 存量转贷 triggers historical-contract query.
    • 新增 and 存量新增 do not trigger historical-contract query.
  • Step 5: Stop test processes

Stop any frontend/backend processes started in this task. Verify with:

ps -ef | rg 'vue-cli-service|ruoyi-admin|RuoYiApplication'

Expected: no leftover processes from this test run.

  • Step 6: Update implementation record

Append:

## 前端实现

- 调整个人/企业新增弹窗业务种类选项为 `新增/存量新增/存量转贷`- 个人新增弹窗剔除 `loanPurpose``bizProof`- 按客户类型和担保方式调整抵质押类型选项。
- 新增 `质押 + 存单质押` 下的 `couponRate` 存单票面利率字段、必填校验和提交清理。

## 前端验证

- `npm --prefix ruoyi-ui run test:business-type-history-rate`
- `npm --prefix ruoyi-ui run test:personal-create-input-params`
- `npm --prefix ruoyi-ui run test:corporate-create-input-params`
- `npm --prefix ruoyi-ui run build:prod`
- Playwright 真实页面验证:通过
  • Step 7: Commit frontend verification record
git add doc/implementation-report-2026-05-11-shangyu-pricing-field-adjustment.md
git commit -m "记录上虞字段调整前端验证"