Browse Source

为客服角色管理页面的字段添加 label

并移除排序字段
dev-mcp
wanghanlin 3 weeks ago
parent
commit
8c02a3f054
  1. 19
      src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java
  2. 4
      src/main/java/com/wok/supportbot/controller/CustomerServiceRoleController.java
  3. 16
      src/main/java/com/wok/supportbot/service/CustomerServiceRoleService.java
  4. 16
      src/main/resources/init-database.sql
  5. 29
      src/main/resources/static/components/RoleManager.js

19
src/main/java/com/wok/supportbot/config/DatabaseInitConfig.java

@ -339,7 +339,6 @@ public class DatabaseInitConfig {
name VARCHAR(100) NOT NULL, name VARCHAR(100) NOT NULL,
description TEXT, description TEXT,
prompt TEXT, prompt TEXT,
sort_order INTEGER DEFAULT 0 NOT NULL,
enabled BOOLEAN DEFAULT TRUE NOT NULL, enabled BOOLEAN DEFAULT TRUE NOT NULL,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
@ -347,7 +346,7 @@ public class DatabaseInitConfig {
) )
"""; """;
jdbcTemplate.execute(sql); jdbcTemplate.execute(sql);
jdbcTemplate.execute("CREATE INDEX IF NOT EXISTS idx_customer_service_role_enabled ON customer_service_role (enabled, sort_order)");
jdbcTemplate.execute("CREATE INDEX IF NOT EXISTS idx_customer_service_role_enabled ON customer_service_role (enabled)");
} }
private void createCustomerServiceRoleCategoryTable() { private void createCustomerServiceRoleCategoryTable() {
@ -464,17 +463,17 @@ public class DatabaseInitConfig {
""" """
职责回答用户关于业务办理服务流程常见问题问题受理和进度说明的问题 职责回答用户关于业务办理服务流程常见问题问题受理和进度说明的问题
要求优先依据知识库回答资料不足时说明无法确认并引导用户补充必要信息涉及财务行政制度细节时不要猜测应提示转对应角色处理 要求优先依据知识库回答资料不足时说明无法确认并引导用户补充必要信息涉及财务行政制度细节时不要猜测应提示转对应角色处理
""", 10);
""");
upsertDefaultRole("finance", "财务", "付款、退款、发票、对账、报销、结算与费用规则", upsertDefaultRole("finance", "财务", "付款、退款、发票、对账、报销、结算与费用规则",
""" """
职责回答付款退款发票对账报销结算费用规则相关问题 职责回答付款退款发票对账报销结算费用规则相关问题
要求金额账户票据时间节点必须严谨知识库没有依据时不得编造政策需要用户提供单号金额日期发票抬头等关键信息 要求金额账户票据时间节点必须严谨知识库没有依据时不得编造政策需要用户提供单号金额日期发票抬头等关键信息
""", 20);
""");
upsertDefaultRole("administration", "行政", "办公制度、行政流程、资产、会议、考勤、用章、采购与后勤", upsertDefaultRole("administration", "行政", "办公制度、行政流程、资产、会议、考勤、用章、采购与后勤",
""" """
职责回答办公制度行政流程资产会议考勤入职用章采购后勤等问题 职责回答办公制度行政流程资产会议考勤入职用章采购后勤等问题
要求优先依据公司制度和流程文件回答涉及审批权限特殊例外或未覆盖场景时提示按制度提交申请或联系行政负责人 要求优先依据公司制度和流程文件回答涉及审批权限特殊例外或未覆盖场景时提示按制度提交申请或联系行政负责人
""", 30);
""");
retireObsoleteDefaultRoles(); retireObsoleteDefaultRoles();
} }
@ -485,19 +484,18 @@ public class DatabaseInitConfig {
upsertDefaultAccount("administration", "行政账号", "默认行政账号", "administration"); upsertDefaultAccount("administration", "行政账号", "默认行政账号", "administration");
} }
private void upsertDefaultRole(String roleKey, String name, String description, String prompt, int sortOrder) {
private void upsertDefaultRole(String roleKey, String name, String description, String prompt) {
jdbcTemplate.update(""" jdbcTemplate.update("""
INSERT INTO customer_service_role (role_key, name, description, prompt, sort_order)
VALUES (?, ?, ?, ?, ?)
INSERT INTO customer_service_role (role_key, name, description, prompt)
VALUES (?, ?, ?, ?)
ON CONFLICT (role_key) ON CONFLICT (role_key)
DO UPDATE SET name = EXCLUDED.name, DO UPDATE SET name = EXCLUDED.name,
description = EXCLUDED.description, description = EXCLUDED.description,
prompt = EXCLUDED.prompt, prompt = EXCLUDED.prompt,
sort_order = EXCLUDED.sort_order,
enabled = true, enabled = true,
is_delete = false, is_delete = false,
update_time = CURRENT_TIMESTAMP update_time = CURRENT_TIMESTAMP
""", roleKey, name, description, prompt, sortOrder);
""", roleKey, name, description, prompt);
} }
private void upsertDefaultAccount(String accountKey, String name, String description, String roleKey) { private void upsertDefaultAccount(String accountKey, String name, String description, String roleKey) {
@ -1122,7 +1120,6 @@ public class DatabaseInitConfig {
executeComment("COLUMN customer_service_role.name", "角色名称"); executeComment("COLUMN customer_service_role.name", "角色名称");
executeComment("COLUMN customer_service_role.description", "角色描述"); executeComment("COLUMN customer_service_role.description", "角色描述");
executeComment("COLUMN customer_service_role.prompt", "系统提示词(角色人设与行为规范)"); executeComment("COLUMN customer_service_role.prompt", "系统提示词(角色人设与行为规范)");
executeComment("COLUMN customer_service_role.sort_order", "排序权重");
executeComment("COLUMN customer_service_role.enabled", "是否启用"); executeComment("COLUMN customer_service_role.enabled", "是否启用");
executeComment("COLUMN customer_service_role.create_time", "创建时间"); executeComment("COLUMN customer_service_role.create_time", "创建时间");
executeComment("COLUMN customer_service_role.update_time", "更新时间"); executeComment("COLUMN customer_service_role.update_time", "更新时间");

4
src/main/java/com/wok/supportbot/controller/CustomerServiceRoleController.java

@ -49,7 +49,7 @@ public class CustomerServiceRoleController {
try { try {
customerServiceRoleService.createRole( customerServiceRoleService.createRole(
str(body.get("roleKey")), str(body.get("name")), str(body.get("description")), str(body.get("roleKey")), str(body.get("name")), str(body.get("description")),
str(body.get("prompt")), intOrNull(body.get("sortOrder")), boolOrNull(body.get("enabled")));
str(body.get("prompt")), boolOrNull(body.get("enabled")));
return ResponseEntity.ok(Map.of("success", true, "message", "角色创建成功")); return ResponseEntity.ok(Map.of("success", true, "message", "角色创建成功"));
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(500).body(Map.of("success", false, "message", "创建角色失败:" + e.getMessage())); return ResponseEntity.status(500).body(Map.of("success", false, "message", "创建角色失败:" + e.getMessage()));
@ -62,7 +62,7 @@ public class CustomerServiceRoleController {
try { try {
customerServiceRoleService.updateRole(roleId, customerServiceRoleService.updateRole(roleId,
str(body.get("name")), str(body.get("description")), str(body.get("prompt")), str(body.get("name")), str(body.get("description")), str(body.get("prompt")),
intOrNull(body.get("sortOrder")), boolOrNull(body.get("enabled")));
boolOrNull(body.get("enabled")));
return ResponseEntity.ok(Map.of("success", true, "message", "角色更新成功")); return ResponseEntity.ok(Map.of("success", true, "message", "角色更新成功"));
} catch (Exception e) { } catch (Exception e) {
return ResponseEntity.status(500).body(Map.of("success", false, "message", "更新角色失败:" + e.getMessage())); return ResponseEntity.status(500).body(Map.of("success", false, "message", "更新角色失败:" + e.getMessage()));

16
src/main/java/com/wok/supportbot/service/CustomerServiceRoleService.java

@ -32,10 +32,10 @@ public class CustomerServiceRoleService {
* @param includeDisabled true=包含已停用角色管理页用false=仅启用角色对话页用 * @param includeDisabled true=包含已停用角色管理页用false=仅启用角色对话页用
*/ */
public List<Map<String, Object>> listRoles(boolean includeDisabled) { public List<Map<String, Object>> listRoles(boolean includeDisabled) {
String roleSql = "SELECT id::text AS id, role_key, name, description, prompt, sort_order, enabled, allowed_mcp_tools "
String roleSql = "SELECT id::text AS id, role_key, name, description, prompt, enabled, allowed_mcp_tools "
+ "FROM customer_service_role WHERE is_delete = false " + "FROM customer_service_role WHERE is_delete = false "
+ (includeDisabled ? "" : "AND enabled = true ") + (includeDisabled ? "" : "AND enabled = true ")
+ "ORDER BY sort_order ASC, id ASC";
+ "ORDER BY id ASC";
List<Map<String, Object>> roles = jdbcTemplate.queryForList(roleSql); List<Map<String, Object>> roles = jdbcTemplate.queryForList(roleSql);
String categorySql = """ String categorySql = """
@ -94,7 +94,7 @@ public class CustomerServiceRoleService {
* 新增角色role_key 缺省时自动生成 * 新增角色role_key 缺省时自动生成
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void createRole(String roleKey, String name, String description, String prompt, Integer sortOrder, Boolean enabled) {
public void createRole(String roleKey, String name, String description, String prompt, Boolean enabled) {
if (name == null || name.trim().isEmpty()) { if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("角色名称不能为空"); throw new IllegalArgumentException("角色名称不能为空");
} }
@ -102,11 +102,10 @@ public class CustomerServiceRoleService {
? "role_" + System.currentTimeMillis() ? "role_" + System.currentTimeMillis()
: roleKey.trim(); : roleKey.trim();
jdbcTemplate.update(""" jdbcTemplate.update("""
INSERT INTO customer_service_role (role_key, name, description, prompt, sort_order, enabled)
VALUES (?, ?, ?, ?, ?, ?)
INSERT INTO customer_service_role (role_key, name, description, prompt, enabled)
VALUES (?, ?, ?, ?, ?)
""", """,
key, name.trim(), description, prompt, key, name.trim(), description, prompt,
sortOrder != null ? sortOrder : 0,
enabled != null ? enabled : true); enabled != null ? enabled : true);
} }
@ -114,7 +113,7 @@ public class CustomerServiceRoleService {
* 编辑角色基本信息不含知识库分类分类走 {@link #updateRoleCategories} * 编辑角色基本信息不含知识库分类分类走 {@link #updateRoleCategories}
*/ */
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateRole(Long roleId, String name, String description, String prompt, Integer sortOrder, Boolean enabled) {
public void updateRole(Long roleId, String name, String description, String prompt, Boolean enabled) {
if (roleId == null || roleId <= 0) { if (roleId == null || roleId <= 0) {
throw new IllegalArgumentException("角色ID无效"); throw new IllegalArgumentException("角色ID无效");
} }
@ -123,11 +122,10 @@ public class CustomerServiceRoleService {
} }
jdbcTemplate.update(""" jdbcTemplate.update("""
UPDATE customer_service_role UPDATE customer_service_role
SET name = ?, description = ?, prompt = ?, sort_order = ?, enabled = ?, update_time = CURRENT_TIMESTAMP
SET name = ?, description = ?, prompt = ?, enabled = ?, update_time = CURRENT_TIMESTAMP
WHERE id = ? AND is_delete = false WHERE id = ? AND is_delete = false
""", """,
name.trim(), description, prompt, name.trim(), description, prompt,
sortOrder != null ? sortOrder : 0,
enabled != null ? enabled : true, enabled != null ? enabled : true,
roleId); roleId);
} }

16
src/main/resources/init-database.sql

@ -137,7 +137,6 @@ CREATE TABLE IF NOT EXISTS customer_service_role (
name VARCHAR(100) NOT NULL, name VARCHAR(100) NOT NULL,
description TEXT, description TEXT,
prompt TEXT, prompt TEXT,
sort_order INTEGER NOT NULL DEFAULT 0,
enabled BOOLEAN NOT NULL DEFAULT TRUE, enabled BOOLEAN NOT NULL DEFAULT TRUE,
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
@ -145,7 +144,7 @@ CREATE TABLE IF NOT EXISTS customer_service_role (
allowed_mcp_tools JSONB NOT NULL DEFAULT '[]' allowed_mcp_tools JSONB NOT NULL DEFAULT '[]'
); );
CREATE INDEX IF NOT EXISTS idx_customer_service_role_enabled ON customer_service_role (enabled, sort_order);
CREATE INDEX IF NOT EXISTS idx_customer_service_role_enabled ON customer_service_role (enabled);
COMMENT ON TABLE customer_service_role IS '客服角色表'; COMMENT ON TABLE customer_service_role IS '客服角色表';
COMMENT ON COLUMN customer_service_role.id IS '主键'; COMMENT ON COLUMN customer_service_role.id IS '主键';
@ -153,7 +152,6 @@ COMMENT ON COLUMN customer_service_role.role_key IS '角色标识符(唯一
COMMENT ON COLUMN customer_service_role.name IS '角色名称'; COMMENT ON COLUMN customer_service_role.name IS '角色名称';
COMMENT ON COLUMN customer_service_role.description IS '角色描述'; COMMENT ON COLUMN customer_service_role.description IS '角色描述';
COMMENT ON COLUMN customer_service_role.prompt IS '系统提示词'; COMMENT ON COLUMN customer_service_role.prompt IS '系统提示词';
COMMENT ON COLUMN customer_service_role.sort_order IS '排序权重';
COMMENT ON COLUMN customer_service_role.enabled IS '是否启用'; COMMENT ON COLUMN customer_service_role.enabled IS '是否启用';
COMMENT ON COLUMN customer_service_role.create_time IS '创建时间'; COMMENT ON COLUMN customer_service_role.create_time IS '创建时间';
COMMENT ON COLUMN customer_service_role.update_time IS '更新时间'; COMMENT ON COLUMN customer_service_role.update_time IS '更新时间';
@ -161,16 +159,16 @@ COMMENT ON COLUMN customer_service_role.is_delete IS '逻辑删除';
COMMENT ON COLUMN customer_service_role.allowed_mcp_tools IS '允许使用的 MCP 工具列表(JSONB 数组,空=不允许,["*"]=全部允许)'; COMMENT ON COLUMN customer_service_role.allowed_mcp_tools IS '允许使用的 MCP 工具列表(JSONB 数组,空=不允许,["*"]=全部允许)';
-- 默认角色种子数据 -- 默认角色种子数据
INSERT INTO customer_service_role (role_key, name, description, sort_order, enabled)
VALUES ('general', '客服', '通用客服角色', 0, TRUE)
INSERT INTO customer_service_role (role_key, name, description, enabled)
VALUES ('general', '客服', '通用客服角色', TRUE)
ON CONFLICT (role_key) DO NOTHING; ON CONFLICT (role_key) DO NOTHING;
INSERT INTO customer_service_role (role_key, name, description, sort_order, enabled)
VALUES ('finance', '财务', '财务相关客服角色', 1, TRUE)
INSERT INTO customer_service_role (role_key, name, description, enabled)
VALUES ('finance', '财务', '财务相关客服角色', TRUE)
ON CONFLICT (role_key) DO NOTHING; ON CONFLICT (role_key) DO NOTHING;
INSERT INTO customer_service_role (role_key, name, description, sort_order, enabled)
VALUES ('administration', '行政', '行政相关客服角色', 2, TRUE)
INSERT INTO customer_service_role (role_key, name, description, enabled)
VALUES ('administration', '行政', '行政相关客服角色', TRUE)
ON CONFLICT (role_key) DO NOTHING; ON CONFLICT (role_key) DO NOTHING;
-- ============================================================ -- ============================================================

29
src/main/resources/static/components/RoleManager.js

@ -19,14 +19,24 @@ export default {
<!-- 新增 / 编辑 表单 --> <!-- 新增 / 编辑 表单 -->
<div style="border:1px solid var(--border);border-radius:8px;padding:12px;margin-bottom:16px;"> <div style="border:1px solid var(--border);border-radius:8px;padding:12px;margin-bottom:16px;">
<div class="input-row"> <div class="input-row">
<input class="input" v-model="form.name" placeholder="角色名称 *">
<input class="input" v-model="form.description" placeholder="职责描述(可选)">
<input class="input input-sm" v-model.number="form.sortOrder" type="number" placeholder="排序">
<label class="toggle-line"><input type="checkbox" v-model="form.enabled"><span>启用</span></label>
<div style="flex:1;min-width:0;">
<label style="display:block;font-size:12px;color:var(--sub);margin-bottom:4px;">角色名称 <span style="color:#b91c1c;">*</span></label>
<input class="input" v-model="form.name" placeholder="请输入角色名称">
</div>
<div style="flex:1;min-width:0;">
<label style="display:block;font-size:12px;color:var(--sub);margin-bottom:4px;">职责描述</label>
<input class="input" v-model="form.description" placeholder="可选,简要说明角色职责">
</div>
<div style="display:flex;align-items:flex-end;padding-bottom:6px;">
<label class="toggle-line"><input type="checkbox" v-model="form.enabled"><span>启用</span></label>
</div>
</div>
<div style="margin-top:8px;">
<label style="display:block;font-size:12px;color:var(--sub);margin-bottom:4px;">角色人设 / 风格提示词</label>
<textarea class="textarea" v-model="form.prompt" rows="2"
placeholder="例如:先判断问题归属,再引导用户补充必要信息,并按制度或流程说明下一步。"
style="width:100%;"></textarea>
</div> </div>
<textarea class="textarea" v-model="form.prompt" rows="2"
placeholder="角色人设 / 风格提示词,例如:先判断问题归属,再引导用户补充必要信息,并按制度或流程说明下一步。"
style="margin-top:8px;width:100%;"></textarea>
<div class="input-row" style="margin-top:8px;"> <div class="input-row" style="margin-top:8px;">
<button class="btn btn-success" @click="submit">{{ editingId ? '保存修改' : '新增角色' }}</button> <button class="btn btn-success" @click="submit">{{ editingId ? '保存修改' : '新增角色' }}</button>
<button v-if="editingId" class="btn btn-outline btn-sm" @click="resetForm">取消编辑</button> <button v-if="editingId" class="btn btn-outline btn-sm" @click="resetForm">取消编辑</button>
@ -75,7 +85,7 @@ export default {
setup() { setup() {
const roles = ref([]) const roles = ref([])
const editingId = ref('') const editingId = ref('')
const form = reactive({ name: '', description: '', prompt: '', sortOrder: 0, enabled: true })
const form = reactive({ name: '', description: '', prompt: '', enabled: true })
async function reload() { async function reload() {
try { try {
@ -96,7 +106,6 @@ export default {
form.name = '' form.name = ''
form.description = '' form.description = ''
form.prompt = '' form.prompt = ''
form.sortOrder = 0
form.enabled = true form.enabled = true
} }
@ -105,7 +114,6 @@ export default {
form.name = role.name || '' form.name = role.name || ''
form.description = role.description || '' form.description = role.description || ''
form.prompt = role.prompt || '' form.prompt = role.prompt || ''
form.sortOrder = Number(role.sort_order || 0)
form.enabled = role.enabled !== false form.enabled = role.enabled !== false
} }
@ -118,7 +126,6 @@ export default {
name: form.name, name: form.name,
description: form.description, description: form.description,
prompt: form.prompt, prompt: form.prompt,
sortOrder: form.sortOrder,
enabled: form.enabled enabled: form.enabled
} }
try { try {

Loading…
Cancel
Save