智能体按 reply_code 读后台回复语;陆运整车报价单顶栏色与填表更稳,工单页展示同步收紧。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+16
@@ -44,12 +44,28 @@ public class InquiryAgentController {
|
||||
@Autowired
|
||||
private org.jeecg.modules.inquiry.tms.InquiryTmsCabinService cabinService;
|
||||
|
||||
@Autowired
|
||||
private org.jeecg.modules.inquiry.service.IInquiryBotReplyService botReplyService;
|
||||
|
||||
@Value("${inquiry.agent.callback-token:${AGENT_CALLBACK_TOKEN:}}")
|
||||
private String agentToken;
|
||||
|
||||
@Value("${inquiry.agent.biz-token:${BIZ_API_TOKEN:}}")
|
||||
private String bizToken;
|
||||
|
||||
/**
|
||||
* 智能体只读回复语。停用或不在列表里的编码由智能体回退默认句。
|
||||
* 鉴权同其它 /inquiry/agent/** ,禁止后台菜单权限码。
|
||||
*/
|
||||
@ApiOperation("智能体-已启用回复语")
|
||||
@GetMapping("/botReply/listEnabled")
|
||||
public Result<java.util.List<java.util.Map<String, Object>>> botReplyListEnabled(HttpServletRequest http) {
|
||||
if (!authed(http)) {
|
||||
return Result.error(401, "unauthorized");
|
||||
}
|
||||
return Result.OK(botReplyService.listEnabledForAgent());
|
||||
}
|
||||
|
||||
@ApiOperation("智能体-回写模板 AI 映射结果")
|
||||
@PutMapping("/quoteTemplate/parseResult")
|
||||
public Result<String> quoteTemplateParseResult(@RequestBody Map<String, Object> body,
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
/**
|
||||
* 机器人回复语 API。
|
||||
* 支持按分类拉取全部条目(后台九分类页)与分页查询。
|
||||
* 调用编码 replyCode 给智能体日后按码取文案;本期只维护、不向智能体下发。
|
||||
* 调用编码 replyCode 供智能体 GET /inquiry/agent/botReply/listEnabled 按码取文案。
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "询价-机器人回复语")
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ public class InquiryTicket implements Serializable {
|
||||
private List<InquiryPriceLine> saleLines;
|
||||
|
||||
/**
|
||||
* 利润点逐行。不入库。没调过价为空。最后一行是整单利润点。
|
||||
* 利润点逐行。不入库。没调过价每项都是 0%。最后一行是整单利润点。
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty("利润点逐行(展示)")
|
||||
|
||||
+6
@@ -22,4 +22,10 @@ public interface IInquiryBotReplyService extends IService<InquiryBotReply> {
|
||||
* 编辑正文/启停。已有调用编码不可被请求覆盖。
|
||||
*/
|
||||
void updateReply(InquiryBotReply body);
|
||||
|
||||
/**
|
||||
* 智能体只读:已启用且已有调用编码的正文。
|
||||
* 停用项不返回,智能体回退默认句。
|
||||
*/
|
||||
java.util.List<java.util.Map<String, Object>> listEnabledForAgent();
|
||||
}
|
||||
|
||||
+35
@@ -9,7 +9,13 @@ import org.jeecg.modules.inquiry.service.IInquiryBotReplyService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -90,6 +96,35 @@ public class InquiryBotReplyServiceImpl extends ServiceImpl<InquiryBotReplyMappe
|
||||
body.setReplyCode(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> listEnabledForAgent() {
|
||||
QueryWrapper<InquiryBotReply> qw = new QueryWrapper<>();
|
||||
qw.eq("enabled", 1);
|
||||
qw.isNotNull("reply_code");
|
||||
qw.ne("reply_code", "");
|
||||
qw.orderByAsc("sort_no").orderByAsc("id");
|
||||
Page<InquiryBotReply> page = new Page<>(1, 2000);
|
||||
page.setSearchCount(false);
|
||||
page.setMaxLimit(2000L);
|
||||
List<InquiryBotReply> rows = page(page, qw).getRecords();
|
||||
List<Map<String, Object>> out = new ArrayList<>();
|
||||
if (rows == null) {
|
||||
return out;
|
||||
}
|
||||
for (InquiryBotReply row : rows) {
|
||||
if (row == null || StringUtils.isBlank(row.getReplyCode())) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("replyCode", row.getReplyCode());
|
||||
item.put("replyText", row.getReplyText());
|
||||
item.put("triggerScene", row.getTriggerScene());
|
||||
item.put("categoryCode", row.getCategoryCode());
|
||||
out.add(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private void assertCodeUnique(String replyCode, String excludeId) {
|
||||
if (StringUtils.isBlank(replyCode)) {
|
||||
return;
|
||||
|
||||
+17
-1
@@ -686,7 +686,7 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
return;
|
||||
}
|
||||
String username = StringUtils.trimToEmpty(login.getUsername());
|
||||
String wecom = StringUtils.trimToEmpty(login.getWorkNo());
|
||||
String wecom = dashboardWecomId(login);
|
||||
qw.and(w -> {
|
||||
boolean any = false;
|
||||
if (StringUtils.isNotBlank(wecom)) {
|
||||
@@ -734,4 +734,20 @@ public class InquiryDashboardServiceImpl implements IInquiryDashboardService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 看板「只看自己」用的企微工号。
|
||||
* 不用直接调 getWorkNo:测服打包时基座 LoginUser 可能还没有这个方法。
|
||||
*/
|
||||
private static String dashboardWecomId(LoginUser login) {
|
||||
if (login == null) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
Object v = login.getClass().getMethod("getWorkNo").invoke(login);
|
||||
return v == null ? "" : StringUtils.trimToEmpty(String.valueOf(v));
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-4
@@ -19,7 +19,9 @@ import java.util.List;
|
||||
* <p>
|
||||
* 职责:从已保存的报价明细铺开展示。不改调价算法,不把各行金额加总冒充费用合计。
|
||||
* 海运/陆运:成本是调价前生效价(手工同名盖 TMS,多出来的补上);销售是最新调价。
|
||||
* 空运:成本整列空;销售是当前生效价;利润点只在调过价之后,对调价前销售价。
|
||||
* 空运:成本整列空;销售是当前生效价。
|
||||
* 未调价:各项利润点与费用合计都是 0%,禁止拿金额去填利润点列。
|
||||
* 已调价:利润点对调价前同名行。
|
||||
* 副作用:改 ticket 的三列逐行;手工盖价算出新的官方总价时,同时改成本价和利润点字符串。不写库。
|
||||
* 调用:{@link InquiryTicketPriceSupport#apply} 末尾。列表 enrich 与保存报价后的 update 都走那里。
|
||||
*/
|
||||
@@ -126,7 +128,7 @@ public final class InquiryQuoteLineSupport {
|
||||
profitTotal = StringUtils.defaultString(InquiryTicketPriceSupport.profitText(saleTotal, baseTotal));
|
||||
ticket.setProfitRate(profitTotal);
|
||||
} else if (!adjusted) {
|
||||
ticket.setProfitRate("");
|
||||
ticket.setProfitRate("0%");
|
||||
}
|
||||
|
||||
if (air) {
|
||||
@@ -134,13 +136,13 @@ public final class InquiryQuoteLineSupport {
|
||||
ticket.setSaleLines(moneyLines(saleFees, saleTotal));
|
||||
ticket.setProfitLines(adjusted && StringUtils.isNotBlank(profitTotal)
|
||||
? profitAgainst(baselineFees, saleFees, profitTotal)
|
||||
: Collections.<InquiryPriceLine>emptyList());
|
||||
: zeroPercentLines(saleFees));
|
||||
return;
|
||||
}
|
||||
if (!adjusted) {
|
||||
ticket.setCostLines(moneyLines(costFees, costTotal));
|
||||
ticket.setSaleLines(Collections.<InquiryPriceLine>emptyList());
|
||||
ticket.setProfitLines(Collections.<InquiryPriceLine>emptyList());
|
||||
ticket.setProfitLines(zeroPercentLines(costFees));
|
||||
return;
|
||||
}
|
||||
List<Aligned> rows = align(costFees, saleFees);
|
||||
@@ -216,6 +218,21 @@ public final class InquiryQuoteLineSupport {
|
||||
return formatMoney(base.add(delta), totalCcy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未调价:每一项费用和费用合计都写 0%。
|
||||
* 列表/详情都走这里,避免利润点列空白或误把金额填进去。
|
||||
*/
|
||||
private static List<InquiryPriceLine> zeroPercentLines(List<FeeRow> fees) {
|
||||
List<InquiryPriceLine> lines = new ArrayList<InquiryPriceLine>();
|
||||
if (fees != null) {
|
||||
for (FeeRow fee : fees) {
|
||||
lines.add(line(fee.name, "0%"));
|
||||
}
|
||||
}
|
||||
lines.add(line(TOTAL_NAME, "0%"));
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static List<InquiryPriceLine> moneyLines(List<FeeRow> fees, String totalText) {
|
||||
List<InquiryPriceLine> lines = new ArrayList<InquiryPriceLine>();
|
||||
if (fees != null) {
|
||||
|
||||
+4
-3
@@ -14,7 +14,8 @@ import java.util.regex.Pattern;
|
||||
* 后台成本价 / 销售价 / 利润点:按业务线从报价记录重算。
|
||||
* <p>
|
||||
* 海运/陆运:TMS、产品报价是成本;销售调价后才有销售价,利润点=(销售-成本)/成本。
|
||||
* 空运:成本价始终空;TMS/航线/调价都是销售侧;利润点只在销售调过价后算。
|
||||
* 空运:成本价始终空;TMS/航线/调价都是销售侧。
|
||||
* 未调价时利润点固定 0%(含各项),调过价才按差额算。
|
||||
* 副作用:只改传入 ticket 的展示字段(三个总价字符串和三列逐行),不写库。调用方决定是否 updateById。
|
||||
*/
|
||||
public final class InquiryTicketPriceSupport {
|
||||
@@ -63,7 +64,7 @@ public final class InquiryTicketPriceSupport {
|
||||
ticket.setProfitRate(profitText(adjustPrice, baseline));
|
||||
} else {
|
||||
ticket.setSalePrice(StringUtils.isNotBlank(manualPrice) ? manualPrice : tmsPrice);
|
||||
ticket.setProfitRate("");
|
||||
ticket.setProfitRate("0%");
|
||||
}
|
||||
} else {
|
||||
String cost = StringUtils.isNotBlank(manualPrice) ? manualPrice : tmsPrice;
|
||||
@@ -73,7 +74,7 @@ public final class InquiryTicketPriceSupport {
|
||||
ticket.setProfitRate(profitText(adjustPrice, cost));
|
||||
} else {
|
||||
ticket.setSalePrice("");
|
||||
ticket.setProfitRate("");
|
||||
ticket.setProfitRate("0%");
|
||||
}
|
||||
}
|
||||
// 三个总价定完后,按同一批报价拆成逐行。有手工明细盖 TMS 时,这里会改写成本价和利润点。
|
||||
|
||||
+1148
-40
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -689,7 +689,7 @@ public class InquiryTmsQueryService {
|
||||
|
||||
/**
|
||||
* 把本次 TMS 报价写回工单主表,供后台列表/详情展示。
|
||||
* 海运/陆运进成本价,空运进销售价;利润点必须等销售调价后才算。
|
||||
* 海运/陆运进成本价,空运进销售价;未调价利润点为 0%,调过价才按差额算。
|
||||
*/
|
||||
static void applyQuoteToTicket(InquiryTicket ticket, Map<String, String> quote) {
|
||||
if (ticket == null || quote == null) {
|
||||
|
||||
Reference in New Issue
Block a user