1
This commit is contained in:
227
doc/子账号功能更新说明.md
Normal file
227
doc/子账号功能更新说明.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# 批量发品-子账号功能更新说明
|
||||
|
||||
## 更新时间
|
||||
2025-01-10 (最后更新:2025-01-10 18:30)
|
||||
|
||||
## 功能描述
|
||||
在批量发品功能中新增子账号选择功能。支持**同时选择多个主账号**,每个主账号可以**多选子账号**。系统会为每个商品×每个主账号×每个子账号创建发品任务。
|
||||
|
||||
## 前端修改
|
||||
|
||||
### 1. `ruoyi-vue/src/views/jarvis/batchPublish/index.vue`
|
||||
|
||||
#### 界面改动
|
||||
- 将"目标账号"改为复选框(Checkbox),支持**同时选择多个主账号**
|
||||
- 每个选中的主账号下方自动展开对应的**子账号多选下拉框**
|
||||
- 子账号在首次展开或点击下拉框时自动加载
|
||||
- 支持为不同主账号选择不同的子账号组合
|
||||
- 添加加载状态提示和友好的错误提示
|
||||
|
||||
#### 数据改动
|
||||
```javascript
|
||||
// 修改后的数据结构
|
||||
publishForm: {
|
||||
selectedMainAccounts: [], // 选中的主账号列表 ['appid1', 'appid2']
|
||||
accountSubAccounts: { // 每个主账号对应的子账号
|
||||
'appid1': ['子账号1', '子账号2'],
|
||||
'appid2': ['子账号3']
|
||||
}
|
||||
}
|
||||
|
||||
// 子账号数据
|
||||
subAccountsMap: { // 每个主账号对应的子账号选项列表
|
||||
'appid1': [{value, label}],
|
||||
'appid2': [{value, label}]
|
||||
}
|
||||
loadingSubAccounts: { // 每个主账号的加载状态
|
||||
'appid1': false,
|
||||
'appid2': true
|
||||
}
|
||||
```
|
||||
|
||||
#### 新增/修改方法
|
||||
- `onMainAccountsChange(selectedAccounts)`: 主账号变化时触发,清理未选中账号的数据,为新选中账号初始化数据结构
|
||||
- `loadSubAccountsForAccount(appid)`: 为指定主账号加载子账号列表(带防重复加载逻辑)
|
||||
|
||||
## 后端修改
|
||||
|
||||
### 1. `BatchPublishRequest.java`
|
||||
```java
|
||||
// 新增内部类
|
||||
public static class AccountConfig {
|
||||
private String targetAccount; // 目标ERP账号(appid)
|
||||
private List<String> subAccounts; // 该账号下的子账号列表
|
||||
}
|
||||
|
||||
// 修改后的字段
|
||||
private List<AccountConfig> accountConfigs; // 账号配置列表(多个主账号+子账号)
|
||||
```
|
||||
|
||||
数据结构示例:
|
||||
```json
|
||||
{
|
||||
"accountConfigs": [
|
||||
{
|
||||
"targetAccount": "appid1",
|
||||
"subAccounts": ["子账号1", "子账号2"]
|
||||
},
|
||||
{
|
||||
"targetAccount": "appid2",
|
||||
"subAccounts": ["子账号3"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `BatchPublishItem.java`
|
||||
新增字段:
|
||||
```java
|
||||
private String subAccount; // 子账号(会员名)
|
||||
```
|
||||
|
||||
### 3. `BatchPublishServiceImpl.java`
|
||||
#### batchPublish方法
|
||||
- 修改任务创建逻辑,支持多主账号配置
|
||||
- 为**每个商品 × 每个主账号 × 每个子账号**创建一条发品记录
|
||||
- 保存完整的账号配置信息到任务记录中
|
||||
|
||||
**处理逻辑:**
|
||||
```java
|
||||
for (ProductItem product : products) {
|
||||
for (AccountConfig config : accountConfigs) {
|
||||
String appid = config.getTargetAccount();
|
||||
for (String subAccount : config.getSubAccounts()) {
|
||||
// 创建一条发品记录
|
||||
// 记录包含:商品信息 + 主账号(appid) + 子账号(会员名)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**示例:**
|
||||
- 2个商品 × 2个主账号 × (每个主账号2个子账号) = 8条发品记录
|
||||
|
||||
#### publishProduct方法
|
||||
- 使用`item.getSubAccount()`作为会员名进行发品
|
||||
- 如果子账号为空,则使用通用参数中的会员名作为备选
|
||||
|
||||
### 4. `BatchPublishItemMapper.xml`
|
||||
#### 修改内容
|
||||
- `resultMap`中添加`sub_account`字段映射
|
||||
- `selectBatchPublishItemVo` SQL中添加`sub_account`字段
|
||||
- `insertBatchPublishItem`中添加`sub_account`字段
|
||||
- `batchInsertBatchPublishItem`批量插入中添加`sub_account`字段
|
||||
|
||||
## 数据库修改
|
||||
|
||||
### SQL迁移脚本
|
||||
文件:`sql/add_sub_account_column.sql`
|
||||
|
||||
```sql
|
||||
ALTER TABLE batch_publish_item
|
||||
ADD COLUMN sub_account VARCHAR(100) COMMENT '子账号(会员名)' AFTER account_remark;
|
||||
```
|
||||
|
||||
## 使用流程
|
||||
|
||||
### 用户操作流程
|
||||
1. 选择线报消息并解析商品
|
||||
2. 选择要发品的商品
|
||||
3. **勾选一个或多个主账号**(支持多选)
|
||||
4. 系统自动为每个选中的主账号展开子账号下拉框
|
||||
5. 在每个主账号下**选择一个或多个子账号**(支持多选)
|
||||
6. 填写其他通用参数
|
||||
7. 提交批量发品
|
||||
|
||||
**界面示例:**
|
||||
```
|
||||
☑ 海尔胡歌
|
||||
↓ [子账号1, 子账号2, 子账号3] (多选下拉框)
|
||||
|
||||
☑ 方案小号
|
||||
↓ [子账号A, 子账号B] (多选下拉框)
|
||||
|
||||
☐ 其他账号
|
||||
```
|
||||
|
||||
### 数据流转
|
||||
1. 前端提交数据包含:
|
||||
```javascript
|
||||
{
|
||||
accountConfigs: [
|
||||
{ targetAccount: 'appid1', subAccounts: ['子账号1', '子账号2'] },
|
||||
{ targetAccount: 'appid2', subAccounts: ['子账号A'] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
2. 后端处理逻辑:
|
||||
- 对于每个商品 × 每个主账号配置 × 每个子账号,创建一条发品记录
|
||||
- 每条记录包含:`targetAccount`(appid)和 `subAccount`(会员名)
|
||||
|
||||
3. 发品时:
|
||||
- 使用`targetAccount`确定ERP账号(API密钥)
|
||||
- 使用`subAccount`作为发品时的会员名
|
||||
|
||||
**发品数量计算:**
|
||||
- 假设选择:2个商品、2个主账号(每个主账号选2个子账号)
|
||||
- 生成发品任务数:2 × 2 × 2 = **8条发品记录**
|
||||
|
||||
## 兼容性说明
|
||||
|
||||
### 向后兼容
|
||||
- 如果`subAccount`字段为空,系统会使用通用参数中的`userName`作为备选
|
||||
- 旧的发品记录不受影响,可以正常查询和显示
|
||||
|
||||
## 部署步骤
|
||||
|
||||
1. 执行数据库迁移脚本:
|
||||
```sql
|
||||
source sql/add_sub_account_column.sql
|
||||
```
|
||||
|
||||
2. 重新编译并部署后端服务:
|
||||
```bash
|
||||
cd ruoyi-java
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
3. 部署前端:
|
||||
```bash
|
||||
cd ruoyi-vue
|
||||
npm run build
|
||||
```
|
||||
|
||||
4. 重启服务
|
||||
|
||||
## 测试要点
|
||||
|
||||
### 基础功能测试
|
||||
1. **主账号多选**:勾选多个主账号,确认每个账号下都展开了子账号选择框
|
||||
2. **子账号加载**:确认每个主账号的子账号列表正确加载,且互不干扰
|
||||
3. **取消主账号**:取消勾选主账号时,对应的子账号数据被清理
|
||||
4. **子账号多选**:每个主账号下可以独立选择多个子账号
|
||||
|
||||
### 数据验证测试
|
||||
5. **必填验证**:未选择主账号时提示"请至少选择一个主账号"
|
||||
6. **子账号验证**:选中主账号但未选子账号时,提示"请为账号XXX选择至少一个子账号"
|
||||
7. **发品记录数量**:验证创建的发品记录数 = 商品数 × Σ(每个主账号的子账号数)
|
||||
|
||||
### 业务功能测试
|
||||
8. **任务创建**:提交后正确创建任务,任务记录中保存完整的账号配置信息
|
||||
9. **发品明细**:查看发品明细时,主账号和子账号信息都正确显示
|
||||
10. **实际发品**:验证发品时使用了正确的主账号(API密钥)和子账号(会员名)
|
||||
|
||||
### 边界情况测试
|
||||
11. **单主账号单子账号**:退化到最简单情况是否正常
|
||||
12. **多主账号多子账号**:同时选择所有主账号,每个主账号选择多个子账号
|
||||
13. **子账号为空**:某个主账号下没有子账号时的提示是否友好
|
||||
14. **网络异常**:加载子账号失败时是否有正确的错误提示
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 子账号列表通过调用`/erp/product/usernames`接口获取
|
||||
2. 该接口需要传递`appid`参数,即主账号的API Key
|
||||
3. 确保ERP账号已正确授权,否则可能无法获取子账号列表
|
||||
4. 建议在生产环境部署前,先在测试环境完整测试一遍流程
|
||||
|
||||
@@ -40,6 +40,10 @@ public class BatchPublishItem extends BaseEntity
|
||||
@Excel(name = "账号名称")
|
||||
private String accountRemark;
|
||||
|
||||
/** 子账号(会员名) */
|
||||
@Excel(name = "子账号")
|
||||
private String subAccount;
|
||||
|
||||
/** 发品状态:0待发布 1发布中 2发布成功 3发布失败 4上架中 5已上架 6上架失败 */
|
||||
@Excel(name = "发品状态", readConverterExp = "0=待发布,1=发布中,2=发布成功,3=发布失败,4=上架中,5=已上架,6=上架失败")
|
||||
private Integer status;
|
||||
@@ -118,6 +122,14 @@ public class BatchPublishItem extends BaseEntity
|
||||
this.accountRemark = accountRemark;
|
||||
}
|
||||
|
||||
public String getSubAccount() {
|
||||
return subAccount;
|
||||
}
|
||||
|
||||
public void setSubAccount(String subAccount) {
|
||||
this.subAccount = subAccount;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
@@ -191,6 +203,7 @@ public class BatchPublishItem extends BaseEntity
|
||||
.append("productName", getProductName())
|
||||
.append("targetAccount", getTargetAccount())
|
||||
.append("accountRemark", getAccountRemark())
|
||||
.append("subAccount", getSubAccount())
|
||||
.append("status", getStatus())
|
||||
.append("productId", getProductId())
|
||||
.append("productStatus", getProductStatus())
|
||||
|
||||
@@ -23,9 +23,9 @@ public class BatchPublishRequest {
|
||||
@NotEmpty(message = "商品列表不能为空")
|
||||
private List<ProductItem> products;
|
||||
|
||||
/** 目标ERP账号列表 */
|
||||
@NotEmpty(message = "目标账号不能为空")
|
||||
private List<String> targetAccounts;
|
||||
/** 账号配置列表(包含多个主账号及其子账号) */
|
||||
@NotEmpty(message = "账号配置不能为空")
|
||||
private List<AccountConfig> accountConfigs;
|
||||
|
||||
/** 通用参数 */
|
||||
@NotNull(message = "通用参数不能为空")
|
||||
@@ -34,6 +34,35 @@ public class BatchPublishRequest {
|
||||
/** 延迟上架时间(秒),默认3秒 */
|
||||
private Integer delaySeconds = 3;
|
||||
|
||||
/**
|
||||
* 账号配置(主账号+子账号列表)
|
||||
*/
|
||||
public static class AccountConfig {
|
||||
/** 目标ERP账号(appid) */
|
||||
@NotBlank(message = "目标账号不能为空")
|
||||
private String targetAccount;
|
||||
|
||||
/** 该账号下的子账号列表 */
|
||||
@NotEmpty(message = "子账号不能为空")
|
||||
private List<String> subAccounts;
|
||||
|
||||
public String getTargetAccount() {
|
||||
return targetAccount;
|
||||
}
|
||||
|
||||
public void setTargetAccount(String targetAccount) {
|
||||
this.targetAccount = targetAccount;
|
||||
}
|
||||
|
||||
public List<String> getSubAccounts() {
|
||||
return subAccounts;
|
||||
}
|
||||
|
||||
public void setSubAccounts(List<String> subAccounts) {
|
||||
this.subAccounts = subAccounts;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProductItem {
|
||||
/** SKUID */
|
||||
@NotBlank(message = "SKUID不能为空")
|
||||
@@ -292,12 +321,12 @@ public class BatchPublishRequest {
|
||||
this.products = products;
|
||||
}
|
||||
|
||||
public List<String> getTargetAccounts() {
|
||||
return targetAccounts;
|
||||
public List<AccountConfig> getAccountConfigs() {
|
||||
return accountConfigs;
|
||||
}
|
||||
|
||||
public void setTargetAccounts(List<String> targetAccounts) {
|
||||
this.targetAccounts = targetAccounts;
|
||||
public void setAccountConfigs(List<AccountConfig> accountConfigs) {
|
||||
this.accountConfigs = accountConfigs;
|
||||
}
|
||||
|
||||
public CommonParams getCommonParams() {
|
||||
|
||||
@@ -256,8 +256,15 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
||||
@Override
|
||||
@Transactional
|
||||
public Long batchPublish(BatchPublishRequest request) {
|
||||
log.info("开始批量发品任务,商品数: {}, 账号数: {}",
|
||||
request.getProducts().size(), request.getTargetAccounts().size());
|
||||
// 计算总的子账号数
|
||||
int totalSubAccounts = request.getAccountConfigs().stream()
|
||||
.mapToInt(config -> config.getSubAccounts().size())
|
||||
.sum();
|
||||
|
||||
log.info("开始批量发品任务,商品数: {}, 主账号数: {}, 总子账号数: {}",
|
||||
request.getProducts().size(),
|
||||
request.getAccountConfigs().size(),
|
||||
totalSubAccounts);
|
||||
|
||||
// 获取当前用户
|
||||
SysUser currentUser = SecurityUtils.getLoginUser().getUser();
|
||||
@@ -268,7 +275,8 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
||||
task.setOriginalMessage(request.getOriginalMessage());
|
||||
task.setTotalProducts(request.getProducts().size());
|
||||
task.setSelectedProducts(request.getProducts().size());
|
||||
task.setTargetAccounts(JSON.toJSONString(request.getTargetAccounts()));
|
||||
// 保存账号配置信息
|
||||
task.setTargetAccounts(JSON.toJSONString(request.getAccountConfigs()));
|
||||
task.setStatus(0); // 待处理
|
||||
task.setSuccessCount(0);
|
||||
task.setFailCount(0);
|
||||
@@ -280,16 +288,22 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
||||
taskMapper.insertBatchPublishTask(task);
|
||||
Long taskId = task.getId();
|
||||
|
||||
// 创建明细记录
|
||||
// 创建明细记录 - 为每个商品×每个主账号×每个子账号创建一条记录
|
||||
List<BatchPublishItem> items = new ArrayList<>();
|
||||
|
||||
for (BatchPublishRequest.ProductItem product : request.getProducts()) {
|
||||
for (String accountAppid : request.getTargetAccounts()) {
|
||||
for (BatchPublishRequest.AccountConfig accountConfig : request.getAccountConfigs()) {
|
||||
String accountAppid = accountConfig.getTargetAccount();
|
||||
String accountRemark = getAccountRemark(accountAppid);
|
||||
|
||||
for (String subAccount : accountConfig.getSubAccounts()) {
|
||||
BatchPublishItem item = new BatchPublishItem();
|
||||
item.setTaskId(taskId);
|
||||
item.setSkuid(product.getSkuid());
|
||||
item.setProductName(product.getProductName());
|
||||
item.setTargetAccount(accountAppid);
|
||||
item.setAccountRemark(getAccountRemark(accountAppid));
|
||||
item.setAccountRemark(accountRemark + "-" + subAccount);
|
||||
item.setSubAccount(subAccount); // 设置子账号
|
||||
item.setStatus(0); // 待发布
|
||||
item.setPublishPrice(product.getPrice() != null ? Math.round(product.getPrice() * 100) : null);
|
||||
item.setDelaySeconds(request.getDelaySeconds());
|
||||
@@ -297,6 +311,7 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
itemMapper.batchInsertBatchPublishItem(items);
|
||||
@@ -413,7 +428,8 @@ public class BatchPublishServiceImpl implements IBatchPublishService
|
||||
|
||||
// 2. 发布店铺(必填)
|
||||
PublishShop shop = new PublishShop();
|
||||
shop.setUserName(commonParams.getUserName());
|
||||
// 使用子账号作为会员名
|
||||
shop.setUserName(item.getSubAccount() != null ? item.getSubAccount() : commonParams.getUserName());
|
||||
shop.setProvince(commonParams.getProvince());
|
||||
shop.setCity(commonParams.getCity());
|
||||
shop.setDistrict(commonParams.getDistrict());
|
||||
|
||||
@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="productName" column="product_name" />
|
||||
<result property="targetAccount" column="target_account" />
|
||||
<result property="accountRemark" column="account_remark" />
|
||||
<result property="subAccount" column="sub_account" />
|
||||
<result property="status" column="status" />
|
||||
<result property="productId" column="product_id" />
|
||||
<result property="productStatus" column="product_status" />
|
||||
@@ -23,7 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectBatchPublishItemVo">
|
||||
select id, task_id, skuid, product_name, target_account, account_remark, status,
|
||||
select id, task_id, skuid, product_name, target_account, account_remark, sub_account, status,
|
||||
product_id, product_status, outer_id, publish_price, error_message,
|
||||
publish_time, delay_seconds, create_time
|
||||
from batch_publish_item
|
||||
@@ -59,6 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="productName != null">product_name,</if>
|
||||
<if test="targetAccount != null">target_account,</if>
|
||||
<if test="accountRemark != null">account_remark,</if>
|
||||
<if test="subAccount != null">sub_account,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="productId != null">product_id,</if>
|
||||
<if test="productStatus != null">product_status,</if>
|
||||
@@ -75,6 +77,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="productName != null">#{productName},</if>
|
||||
<if test="targetAccount != null">#{targetAccount},</if>
|
||||
<if test="accountRemark != null">#{accountRemark},</if>
|
||||
<if test="subAccount != null">#{subAccount},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="productId != null">#{productId},</if>
|
||||
<if test="productStatus != null">#{productStatus},</if>
|
||||
@@ -89,11 +92,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<insert id="batchInsertBatchPublishItem" parameterType="java.util.List">
|
||||
insert into batch_publish_item
|
||||
(task_id, skuid, product_name, target_account, account_remark, status, publish_price, delay_seconds, create_time)
|
||||
(task_id, skuid, product_name, target_account, account_remark, sub_account, status, publish_price, delay_seconds, create_time)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.taskId}, #{item.skuid}, #{item.productName}, #{item.targetAccount}, #{item.accountRemark},
|
||||
#{item.status}, #{item.publishPrice}, #{item.delaySeconds}, #{item.createTime})
|
||||
#{item.subAccount}, #{item.status}, #{item.publishPrice}, #{item.delaySeconds}, #{item.createTime})
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
|
||||
8
sql/add_sub_account_column.sql
Normal file
8
sql/add_sub_account_column.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- 添加子账号字段到批量发品明细表
|
||||
-- 执行时间: 2025-01-10
|
||||
|
||||
ALTER TABLE batch_publish_item ADD COLUMN sub_account VARCHAR(100) COMMENT '子账号(会员名)' AFTER account_remark;
|
||||
|
||||
-- 为现有数据设置默认值(可选)
|
||||
-- UPDATE batch_publish_item SET sub_account = '默认子账号' WHERE sub_account IS NULL;
|
||||
|
||||
Reference in New Issue
Block a user