xsh_1997 пре 2 недеља
родитељ
комит
8c19d5604d

+ 40 - 20
doc/农资商城web/组织管理/商户管理/商户管理前端技术方案.md

@@ -65,8 +65,8 @@
65
 │   ├── 列:所属单位、类型、名称、联系人、手机、店铺数、认证状态、认证时间
65
 │   ├── 列:所属单位、类型、名称、联系人、手机、店铺数、认证状态、认证时间
66
 │   └── 操作:详情、编辑(canEdit)、删除(canDelete)
66
 │   └── 操作:详情、编辑(canEdit)、删除(canDelete)
67
 ├── 添加/编辑弹窗(860px · el-tabs)
67
 ├── 添加/编辑弹窗(860px · el-tabs)
68
-│   ├── Tab「主体资质」:个人 / 企业字段 + 证件照上传
69
-│   ├── Tab「商户经营信息」(仅编辑):名称、地址、联系人、结算等
68
+│   ├── Tab「主体资质」:个人 / 企业字段 + 证件照上传;企业注册地区 el-cascader
69
+│   ├── Tab「商户经营信息」(仅编辑):名称、经营地区 cascader、联系人、结算等
70
 │   └── Tab「绑定经营账号」(仅新增):管理员 / 会员远程搜索
70
 │   └── Tab「绑定经营账号」(仅新增):管理员 / 会员远程搜索
71
 └── 详情抽屉(detail.vue · 72% 宽)
71
 └── 详情抽屉(detail.vue · 72% 宽)
72
     ├── 概要、主体资质、经营信息、关联店铺
72
     ├── 概要、主体资质、经营信息、关联店铺
@@ -97,8 +97,19 @@
97
 | 场景 | 组件 | 提交拆分 |
97
 | 场景 | 组件 | 提交拆分 |
98
 |------|------|----------|
98
 |------|------|----------|
99
 | 个人证件有效期 | `el-date-picker type="daterange"` → `idValidRange` | `idValidStart` / `idValidEnd` |
99
 | 个人证件有效期 | `el-date-picker type="daterange"` → `idValidRange` | `idValidStart` / `idValidEnd` |
100
+| 法人证件有效期 | `el-date-picker type="daterange"` → `legalIdValidRange` | `legalIdValidStart` / `legalIdValidEnd` |
100
 | 企业营业期限 | `el-date-picker type="daterange"` → `licenseValidRange` | `licenseValidStart` / `licenseValidEnd` |
101
 | 企业营业期限 | `el-date-picker type="daterange"` → `licenseValidRange` | `licenseValidStart` / `licenseValidEnd` |
101
-| 长期有效 | `idValidType=2` / `licenseValidType=2`,仅填起始日 | `*ValidEnd` 可为 null |
102
+| 长期有效 | `idValidType=2` / `legalIdValidType=2` / `licenseValidType=2`,仅填起始日 | `*ValidEnd` 可为 null |
103
+
104
+**省市区级联(v1.7 · `el-cascader`):**
105
+
106
+| 场景 | 组件 | 数据源 | 落库字段 |
107
+|------|------|--------|----------|
108
+| 企业注册地址 | `form.regRegionCascader` | `getRegionTree()` | `regRegionCode`(区县 `code`)、`regRegionName`(省/市/区县 `/` 连接) |
109
+| 经营地址(编辑 Tab) | `form.bizRegionCascader` | 同上 | `bizRegionCode`、`bizRegionName` |
110
+| 详细地址 | `el-input` | — | `companyDetailAddress` / `bizDetailAddress` |
111
+
112
+级联配置:`value: code`、`label: name`、`children: children`、`emitPath: true`;支持 `filterable`、`clearable`。编辑回显按已存 `*RegionCode` 在树中查找路径;提交前剔除 `regRegionCascader` / `bizRegionCascader` 仅 UI 字段。
102
 
113
 
103
 ---
114
 ---
104
 
115
 
@@ -119,7 +130,17 @@
119
 | `adminUserOptions` | GET | `/adminUserOptions` | 新增绑定管理员远程搜索 |
130
 | `adminUserOptions` | GET | `/adminUserOptions` | 新增绑定管理员远程搜索 |
120
 | `memberOptions` | GET | `/memberOptions` | 新增绑定会员远程搜索 |
131
 | `memberOptions` | GET | `/memberOptions` | 新增绑定会员远程搜索 |
121
 
132
 
122
-### 6.1 列表请求参数
133
+### 6.1 省市区(v1.7)
134
+
135
+**基路径:** `/agri/region`(见 `src/api/agri/region.js`)
136
+
137
+| 前端方法 | HTTP | 路径 | 说明 |
138
+|----------|------|------|------|
139
+| `getRegionTree` | GET | `/tree` | 省/市/区县三级树;节点含 `id`、`pid`、`name`、`type`(1省/2市/3区县)、`code`、`children` |
140
+
141
+页面 `created` 预加载并缓存;添加/编辑弹窗打开时若未加载则再次请求。落库规则与后端 §9.9 一致:`code` 取选中区县,`name` 为路径名称用 `/` 拼接。
142
+
143
+### 6.2 列表请求参数
123
 
144
 
124
 | 字段 | 说明 |
145
 | 字段 | 说明 |
125
 |------|------|
146
 |------|------|
@@ -127,7 +148,7 @@
127
 | merchantName | 模糊(名称 / 所属单位) |
148
 | merchantName | 模糊(名称 / 所属单位) |
128
 | certStatus | `0` 正常 / `1` 冻结 / `2` 注销 |
149
 | certStatus | `0` 正常 / `1` 冻结 / `2` 注销 |
129
 
150
 
130
-### 6.2 列表行字段
151
+### 6.3 列表行字段
131
 
152
 
132
 | 字段 | 展示规则 |
153
 | 字段 | 展示规则 |
133
 |------|----------|
154
 |------|----------|
@@ -136,18 +157,18 @@
136
 | contactName, contactPhone | 未完善显示「—」 |
157
 | contactName, contactPhone | 未完善显示「—」 |
137
 | canEdit, canDelete | 后端布尔,控制按钮显隐 |
158
 | canEdit, canDelete | 后端布尔,控制按钮显隐 |
138
 
159
 
139
-### 6.3 新增请求体要点(v1.5 / v1.6)
160
+### 6.4 新增请求体要点(v1.5 / v1.6)
140
 
161
 
141
 - **仅** 主体资质 + `bindType`(`SYS_USER` / `MEMBER`)+ `bindUserId` 或 `bindMemberId`
162
 - **仅** 主体资质 + `bindType`(`SYS_USER` / `MEMBER`)+ `bindUserId` 或 `bindMemberId`
142
 - **不含** 经营信息字段
163
 - **不含** 经营信息字段
143
 - **平台新增最小必填**(`validateSubjectOnInsert`):
164
 - **平台新增最小必填**(`validateSubjectOnInsert`):
144
   - 个人:仅 `personName`
165
   - 个人:仅 `personName`
145
   - 企业:仅 `legalName` + `companyName`
166
   - 企业:仅 `legalName` + `companyName`
146
-- **v1.5 新增主体字段**:`idCardType` / `legalIdCardType`(1 大陆身份证 / 2 来往内地通行证)、`regRegionCode` / `regRegionName`、`corpBankAccount`、法人证件有效期区间等
167
+- **v1.5 新增主体字段**:`idCardType` / `legalIdCardType`(1 大陆身份证 / 2 来往内地通行证)、`regRegionCode` / `regRegionName`(v1.7 由级联写入)、`corpBankAccount`、法人证件有效期区间等
147
 - **会员绑定(v1.6)**:登录名=会员名称、管理员姓名=会员昵称;密码复制会员 `sys_user.password`;**不传** `sysUserInitPassword`
168
 - **会员绑定(v1.6)**:登录名=会员名称、管理员姓名=会员昵称;密码复制会员 `sys_user.password`;**不传** `sysUserInitPassword`
148
 - **管理员绑定(v1.6)**:检索范围 `role_key=merchant`;登录名=`user_name`、管理员姓名=`nick_name`
169
 - **管理员绑定(v1.6)**:检索范围 `role_key=merchant`;登录名=`user_name`、管理员姓名=`nick_name`
149
 
170
 
150
-### 6.3.1 绑定 Tab UI
171
+### 6.4.1 绑定 Tab UI
151
 
172
 
152
 | bindType | 远程搜索 | 下拉展示 |
173
 | bindType | 远程搜索 | 下拉展示 |
153
 |----------|----------|----------|
174
 |----------|----------|----------|
@@ -156,13 +177,13 @@
156
 
177
 
157
 顶部 `el-alert` 说明绑定落库规则;**已移除** 会员「初始密码」输入框。
178
 顶部 `el-alert` 说明绑定落库规则;**已移除** 会员「初始密码」输入框。
158
 
179
 
159
-### 6.4 编辑请求体要点
180
+### 6.5 编辑请求体要点
160
 
181
 
161
-- 含 `merchantId`、主体字段、经营信息字段
182
+- 含 `merchantId`、主体字段、经营信息字段;经营 Tab 含 `bizRegionCode` / `bizRegionName` / `bizDetailAddress`
162
 - **不传** `certStatus`(认证仅在详情改)
183
 - **不传** `certStatus`(认证仅在详情改)
163
 - 入驻后 `idCardNo`、`creditCode` 前端 disabled,仍随表单提交
184
 - 入驻后 `idCardNo`、`creditCode` 前端 disabled,仍随表单提交
164
 
185
 
165
-### 6.5 认证状态变更
186
+### 6.6 认证状态变更
166
 
187
 
167
 ```json
188
 ```json
168
 { "certStatus": "1", "confirm": true }
189
 { "certStatus": "1", "confirm": true }
@@ -170,7 +191,7 @@
170
 
191
 
171
 详情页先 `$modal.confirm(confirmMessage)`,再 `confirm: true` 提交。
192
 详情页先 `$modal.confirm(confirmMessage)`,再 `confirm: true` 提交。
172
 
193
 
173
-### 6.6 保存成功扩展
194
+### 6.7 保存成功扩展
174
 
195
 
175
 | response.data | 前端行为 |
196
 | response.data | 前端行为 |
176
 |---------------|----------|
197
 |---------------|----------|
@@ -188,6 +209,7 @@
188
 | 新增校验 | 个人仅姓名必填;企业仅法人姓名+企业名称必填;证件号/信用代码选填 |
209
 | 新增校验 | 个人仅姓名必填;企业仅法人姓名+企业名称必填;证件号/信用代码选填 |
189
 | 绑定搜索 | `el-select` + `remote` + `filterable`;keyword 空不请求 |
210
 | 绑定搜索 | `el-select` + `remote` + `filterable`;keyword 空不请求 |
190
 | 编辑 Tab | 「主体资质」+「商户经营信息」;无绑定 Tab |
211
 | 编辑 Tab | 「主体资质」+「商户经营信息」;无绑定 Tab |
212
+| 注册/经营地址 | 企业主体 Tab 选注册地区;编辑经营 Tab 选经营地区;均为 `el-cascader` + 详细地址输入 |
191
 | 详情跳转店铺 | `$router.push({ path: '/agri/org/shop', query: { merchantName } })` |
213
 | 详情跳转店铺 | `$router.push({ path: '/agri/org/shop', query: { merchantName } })` |
192
 | 删除 | 先 `deleteMerchantCheck`;`canDelete=false` 展示 reasons;通过后再二次确认 |
214
 | 删除 | 先 `deleteMerchantCheck`;`canDelete=false` 展示 reasons;通过后再二次确认 |
193
 | 列表名称 | `merchantName` 空显示「待完善」 |
215
 | 列表名称 | `merchantName` 空显示「待完善」 |
@@ -222,7 +244,7 @@ v-hasPermi="['agri:merchant:cert']"
222
 - [ ] 新增个人仅填姓名可提交;企业仅法人姓名+企业名称可提交  
244
 - [ ] 新增个人仅填姓名可提交;企业仅法人姓名+企业名称可提交  
223
 - [ ] 绑定会员无初始密码字段;admin/member 远程搜索展示正确  
245
 - [ ] 绑定会员无初始密码字段;admin/member 远程搜索展示正确  
224
 - [ ] 删除 deleteCheck 阻断并展示 reasons  
246
 - [ ] 删除 deleteCheck 阻断并展示 reasons  
225
-- [ ] 详情展示 idCardType、regRegion、corpBankAccount、法人完整字段  
247
+- [ ] 详情展示 idCardType、regRegion、bizRegion、corpBankAccount、法人完整字段  
226
 - [ ] 菜单组件路径 `agri/org/merchant/index` 可打开  
248
 - [ ] 菜单组件路径 `agri/org/merchant/index` 可打开  
227
 - [ ] 列表分页、检索、canEdit/canDelete 正确  
249
 - [ ] 列表分页、检索、canEdit/canDelete 正确  
228
 - [ ] 新增仅主体 + 绑定;成功后提示完善经营信息  
250
 - [ ] 新增仅主体 + 绑定;成功后提示完善经营信息  
@@ -230,8 +252,8 @@ v-hasPermi="['agri:merchant:cert']"
230
 - [ ] 详情 `allowedCertStatuses` 流转与二次确认  
252
 - [ ] 详情 `allowedCertStatuses` 流转与二次确认  
231
 - [ ] 证件号/信用代码编辑页 disabled  
253
 - [ ] 证件号/信用代码编辑页 disabled  
232
 - [ ] 删除前置条件后端 msg 正常弹出  
254
 - [ ] 删除前置条件后端 msg 正常弹出  
233
-- [ ] (可选)`GET /agri/region/tree` 返回三级树;编辑提交 `bizRegionCode`/`bizRegionName` 与 §9.9 一致  
234
-- [ ] 编辑页 **经营地址**、企业 **注册地址** 级联选择器可选省/市/区县并正确落库  
255
+- [ ] `GET /agri/region/tree` 返回三级树;级联选中后 `regRegionCode`/`regRegionName`、`bizRegionCode`/`bizRegionName` 与后端 §9.9 一致  
256
+- [ ] 编辑回显:已存区县 code 能正确还原级联路径  
235
 
257
 
236
 ---
258
 ---
237
 
259
 
@@ -248,14 +270,12 @@ v-hasPermi="['agri:merchant:cert']"
248
 
270
 
249
 | 版本 | 日期 | 说明 |
271
 | 版本 | 日期 | 说明 |
250
 |------|------|------|
272
 |------|------|------|
251
-
252
-| v1.3 | 2026-05 | 商户编辑页接入 `el-cascader` 选择注册/经营省市区 |
253
-| v1.2 | 2026-05 | 对齐 v1.7:省市区接口 `/agri/region/tree` |
254
-
273
+| v1.3 | 2026-06 | 接入 `GET /agri/region/tree`;企业注册地址、经营地址改为 `el-cascader`;新增 `api/agri/region.js` |
274
+| v1.2 | 2026-05 | 对齐 v1.6:绑定 Tab、主体扩展字段、deleteCheck |
255
 | v1.1 | 2026-05 | 对齐 v1.6:角色 merchant/member;会员绑定不传初始密码 |
275
 | v1.1 | 2026-05 | 对齐 v1.6:角色 merchant/member;会员绑定不传初始密码 |
256
 | v1.0 | 2026-05 | 首版:列表 CRUD、详情抽屉、绑定远程搜索 |
276
 | v1.0 | 2026-05 | 首版:列表 CRUD、详情抽屉、绑定远程搜索 |
257
 
277
 
258
 ---
278
 ---
259
 
279
 
260
-*文档版本:v1.3 · ruoyi-ui · 关联《商户管理功能需求.md》v1.7*
280
+*文档版本:v1.3 · ruoyi-ui · 关联《商户管理功能需求.md》v1.7 / 《商户管理技术方案.md》v1.7*
261
 
281
 

+ 9 - 0
ruoyi-ui/src/api/agri/region.js

@@ -0,0 +1,9 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询省市区三级树(平台端)
4
+export function getRegionTree() {
5
+  return request({
6
+    url: '/agri/region/tree',
7
+    method: 'get'
8
+  })
9
+}

+ 3 - 3
ruoyi-ui/src/views/agri/org/merchant/detail.vue

@@ -76,8 +76,7 @@
76
           <el-descriptions-item label="统一社会信用代码">{{ detail.creditCode || '—' }}</el-descriptions-item>
76
           <el-descriptions-item label="统一社会信用代码">{{ detail.creditCode || '—' }}</el-descriptions-item>
77
           <el-descriptions-item label="注册地区">{{ detail.regRegionName || '—' }}</el-descriptions-item>
77
           <el-descriptions-item label="注册地区">{{ detail.regRegionName || '—' }}</el-descriptions-item>
78
           <el-descriptions-item label="注册地区编码">{{ detail.regRegionCode || '—' }}</el-descriptions-item>
78
           <el-descriptions-item label="注册地区编码">{{ detail.regRegionCode || '—' }}</el-descriptions-item>
79
-          <el-descriptions-item label="注册地址">{{ detail.regAddress || '—' }}</el-descriptions-item>
80
-          <el-descriptions-item label="详细地址">{{ detail.companyDetailAddress || '—' }}</el-descriptions-item>
79
+          <el-descriptions-item label="注册详细地址">{{ detail.companyDetailAddress || '—' }}</el-descriptions-item>
81
           <el-descriptions-item label="经营范围" :span="2">{{ detail.businessScope || '—' }}</el-descriptions-item>
80
           <el-descriptions-item label="经营范围" :span="2">{{ detail.businessScope || '—' }}</el-descriptions-item>
82
           <el-descriptions-item label="营业期限" :span="2">{{ validPeriodText(detail.licenseValidType, detail.licenseValidStart, detail.licenseValidEnd) }}</el-descriptions-item>
81
           <el-descriptions-item label="营业期限" :span="2">{{ validPeriodText(detail.licenseValidType, detail.licenseValidStart, detail.licenseValidEnd) }}</el-descriptions-item>
83
         </el-descriptions>
82
         </el-descriptions>
@@ -89,7 +88,8 @@
89
         <el-descriptions-item label="商户名称">{{ detail.merchantName || '—' }}</el-descriptions-item>
88
         <el-descriptions-item label="商户名称">{{ detail.merchantName || '—' }}</el-descriptions-item>
90
         <el-descriptions-item label="客服电话">{{ detail.servicePhone || '—' }}</el-descriptions-item>
89
         <el-descriptions-item label="客服电话">{{ detail.servicePhone || '—' }}</el-descriptions-item>
91
         <el-descriptions-item label="经营地址">{{ detail.bizRegionName || '—' }}</el-descriptions-item>
90
         <el-descriptions-item label="经营地址">{{ detail.bizRegionName || '—' }}</el-descriptions-item>
92
-        <el-descriptions-item label="详细地址">{{ detail.bizDetailAddress || '—' }}</el-descriptions-item>
91
+        <el-descriptions-item label="经营地区编码">{{ detail.bizRegionCode || '—' }}</el-descriptions-item>
92
+        <el-descriptions-item label="经营详细地址" :span="2">{{ detail.bizDetailAddress || '—' }}</el-descriptions-item>
93
         <el-descriptions-item label="联系人">{{ detail.contactName || '—' }}</el-descriptions-item>
93
         <el-descriptions-item label="联系人">{{ detail.contactName || '—' }}</el-descriptions-item>
94
         <el-descriptions-item label="联系人手机">{{ detail.contactPhone || '—' }}</el-descriptions-item>
94
         <el-descriptions-item label="联系人手机">{{ detail.contactPhone || '—' }}</el-descriptions-item>
95
         <el-descriptions-item label="联系人邮箱">{{ detail.contactEmail || '—' }}</el-descriptions-item>
95
         <el-descriptions-item label="联系人邮箱">{{ detail.contactEmail || '—' }}</el-descriptions-item>

+ 131 - 12
ruoyi-ui/src/views/agri/org/merchant/index.vue

@@ -20,6 +20,8 @@
20
       </el-form>
20
       </el-form>
21
     </el-card>
21
     </el-card>
22
 
22
 
23
+    <br/>
24
+
23
     <!-- 列表区 -->
25
     <!-- 列表区 -->
24
     <el-card shadow="never" class="table-card">
26
     <el-card shadow="never" class="table-card">
25
       <el-row :gutter="10" class="mb8">
27
       <el-row :gutter="10" class="mb8">
@@ -207,10 +209,21 @@
207
                     <el-input v-model="form.creditCode" maxlength="18" :disabled="!!form.merchantId" placeholder="选填" />
209
                     <el-input v-model="form.creditCode" maxlength="18" :disabled="!!form.merchantId" placeholder="选填" />
208
                   </el-form-item>
210
                   </el-form-item>
209
                 </el-col>
211
                 </el-col>
210
-                <el-col :span="12"><el-form-item label="注册地区编码" prop="regRegionCode"><el-input v-model="form.regRegionCode" placeholder="如 110105" maxlength="64" /></el-form-item></el-col>
211
-                <el-col :span="12"><el-form-item label="注册地区名称" prop="regRegionName"><el-input v-model="form.regRegionName" placeholder="如 北京市/西城区" maxlength="128" /></el-form-item></el-col>
212
-                <el-col :span="12"><el-form-item label="注册地址" prop="regAddress"><el-input v-model="form.regAddress" maxlength="255" placeholder="选填" /></el-form-item></el-col>
213
-                <el-col :span="12"><el-form-item label="详细地址" prop="companyDetailAddress"><el-input v-model="form.companyDetailAddress" maxlength="255" /></el-form-item></el-col>
212
+                <el-col :span="24">
213
+                  <el-form-item label="注册地区" prop="regRegionCascader">
214
+                    <el-cascader
215
+                      v-model="form.regRegionCascader"
216
+                      :options="regionTree"
217
+                      :props="regionCascaderProps"
218
+                      clearable
219
+                      filterable
220
+                      placeholder="请选择省/市/区县"
221
+                      style="width: 100%"
222
+                      @change="handleRegRegionChange"
223
+                    />
224
+                  </el-form-item>
225
+                </el-col>
226
+                <el-col :span="24"><el-form-item label="注册详细地址" prop="companyDetailAddress"><el-input v-model="form.companyDetailAddress" maxlength="255" placeholder="选填,街道门牌号" /></el-form-item></el-col>
214
                 <el-col :span="24"><el-form-item label="经营范围" prop="businessScope"><el-input v-model="form.businessScope" type="textarea" :rows="2" maxlength="1000" /></el-form-item></el-col>
227
                 <el-col :span="24"><el-form-item label="经营范围" prop="businessScope"><el-input v-model="form.businessScope" type="textarea" :rows="2" maxlength="1000" /></el-form-item></el-col>
215
                 <el-col :span="24">
228
                 <el-col :span="24">
216
                   <el-form-item label="营业期限" prop="licenseValidType">
229
                   <el-form-item label="营业期限" prop="licenseValidType">
@@ -239,8 +252,20 @@
239
             <el-row :gutter="16">
252
             <el-row :gutter="16">
240
               <el-col :span="12"><el-form-item label="商户名称" prop="merchantName"><el-input v-model="form.merchantName" maxlength="128" /></el-form-item></el-col>
253
               <el-col :span="12"><el-form-item label="商户名称" prop="merchantName"><el-input v-model="form.merchantName" maxlength="128" /></el-form-item></el-col>
241
               <el-col :span="12"><el-form-item label="客服电话" prop="servicePhone"><el-input v-model="form.servicePhone" maxlength="20" /></el-form-item></el-col>
254
               <el-col :span="12"><el-form-item label="客服电话" prop="servicePhone"><el-input v-model="form.servicePhone" maxlength="20" /></el-form-item></el-col>
242
-              <el-col :span="12"><el-form-item label="经营地区编码" prop="bizRegionCode"><el-input v-model="form.bizRegionCode" placeholder="如 110105" maxlength="64" /></el-form-item></el-col>
243
-              <el-col :span="12"><el-form-item label="经营地区名称" prop="bizRegionName"><el-input v-model="form.bizRegionName" placeholder="如 北京市/朝阳区" maxlength="128" /></el-form-item></el-col>
255
+              <el-col :span="24">
256
+                <el-form-item label="经营地区" prop="bizRegionCascader">
257
+                  <el-cascader
258
+                    v-model="form.bizRegionCascader"
259
+                    :options="regionTree"
260
+                    :props="regionCascaderProps"
261
+                    clearable
262
+                    filterable
263
+                    placeholder="请选择省/市/区县"
264
+                    style="width: 100%"
265
+                    @change="handleBizRegionChange"
266
+                  />
267
+                </el-form-item>
268
+              </el-col>
244
               <el-col :span="24"><el-form-item label="经营详细地址" prop="bizDetailAddress"><el-input v-model="form.bizDetailAddress" maxlength="255" /></el-form-item></el-col>
269
               <el-col :span="24"><el-form-item label="经营详细地址" prop="bizDetailAddress"><el-input v-model="form.bizDetailAddress" maxlength="255" /></el-form-item></el-col>
245
               <el-col :span="12"><el-form-item label="联系人姓名" prop="contactName"><el-input v-model="form.contactName" maxlength="64" /></el-form-item></el-col>
270
               <el-col :span="12"><el-form-item label="联系人姓名" prop="contactName"><el-input v-model="form.contactName" maxlength="64" /></el-form-item></el-col>
246
               <el-col :span="12"><el-form-item label="联系人手机" prop="contactPhone"><el-input v-model="form.contactPhone" maxlength="20" /></el-form-item></el-col>
271
               <el-col :span="12"><el-form-item label="联系人手机" prop="contactPhone"><el-input v-model="form.contactPhone" maxlength="20" /></el-form-item></el-col>
@@ -311,6 +336,7 @@
311
 
336
 
312
 <script>
337
 <script>
313
 import { listMerchant, getMerchant, addMerchant, updateMerchant, delMerchant, deleteMerchantCheck, adminUserOptions, memberOptions } from "@/api/agri/merchant"
338
 import { listMerchant, getMerchant, addMerchant, updateMerchant, delMerchant, deleteMerchantCheck, adminUserOptions, memberOptions } from "@/api/agri/merchant"
339
+import { getRegionTree } from "@/api/agri/region"
314
 import MerchantDetail from "./detail"
340
 import MerchantDetail from "./detail"
315
 
341
 
316
 export default {
342
 export default {
@@ -330,6 +356,14 @@ export default {
330
       bindSearchLoading: false,
356
       bindSearchLoading: false,
331
       adminUserList: [],
357
       adminUserList: [],
332
       memberList: [],
358
       memberList: [],
359
+      regionTree: [],
360
+      regionTreeLoaded: false,
361
+      regionCascaderProps: {
362
+        value: "code",
363
+        label: "name",
364
+        children: "children",
365
+        emitPath: true
366
+      },
333
       queryParams: {
367
       queryParams: {
334
         pageNum: 1,
368
         pageNum: 1,
335
         pageSize: 10,
369
         pageSize: 10,
@@ -365,6 +399,7 @@ export default {
365
   },
399
   },
366
   created() {
400
   created() {
367
     this.getList()
401
     this.getList()
402
+    this.loadRegionTree()
368
   },
403
   },
369
   methods: {
404
   methods: {
370
     /** 查询商户列表 */
405
     /** 查询商户列表 */
@@ -421,6 +456,7 @@ export default {
421
         creditCode: undefined,
456
         creditCode: undefined,
422
         regRegionCode: undefined,
457
         regRegionCode: undefined,
423
         regRegionName: undefined,
458
         regRegionName: undefined,
459
+        regRegionCascader: [],
424
         regAddress: undefined,
460
         regAddress: undefined,
425
         companyDetailAddress: undefined,
461
         companyDetailAddress: undefined,
426
         businessScope: undefined,
462
         businessScope: undefined,
@@ -430,7 +466,8 @@ export default {
430
         licenseValidEnd: undefined,
466
         licenseValidEnd: undefined,
431
         bindType: "SYS_USER",
467
         bindType: "SYS_USER",
432
         bindUserId: undefined,
468
         bindUserId: undefined,
433
-        bindMemberId: undefined
469
+        bindMemberId: undefined,
470
+        bizRegionCascader: []
434
       }
471
       }
435
       this.activeTab = "subject"
472
       this.activeTab = "subject"
436
       this.adminUserList = []
473
       this.adminUserList = []
@@ -451,15 +488,18 @@ export default {
451
     },
488
     },
452
     handleAdd() {
489
     handleAdd() {
453
       this.reset()
490
       this.reset()
491
+      this.loadRegionTree()
454
       this.open = true
492
       this.open = true
455
       this.title = "添加商户"
493
       this.title = "添加商户"
456
     },
494
     },
457
-    /** 打开编辑并组装日期区间 */
495
+    /** 打开编辑并组装日期区间、省市区回显 */
458
     handleUpdate(row) {
496
     handleUpdate(row) {
459
       this.reset()
497
       this.reset()
460
-      getMerchant(row.merchantId).then(response => {
498
+      this.loadRegionTree().then(() => {
499
+        return getMerchant(row.merchantId)
500
+      }).then(response => {
461
         const data = response.data || {}
501
         const data = response.data || {}
462
-        this.form = { ...data }
502
+        this.form = { ...data, regRegionCascader: [], bizRegionCascader: [] }
463
         if (data.idValidType === "1" && data.idValidStart && data.idValidEnd) {
503
         if (data.idValidType === "1" && data.idValidStart && data.idValidEnd) {
464
           this.form.idValidRange = [data.idValidStart, data.idValidEnd]
504
           this.form.idValidRange = [data.idValidStart, data.idValidEnd]
465
         }
505
         }
@@ -469,6 +509,7 @@ export default {
469
         if (data.licenseValidType === "1" && data.licenseValidStart && data.licenseValidEnd) {
509
         if (data.licenseValidType === "1" && data.licenseValidStart && data.licenseValidEnd) {
470
           this.form.licenseValidRange = [data.licenseValidStart, data.licenseValidEnd]
510
           this.form.licenseValidRange = [data.licenseValidStart, data.licenseValidEnd]
471
         }
511
         }
512
+        this.syncRegionCascaderFromForm()
472
         this.activeTab = "subject"
513
         this.activeTab = "subject"
473
         this.open = true
514
         this.open = true
474
         this.title = "编辑商户"
515
         this.title = "编辑商户"
@@ -487,7 +528,83 @@ export default {
487
       this.adminUserList = []
528
       this.adminUserList = []
488
       this.memberList = []
529
       this.memberList = []
489
     },
530
     },
490
-    /** 管理员下拉展示:昵称 / 用户名 / 手机号 */
531
+    /** 加载省市区树 */
532
+    loadRegionTree() {
533
+      if (this.regionTreeLoaded) {
534
+        return Promise.resolve()
535
+      }
536
+      return getRegionTree().then(response => {
537
+        this.regionTree = response.data || []
538
+        this.regionTreeLoaded = true
539
+      }).catch(() => {
540
+        this.regionTree = []
541
+      })
542
+    },
543
+    /** 根据区县 code 回显级联选中路径 */
544
+    findRegionPath(nodes, targetCode, path) {
545
+      if (!nodes || !nodes.length) {
546
+        return null
547
+      }
548
+      for (let i = 0; i < nodes.length; i++) {
549
+        const node = nodes[i]
550
+        const nextPath = (path || []).concat(node.code)
551
+        if (String(node.code) === String(targetCode)) {
552
+          return nextPath
553
+        }
554
+        if (node.children && node.children.length) {
555
+          const found = this.findRegionPath(node.children, targetCode, nextPath)
556
+          if (found) {
557
+            return found
558
+          }
559
+        }
560
+      }
561
+      return null
562
+    },
563
+    /** 根据级联 code 路径拼地区名称 */
564
+    getRegionNamesByCodes(codes) {
565
+      const names = []
566
+      let nodes = this.regionTree
567
+      for (let i = 0; i < codes.length; i++) {
568
+        const code = codes[i]
569
+        const node = (nodes || []).find(item => String(item.code) === String(code))
570
+        if (!node) {
571
+          break
572
+        }
573
+        names.push(node.name)
574
+        nodes = node.children || []
575
+      }
576
+      return names
577
+    },
578
+    /** 编辑回显:把库里的 code 转成 cascader 路径 */
579
+    syncRegionCascaderFromForm() {
580
+      if (this.form.regRegionCode && this.regionTree.length) {
581
+        this.form.regRegionCascader = this.findRegionPath(this.regionTree, this.form.regRegionCode) || []
582
+      }
583
+      if (this.form.bizRegionCode && this.regionTree.length) {
584
+        this.form.bizRegionCascader = this.findRegionPath(this.regionTree, this.form.bizRegionCode) || []
585
+      }
586
+    },
587
+    /** 企业注册地区变更:写入 regRegionCode / regRegionName */
588
+    handleRegRegionChange(codes) {
589
+      this.applyRegionSelection(codes, "reg")
590
+    },
591
+    /** 经营地区变更:写入 bizRegionCode / bizRegionName */
592
+    handleBizRegionChange(codes) {
593
+      this.applyRegionSelection(codes, "biz")
594
+    },
595
+    /** 级联选择落库:code=区县 code,name=省/市/区县用 / 连接 */
596
+    applyRegionSelection(codes, prefix) {
597
+      const codeKey = prefix + "RegionCode"
598
+      const nameKey = prefix + "RegionName"
599
+      if (!codes || !codes.length) {
600
+        this.form[codeKey] = undefined
601
+        this.form[nameKey] = undefined
602
+        return
603
+      }
604
+      const names = this.getRegionNamesByCodes(codes)
605
+      this.form[codeKey] = String(codes[codes.length - 1])
606
+      this.form[nameKey] = names.join("/")
607
+    },
491
     formatAdminOption(item) {
608
     formatAdminOption(item) {
492
       const parts = [item.nickName || item.userName, item.userName]
609
       const parts = [item.nickName || item.userName, item.userName]
493
       if (item.phonenumber) {
610
       if (item.phonenumber) {
@@ -549,6 +666,8 @@ export default {
549
       delete payload.idValidRange
666
       delete payload.idValidRange
550
       delete payload.legalIdValidRange
667
       delete payload.legalIdValidRange
551
       delete payload.licenseValidRange
668
       delete payload.licenseValidRange
669
+      delete payload.regRegionCascader
670
+      delete payload.bizRegionCascader
552
       // 新增时不传绑定无关字段;会员绑定不传 sysUserInitPassword(后端忽略)
671
       // 新增时不传绑定无关字段;会员绑定不传 sysUserInitPassword(后端忽略)
553
       if (!payload.merchantId) {
672
       if (!payload.merchantId) {
554
         delete payload.sysUserInitPassword
673
         delete payload.sysUserInitPassword
@@ -612,7 +731,7 @@ export default {
612
 
731
 
613
 <style scoped>
732
 <style scoped>
614
 .search-card {
733
 .search-card {
615
-  margin-bottom: 10px;
734
+  margin-bottom: 0;
616
 }
735
 }
617
 .form-section-title {
736
 .form-section-title {
618
   font-size: 13px;
737
   font-size: 13px;