Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
pms-dispatch-assistant
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
姜耀祖
pms-dispatch-assistant
Commits
6aab2c93
Commit
6aab2c93
authored
Jun 05, 2025
by
赵灿灿
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加查询专家信息
parent
f1f8a6eb
Pipeline
#21459
passed with stages
in 4 minutes and 24 seconds
Changes
18
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
2938 additions
and
0 deletions
+2938
-0
LangChainController.java
...chassistant/controller/langchain/LangChainController.java
+110
-0
ExpertInformation.java
...assistant/domain/expertInformation/ExpertInformation.java
+269
-0
ExpertInformationCriteria.java
...t/domain/expertInformation/ExpertInformationCriteria.java
+622
-0
ExpertInformationService.java
...nt/domain/expertInformation/ExpertInformationService.java
+111
-0
IExpertInformationRepository.java
...omain/expertInformation/IExpertInformationRepository.java
+79
-0
ExpertInformationRepository.java
...ucture/expertInformation/ExpertInformationRepository.java
+399
-0
ai-chat.html
src/main/resources/static/pages/test/ai-chat.html
+163
-0
reload.png
src/main/resources/static/pages/test/images/reload.png
+0
-0
service_head.png
src/main/resources/static/pages/test/images/service_head.png
+0
-0
service_img1.png
src/main/resources/static/pages/test/images/service_img1.png
+0
-0
service_img2.png
src/main/resources/static/pages/test/images/service_img2.png
+0
-0
service_img3.png
src/main/resources/static/pages/test/images/service_img3.png
+0
-0
service_img4.png
src/main/resources/static/pages/test/images/service_img4.png
+0
-0
service_img5.png
src/main/resources/static/pages/test/images/service_img5.png
+0
-0
service_img6.png
src/main/resources/static/pages/test/images/service_img6.png
+0
-0
user_head.png
src/main/resources/static/pages/test/images/user_head.png
+0
-0
ai-chat-vue.js
src/main/resources/static/pages/test/js/ai-chat-vue.js
+510
-0
ai-chat.css
src/main/resources/static/pages/test/style/ai-chat.css
+675
-0
No files found.
src/main/java/com/infoepoch/pms/dispatchassistant/controller/langchain/LangChainController.java
View file @
6aab2c93
...
...
@@ -767,4 +767,114 @@ public class LangChainController {
chatService
.
deleteChat
(
sessionId
);
return
Result
.
successData
(
"删除成功"
);
}
//调用智能体
@GetMapping
(
"/sseTest"
)
public
ResponseEntity
<
SseEmitter
>
sseTest
(
@RequestParam
String
chatMessage
,
@RequestParam
String
dialogId
,
@RequestParam
String
selectedExpert
,
@RequestParam
String
selectedOrg
)
{
String
condition
=
""
;
// String regionName= chatService.getAuthRegionName();
// if("内部专家".equals(selectedExpert)) {
// if ("组织内".equals(selectedOrg) && StringUtils.isNotEmpty(regionName)) {
// condition = ",只能查找" + regionName;
// } else if ("组织外".equals(selectedOrg) && StringUtils.isNotEmpty(regionName)) {
// condition = ",排除" + regionName;
// }
// }
// String urlAddr = "http://10.32.41.35:40517/scene_gateway/agent/6809d0895428476bb6789ad70c525c97";
String
urlAddr
=
"http://10.32.41.35:40517/scene_gateway/agent/468fd1bfa3e543fc8526a82a9093097a"
;
//chatService.getUrl(selectedExpert);
//String urlAddr = "http://10.32.41.35:40517/scene_gateway/agent/83f77143b09c461993dd9a7db403eb94";
SseEmitter
emitter
=
new
SseEmitter
(
0L
);
QuestionRequest
questionRequest
=
new
QuestionRequest
();
questionRequest
.
setKeyword
(
chatMessage
+
condition
);
questionRequest
.
setRequestId
(
getRequestId
());
questionRequest
.
setDialogId
(
dialogId
);
// Conversations conversations=chatService.saveConversations(dialogId,chatMessage,selectedExpert);
// Messages messagesQusetion=new Messages();
// messagesQusetion.setRequestId(dialogId);
// messagesQusetion.setContent(chatMessage);
// messagesQusetion.setRole("user");
// messagesQusetion.setModelName("qwen2.5-72b");
// messagesQusetion=chatService.insertQuestionMessage(conversations,messagesQusetion);
// Messages messagesContent=new Messages();
// messagesContent.setRole("assistant");
// messagesContent.setModelName("qwen2.5-72b");
// messagesContent.setParentMsgId(messagesQusetion.getId());
// messagesContent.setSort(messagesQusetion.getSort()+1);
// chatService.insertMessage(conversations,messagesContent);
String
params
=
JsonUtils
.
objectToJson
(
questionRequest
);
StringBuffer
content
=
new
StringBuffer
();
StringBuffer
lineCotent
=
new
StringBuffer
();
new
Thread
(()
->
{
HttpURLConnection
connection
=
null
;
try
{
URL
url
=
new
URL
(
urlAddr
);
// 建立链接
connection
=
(
HttpURLConnection
)
url
.
openConnection
();
connection
.
setRequestMethod
(
"GET"
);
connection
.
setRequestProperty
(
"AuthToken"
,
"4009fe23e6b648539792330c14f5ed8e"
);
// connection.setRequestProperty("AuthToken", "fc40db5b7abe47dabfe1899e61fde2d7");
// 允许输入和输出
connection
.
setDoInput
(
true
);
connection
.
setDoOutput
(
true
);
// 设置超时为0,表示无限制
connection
.
setConnectTimeout
(
0
);
connection
.
setReadTimeout
(
0
);
try
(
OutputStream
os
=
connection
.
getOutputStream
())
{
os
.
write
(
params
.
getBytes
(
StandardCharsets
.
UTF_8
));
os
.
flush
();
}
// 检查响应码
int
responseCode
=
connection
.
getResponseCode
();
if
(
responseCode
!=
HttpURLConnection
.
HTTP_OK
)
{
emitter
.
completeWithError
(
new
RuntimeException
(
"SSE 连接失败: "
+
responseCode
));
return
;
}
// 持续读取 SSE 数据流
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
connection
.
getInputStream
())))
{
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
logger
.
info
(
line
);
if
(!
line
.
startsWith
(
"data:CALLBACK#"
))
{
if
(
line
.
startsWith
(
"data:"
))
{
String
data
=
line
.
substring
(
5
).
trim
();
if
(
"stop"
.
equals
(
data
))
{
emitter
.
send
(
SseEmitter
.
event
().
data
(
"stop"
),
MediaType
.
parseMediaType
(
"application/json; charset=UTF-8"
));
}
else
{
lineCotent
.
append
(
data
);
String
sendData
=
data
.
replace
(
"attachment#[]#attachment"
,
""
).
replace
(
"source#[]#source"
,
""
)
.
replace
(
"#"
,
""
).
replace
(
"*"
,
""
);
emitter
.
send
(
SseEmitter
.
event
().
data
(
sendData
),
MediaType
.
parseMediaType
(
"application/json; charset=UTF-8"
));
if
(!
sendData
.
startsWith
(
"SUGGEST["
))
content
.
append
(
sendData
);
}
}
}
}
}
emitter
.
complete
();
// 流结束
}
catch
(
Exception
e
)
{
emitter
.
completeWithError
(
e
);
logger
.
info
(
e
.
getMessage
());
}
finally
{
// messagesContent.setContent(content.toString());
// chatService.updateMessage(messagesContent);
if
(
connection
!=
null
)
{
connection
.
disconnect
();
}
logger
.
info
(
lineCotent
.
toString
());
}
}).
start
();
return
ResponseEntity
.
ok
()
.
header
(
HttpHeaders
.
CONTENT_TYPE
,
MediaType
.
TEXT_EVENT_STREAM_VALUE
)
.
body
(
emitter
);
}
}
src/main/java/com/infoepoch/pms/dispatchassistant/domain/expertInformation/ExpertInformation.java
0 → 100644
View file @
6aab2c93
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
domain
.
expertInformation
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
java.math.BigDecimal
;
import
java.util.Date
;
/**
* generated by code-generator
* 专家信息表
*/
public
class
ExpertInformation
{
/**
* 专家ID
*/
private
Integer
id
;
/**
* 专家姓名
*/
private
String
name
;
/**
* 专家性别
*/
private
String
gender
;
/**
* 专家邮箱
*/
private
String
mailbox
;
/**
* 专家电话
*/
private
String
telephone
;
/**
* 专家OA用户名
*/
private
String
userName
;
/**
* 入职时间
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
employmentDate
;
/**
* 专家部门
*/
private
String
department
;
/**
* 专家科室
*/
private
String
group
;
/**
* 职位
*/
private
String
position
;
/**
* 业务范围
*/
private
String
scopeBusiness
;
/**
* 调用状态
*/
private
String
state
;
/**
* 擅长领域
*/
private
String
specializesFields
;
/**
* 专家简介
*/
private
String
expertIntroduction
;
/**
* 所属OA组织编码
*/
private
String
organizationalCode
;
/**
* 记录时间
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
recordTime
;
/**
* 更新时间
*/
@JsonFormat
(
pattern
=
"yyyy-MM-dd HH:mm:ss"
,
timezone
=
"GMT+8"
)
private
Date
updateTime
;
/**
* 专家照片
*/
private
String
photo
;
/**
* 专家科室ID
*/
private
Integer
groupId
;
/**
* 专家部门ID
*/
private
Integer
departmentId
;
/**
* 专家用户ID
*/
private
Integer
userId
;
/**
* 专家满意度均分
*/
private
BigDecimal
satisfactionScore
;
/**
* 专家职称
*/
private
String
level
;
/**
* 专家是否启用(1是启用,0是禁用,2是冻结)
*/
private
String
disabled
;
/**
* 所属地市
*/
private
String
regionCode
;
/**
* 排序
*/
private
Integer
sort
;
/**
* 私有无参构造
*/
private
ExpertInformation
()
{
}
/**
* 仓储还原
*/
public
ExpertInformation
(
Integer
id
,
String
name
,
String
gender
,
String
mailbox
,
String
telephone
,
String
userName
,
Date
employmentDate
,
String
department
,
String
group
,
String
position
,
String
scopeBusiness
,
String
state
,
String
specializesFields
,
String
expertIntroduction
,
String
organizationalCode
,
Date
recordTime
,
Date
updateTime
,
String
photo
,
Integer
groupId
,
Integer
departmentId
,
Integer
userId
,
BigDecimal
satisfactionScore
,
String
level
,
String
disabled
,
String
regionCode
,
Integer
sort
)
{
this
.
id
=
id
;
this
.
name
=
name
;
this
.
gender
=
gender
;
this
.
mailbox
=
mailbox
;
this
.
telephone
=
telephone
;
this
.
userName
=
userName
;
this
.
employmentDate
=
employmentDate
;
this
.
department
=
department
;
this
.
group
=
group
;
this
.
position
=
position
;
this
.
scopeBusiness
=
scopeBusiness
;
this
.
state
=
state
;
this
.
specializesFields
=
specializesFields
;
this
.
expertIntroduction
=
expertIntroduction
;
this
.
organizationalCode
=
organizationalCode
;
this
.
recordTime
=
recordTime
;
this
.
updateTime
=
updateTime
;
this
.
photo
=
photo
;
this
.
groupId
=
groupId
;
this
.
departmentId
=
departmentId
;
this
.
userId
=
userId
;
this
.
satisfactionScore
=
satisfactionScore
;
this
.
level
=
level
;
this
.
disabled
=
disabled
;
this
.
regionCode
=
regionCode
;
this
.
sort
=
sort
;
}
/**
* 校验
*/
public
void
verify
()
{
}
public
Integer
getId
()
{
return
id
;
}
public
String
getName
()
{
return
name
;
}
public
String
getGender
()
{
return
gender
;
}
public
String
getMailbox
()
{
return
mailbox
;
}
public
String
getTelephone
()
{
return
telephone
;
}
public
String
getUserName
()
{
return
userName
;
}
public
Date
getEmploymentDate
()
{
return
employmentDate
;
}
public
String
getDepartment
()
{
return
department
;
}
public
String
getGroup
()
{
return
group
;
}
public
String
getPosition
()
{
return
position
;
}
public
String
getScopeBusiness
()
{
return
scopeBusiness
;
}
public
String
getState
()
{
return
state
;
}
public
String
getSpecializesFields
()
{
return
specializesFields
;
}
public
String
getExpertIntroduction
()
{
return
expertIntroduction
;
}
public
String
getOrganizationalCode
()
{
return
organizationalCode
;
}
public
Date
getRecordTime
()
{
return
recordTime
;
}
public
Date
getUpdateTime
()
{
return
updateTime
;
}
public
String
getPhoto
()
{
return
photo
;
}
public
Integer
getGroupId
()
{
return
groupId
;
}
public
Integer
getDepartmentId
()
{
return
departmentId
;
}
public
Integer
getUserId
()
{
return
userId
;
}
public
BigDecimal
getSatisfactionScore
()
{
return
satisfactionScore
;
}
public
String
getLevel
()
{
return
level
;
}
public
String
getDisabled
()
{
return
disabled
;
}
public
String
getRegionCode
()
{
return
regionCode
;
}
public
Integer
getSort
()
{
return
sort
;
}
}
src/main/java/com/infoepoch/pms/dispatchassistant/domain/expertInformation/ExpertInformationCriteria.java
0 → 100644
View file @
6aab2c93
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
domain
.
expertInformation
;
import
com.infoepoch.pms.dispatchassistant.common.component.AbstractCriteria
;
import
java.util.Date
;
/**
* generated by code-generator
* 专家信息表查询条件类
*/
public
class
ExpertInformationCriteria
extends
AbstractCriteria
{
//region 样例
//public boolean byId() {
// return this.andMap.containsKey("Id");
//}
//
//private String id;
//
//public String getId() {
// if (byId())
// return id;
// return null;
//}
//
//public void setId(String value) {
// this.id = value;
// this.andMap.put("Id", value);
//}
//endregion
//region 专家姓名
public
boolean
byName
()
{
return
this
.
andMap
.
containsKey
(
"Name"
);
}
private
String
name
;
public
String
getName
()
{
if
(
byName
())
return
name
;
return
null
;
}
public
void
setName
(
String
value
)
{
this
.
name
=
value
;
this
.
andMap
.
put
(
"Name"
,
value
);
}
//endregion
//region 专家姓名模糊查询
public
boolean
byNameContain
()
{
return
this
.
andMap
.
containsKey
(
"NameContain"
);
}
private
String
nameContain
;
public
String
getNameContain
()
{
if
(
byNameContain
())
return
nameContain
;
return
null
;
}
public
void
setNameContain
(
String
value
)
{
this
.
nameContain
=
value
;
this
.
andMap
.
put
(
"NameContain"
,
value
);
}
//endregion
//region 专家性别
public
boolean
byGender
()
{
return
this
.
andMap
.
containsKey
(
"Gender"
);
}
private
String
gender
;
public
String
getGender
()
{
if
(
byGender
())
return
gender
;
return
null
;
}
public
void
setGender
(
String
value
)
{
this
.
gender
=
value
;
this
.
andMap
.
put
(
"Gender"
,
value
);
}
//endregion
//region 专家性别模糊查询
public
boolean
byGenderContain
()
{
return
this
.
andMap
.
containsKey
(
"GenderContain"
);
}
private
String
genderContain
;
public
String
getGenderContain
()
{
if
(
byGenderContain
())
return
genderContain
;
return
null
;
}
public
void
setGenderContain
(
String
value
)
{
this
.
genderContain
=
value
;
this
.
andMap
.
put
(
"GenderContain"
,
value
);
}
//endregion
//region 专家邮箱
public
boolean
byMailbox
()
{
return
this
.
andMap
.
containsKey
(
"Mailbox"
);
}
private
String
mailbox
;
public
String
getMailbox
()
{
if
(
byMailbox
())
return
mailbox
;
return
null
;
}
public
void
setMailbox
(
String
value
)
{
this
.
mailbox
=
value
;
this
.
andMap
.
put
(
"Mailbox"
,
value
);
}
//endregion
//region 专家邮箱模糊查询
public
boolean
byMailboxContain
()
{
return
this
.
andMap
.
containsKey
(
"MailboxContain"
);
}
private
String
mailboxContain
;
public
String
getMailboxContain
()
{
if
(
byMailboxContain
())
return
mailboxContain
;
return
null
;
}
public
void
setMailboxContain
(
String
value
)
{
this
.
mailboxContain
=
value
;
this
.
andMap
.
put
(
"MailboxContain"
,
value
);
}
//endregion
//region 专家电话
public
boolean
byTelephone
()
{
return
this
.
andMap
.
containsKey
(
"Telephone"
);
}
private
String
telephone
;
public
String
getTelephone
()
{
if
(
byTelephone
())
return
telephone
;
return
null
;
}
public
void
setTelephone
(
String
value
)
{
this
.
telephone
=
value
;
this
.
andMap
.
put
(
"Telephone"
,
value
);
}
//endregion
//region 专家电话模糊查询
public
boolean
byTelephoneContain
()
{
return
this
.
andMap
.
containsKey
(
"TelephoneContain"
);
}
private
String
telephoneContain
;
public
String
getTelephoneContain
()
{
if
(
byTelephoneContain
())
return
telephoneContain
;
return
null
;
}
public
void
setTelephoneContain
(
String
value
)
{
this
.
telephoneContain
=
value
;
this
.
andMap
.
put
(
"TelephoneContain"
,
value
);
}
//endregion
//region 专家OA用户名
public
boolean
byUserName
()
{
return
this
.
andMap
.
containsKey
(
"UserName"
);
}
private
String
userName
;
public
String
getUserName
()
{
if
(
byUserName
())
return
userName
;
return
null
;
}
public
void
setUserName
(
String
value
)
{
this
.
userName
=
value
;
this
.
andMap
.
put
(
"UserName"
,
value
);
}
//endregion
//region 专家OA用户名模糊查询
public
boolean
byUserNameContain
()
{
return
this
.
andMap
.
containsKey
(
"UserNameContain"
);
}
private
String
userNameContain
;
public
String
getUserNameContain
()
{
if
(
byUserNameContain
())
return
userNameContain
;
return
null
;
}
public
void
setUserNameContain
(
String
value
)
{
this
.
userNameContain
=
value
;
this
.
andMap
.
put
(
"UserNameContain"
,
value
);
}
//endregion
//region 入职时间
public
boolean
byEmploymentDate
()
{
return
this
.
andMap
.
containsKey
(
"EmploymentDate"
);
}
private
Date
employmentDate
;
public
Date
getEmploymentDate
()
{
if
(
byEmploymentDate
())
return
employmentDate
;
return
null
;
}
public
void
setEmploymentDate
(
Date
value
)
{
this
.
employmentDate
=
value
;
this
.
andMap
.
put
(
"EmploymentDate"
,
value
);
}
//endregion
//region 专家部门
public
boolean
byDepartment
()
{
return
this
.
andMap
.
containsKey
(
"Department"
);
}
private
String
department
;
public
String
getDepartment
()
{
if
(
byDepartment
())
return
department
;
return
null
;
}
public
void
setDepartment
(
String
value
)
{
this
.
department
=
value
;
this
.
andMap
.
put
(
"Department"
,
value
);
}
//endregion
//region 专家部门模糊查询
public
boolean
byDepartmentContain
()
{
return
this
.
andMap
.
containsKey
(
"DepartmentContain"
);
}
private
String
departmentContain
;
public
String
getDepartmentContain
()
{
if
(
byDepartmentContain
())
return
departmentContain
;
return
null
;
}
public
void
setDepartmentContain
(
String
value
)
{
this
.
departmentContain
=
value
;
this
.
andMap
.
put
(
"DepartmentContain"
,
value
);
}
//endregion
//region 专家科室
public
boolean
byGroup
()
{
return
this
.
andMap
.
containsKey
(
"Group"
);
}
private
String
group
;
public
String
getGroup
()
{
if
(
byGroup
())
return
group
;
return
null
;
}
public
void
setGroup
(
String
value
)
{
this
.
group
=
value
;
this
.
andMap
.
put
(
"Group"
,
value
);
}
//endregion
//region 专家科室模糊查询
public
boolean
byGroupContain
()
{
return
this
.
andMap
.
containsKey
(
"GroupContain"
);
}
private
String
groupContain
;
public
String
getGroupContain
()
{
if
(
byGroupContain
())
return
groupContain
;
return
null
;
}
public
void
setGroupContain
(
String
value
)
{
this
.
groupContain
=
value
;
this
.
andMap
.
put
(
"GroupContain"
,
value
);
}
//endregion
//region 职位
public
boolean
byPosition
()
{
return
this
.
andMap
.
containsKey
(
"Position"
);
}
private
String
position
;
public
String
getPosition
()
{
if
(
byPosition
())
return
position
;
return
null
;
}
public
void
setPosition
(
String
value
)
{
this
.
position
=
value
;
this
.
andMap
.
put
(
"Position"
,
value
);
}
//endregion
//region 职位模糊查询
public
boolean
byPositionContain
()
{
return
this
.
andMap
.
containsKey
(
"PositionContain"
);
}
private
String
positionContain
;
public
String
getPositionContain
()
{
if
(
byPositionContain
())
return
positionContain
;
return
null
;
}
public
void
setPositionContain
(
String
value
)
{
this
.
positionContain
=
value
;
this
.
andMap
.
put
(
"PositionContain"
,
value
);
}
//endregion
//region 业务范围
public
boolean
byScopeBusiness
()
{
return
this
.
andMap
.
containsKey
(
"ScopeBusiness"
);
}
private
String
scopeBusiness
;
public
String
getScopeBusiness
()
{
if
(
byScopeBusiness
())
return
scopeBusiness
;
return
null
;
}
public
void
setScopeBusiness
(
String
value
)
{
this
.
scopeBusiness
=
value
;
this
.
andMap
.
put
(
"ScopeBusiness"
,
value
);
}
//endregion
//region 业务范围模糊查询
public
boolean
byScopeBusinessContain
()
{
return
this
.
andMap
.
containsKey
(
"ScopeBusinessContain"
);
}
private
String
scopeBusinessContain
;
public
String
getScopeBusinessContain
()
{
if
(
byScopeBusinessContain
())
return
scopeBusinessContain
;
return
null
;
}
public
void
setScopeBusinessContain
(
String
value
)
{
this
.
scopeBusinessContain
=
value
;
this
.
andMap
.
put
(
"ScopeBusinessContain"
,
value
);
}
//endregion
//region 调用状态
public
boolean
byState
()
{
return
this
.
andMap
.
containsKey
(
"State"
);
}
private
String
state
;
public
String
getState
()
{
if
(
byState
())
return
state
;
return
null
;
}
public
void
setState
(
String
value
)
{
this
.
state
=
value
;
this
.
andMap
.
put
(
"State"
,
value
);
}
//endregion
//region 调用状态模糊查询
public
boolean
byStateContain
()
{
return
this
.
andMap
.
containsKey
(
"StateContain"
);
}
private
String
stateContain
;
public
String
getStateContain
()
{
if
(
byStateContain
())
return
stateContain
;
return
null
;
}
public
void
setStateContain
(
String
value
)
{
this
.
stateContain
=
value
;
this
.
andMap
.
put
(
"StateContain"
,
value
);
}
//endregion
//region 擅长领域
public
boolean
bySpecializesFields
()
{
return
this
.
andMap
.
containsKey
(
"SpecializesFields"
);
}
private
String
specializesFields
;
public
String
getSpecializesFields
()
{
if
(
bySpecializesFields
())
return
specializesFields
;
return
null
;
}
public
void
setSpecializesFields
(
String
value
)
{
this
.
specializesFields
=
value
;
this
.
andMap
.
put
(
"SpecializesFields"
,
value
);
}
//endregion
//region 擅长领域模糊查询
public
boolean
bySpecializesFieldsContain
()
{
return
this
.
andMap
.
containsKey
(
"SpecializesFieldsContain"
);
}
private
String
specializesFieldsContain
;
public
String
getSpecializesFieldsContain
()
{
if
(
bySpecializesFieldsContain
())
return
specializesFieldsContain
;
return
null
;
}
public
void
setSpecializesFieldsContain
(
String
value
)
{
this
.
specializesFieldsContain
=
value
;
this
.
andMap
.
put
(
"SpecializesFieldsContain"
,
value
);
}
//endregion
//region 专家简介
public
boolean
byExpertIntroduction
()
{
return
this
.
andMap
.
containsKey
(
"ExpertIntroduction"
);
}
private
String
expertIntroduction
;
public
String
getExpertIntroduction
()
{
if
(
byExpertIntroduction
())
return
expertIntroduction
;
return
null
;
}
public
void
setExpertIntroduction
(
String
value
)
{
this
.
expertIntroduction
=
value
;
this
.
andMap
.
put
(
"ExpertIntroduction"
,
value
);
}
//endregion
//region 专家简介模糊查询
public
boolean
byExpertIntroductionContain
()
{
return
this
.
andMap
.
containsKey
(
"ExpertIntroductionContain"
);
}
private
String
expertIntroductionContain
;
public
String
getExpertIntroductionContain
()
{
if
(
byExpertIntroductionContain
())
return
expertIntroductionContain
;
return
null
;
}
public
void
setExpertIntroductionContain
(
String
value
)
{
this
.
expertIntroductionContain
=
value
;
this
.
andMap
.
put
(
"ExpertIntroductionContain"
,
value
);
}
//endregion
//region 所属OA组织编码
public
boolean
byOrganizationalCode
()
{
return
this
.
andMap
.
containsKey
(
"OrganizationalCode"
);
}
private
String
organizationalCode
;
public
String
getOrganizationalCode
()
{
if
(
byOrganizationalCode
())
return
organizationalCode
;
return
null
;
}
public
void
setOrganizationalCode
(
String
value
)
{
this
.
organizationalCode
=
value
;
this
.
andMap
.
put
(
"OrganizationalCode"
,
value
);
}
//endregion
//region 所属OA组织编码模糊查询
public
boolean
byOrganizationalCodeContain
()
{
return
this
.
andMap
.
containsKey
(
"OrganizationalCodeContain"
);
}
private
String
organizationalCodeContain
;
public
String
getOrganizationalCodeContain
()
{
if
(
byOrganizationalCodeContain
())
return
organizationalCodeContain
;
return
null
;
}
public
void
setOrganizationalCodeContain
(
String
value
)
{
this
.
organizationalCodeContain
=
value
;
this
.
andMap
.
put
(
"OrganizationalCodeContain"
,
value
);
}
//endregion
//region 专家职称
public
boolean
byLevel
()
{
return
this
.
andMap
.
containsKey
(
"Level"
);
}
private
String
level
;
public
String
getLevel
()
{
if
(
byLevel
())
return
level
;
return
null
;
}
public
void
setLevel
(
String
value
)
{
this
.
level
=
value
;
this
.
andMap
.
put
(
"Level"
,
value
);
}
//endregion
//region 专家职称模糊查询
public
boolean
byLevelContain
()
{
return
this
.
andMap
.
containsKey
(
"LevelContain"
);
}
private
String
levelContain
;
public
String
getLevelContain
()
{
if
(
byLevelContain
())
return
levelContain
;
return
null
;
}
public
void
setLevelContain
(
String
value
)
{
this
.
levelContain
=
value
;
this
.
andMap
.
put
(
"LevelContain"
,
value
);
}
//endregion
//region 所属地市
public
boolean
byRegionCode
()
{
return
this
.
andMap
.
containsKey
(
"RegionCode"
);
}
private
String
regionCode
;
public
String
getRegionCode
()
{
if
(
byRegionCode
())
return
regionCode
;
return
null
;
}
public
void
setRegionCode
(
String
value
)
{
this
.
regionCode
=
value
;
this
.
andMap
.
put
(
"RegionCode"
,
value
);
}
//endregion
//region 所属地市模糊查询
public
boolean
byRegionCodeContain
()
{
return
this
.
andMap
.
containsKey
(
"RegionCodeContain"
);
}
private
String
regionCodeContain
;
public
String
getRegionCodeContain
()
{
if
(
byRegionCodeContain
())
return
regionCodeContain
;
return
null
;
}
public
void
setRegionCodeContain
(
String
value
)
{
this
.
regionCodeContain
=
value
;
this
.
andMap
.
put
(
"RegionCodeContain"
,
value
);
}
//endregion
}
\ No newline at end of file
src/main/java/com/infoepoch/pms/dispatchassistant/domain/expertInformation/ExpertInformationService.java
0 → 100644
View file @
6aab2c93
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
domain
.
expertInformation
;
import
com.infoepoch.pms.dispatchassistant.common.exception.ValidationException
;
import
com.infoepoch.pms.dispatchassistant.common.utils.StringUtils
;
import
com.infoepoch.pms.dispatchassistant.infractructure.langchain.ConversationsRepository
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.stereotype.Service
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
/**
* generated by code-generator
* 专家信息表Service
**/
@Service
public
class
ExpertInformationService
{
@Autowired
private
IExpertInformationRepository
repository
;
private
static
final
Logger
LogHelper
=
LoggerFactory
.
getLogger
(
ConversationsRepository
.
class
);
/**
* 根据条件查询单个对象
**/
public
ExpertInformation
querySingle
(
ExpertInformationCriteria
criteria
)
{
criteria
.
removeMapNullOrEmpty
();
ExpertInformation
entity
;
try
{
entity
=
repository
.
selectOneByCriteria
(
criteria
);
return
entity
;
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
throw
new
ValidationException
(
"根据条件查询专家信息表 数据 失败。"
);
}
}
/**
* 根据id查询
**/
public
ExpertInformation
queryById
(
String
id
)
{
if
(
StringUtils
.
isBlank
(
id
)){
throw
new
ValidationException
(
"唯一标识不能为空"
);
};
ExpertInformation
entity
;
try
{
entity
=
repository
.
selectById
(
id
);
return
entity
;
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
throw
new
ValidationException
(
"根据id查询 专家信息表 数据 失败。"
);
}
}
/**
* 根据条件查询列表(可分页)
**/
public
Map
<
String
,
Object
>
queryList
(
ExpertInformationCriteria
criteria
)
{
try
{
criteria
.
removeMapNullOrEmpty
();
if
(
criteria
.
byPage
())
{
List
<
ExpertInformation
>
entityList
=
repository
.
selectCriteriaByPage
(
criteria
,
criteria
.
getPageSize
(),
criteria
.
getPageSize
());
int
totalCount
=
repository
.
selectCountByCriteria
(
criteria
);
Map
<
String
,
Object
>
map
=
new
HashMap
<>();
map
.
put
(
"totalCount"
,
totalCount
);
map
.
put
(
"entityList"
,
entityList
);
return
map
;
}
else
{
if
(!
criteria
.
hasCriteria
())
throw
new
ValidationException
(
"请输入查询条件。"
);
return
null
;
}
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
throw
new
ValidationException
(
"根据条件查询 专家信息表 列表 数据 失败。"
);
}
}
/**
* 保存
**/
public
boolean
save
(
ExpertInformation
entity
)
{
try
{
entity
.
verify
();
boolean
insert
=
repository
.
insert
(
entity
);
return
insert
;
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
throw
new
ValidationException
(
"保存 专家信息表 数据 失败。"
);
}
}
/**
* 修改
**/
public
boolean
modify
(
ExpertInformation
entity
)
{
try
{
entity
.
verify
();
boolean
update
=
repository
.
update
(
entity
);
return
update
;
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
throw
new
ValidationException
(
"修改 专家信息表 数据 失败。"
);
}
}
}
src/main/java/com/infoepoch/pms/dispatchassistant/domain/expertInformation/IExpertInformationRepository.java
0 → 100644
View file @
6aab2c93
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
domain
.
expertInformation
;
import
java.util.List
;
/**
* generated by code-generator
* 专家信息表仓储接口
*/
public
interface
IExpertInformationRepository
{
/**
* 表序列id
*/
Long
sequenceId
();
/**
* 新增
* @param: [entity]
*/
boolean
insert
(
ExpertInformation
entity
);
/**
* 更新
* @param: [entity]
*/
boolean
update
(
ExpertInformation
entity
);
/**
* 批量新增
* @param: [entitys]
*/
int
[]
batchInsert
(
List
<
ExpertInformation
>
entitys
);
/**
* 批量更新
* @param: [entitys]
*/
int
[]
batchUpdate
(
List
<
ExpertInformation
>
entitys
);
/**
* 删除
* @param: [id]
*/
boolean
delete
(
String
id
);
// region select
/**
* 根据Id查询
* @param: [id]
*/
ExpertInformation
selectById
(
String
id
);
/**
* 根据查询条件查询单个对象
* @param: [criteria]
*/
ExpertInformation
selectOneByCriteria
(
ExpertInformationCriteria
criteria
);
/**
* 根据查询条件查询对象集合
* @param: [criteria]
*/
List
<
ExpertInformation
>
selectByCriteria
(
ExpertInformationCriteria
criteria
);
/**
* 根据查询条件分页查询对象结合
* @param: [criteria, pageNum, pageSize]
*/
List
<
ExpertInformation
>
selectCriteriaByPage
(
ExpertInformationCriteria
criteria
,
int
pageNum
,
int
pageSize
);
/**
* 根据条件查询对象总记录数
* @param: [criteria]
*/
Integer
selectCountByCriteria
(
ExpertInformationCriteria
criteria
);
// endregion
}
src/main/java/com/infoepoch/pms/dispatchassistant/infractructure/expertInformation/ExpertInformationRepository.java
0 → 100644
View file @
6aab2c93
package
com
.
infoepoch
.
pms
.
dispatchassistant
.
infractructure
.
expertInformation
;
import
com.infoepoch.pms.dispatchassistant.common.utils.OracleUtils
;
import
com.infoepoch.pms.dispatchassistant.domain.expertInformation.ExpertInformation
;
import
com.infoepoch.pms.dispatchassistant.domain.expertInformation.ExpertInformationCriteria
;
import
com.infoepoch.pms.dispatchassistant.domain.expertInformation.IExpertInformationRepository
;
import
com.infoepoch.pms.dispatchassistant.infractructure.langchain.ConversationsRepository
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.jdbc.core.BatchPreparedStatementSetter
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.jdbc.core.RowMapper
;
import
org.springframework.stereotype.Repository
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.PreparedStatement
;
import
java.sql.Timestamp
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
/**
* generated by code-generator
* 专家信息表仓储实现
*/
@Repository
public
class
ExpertInformationRepository
implements
IExpertInformationRepository
{
@Autowired
private
JdbcTemplate
jdbcTemplate
;
private
static
final
Logger
LogHelper
=
LoggerFactory
.
getLogger
(
ConversationsRepository
.
class
);
/**
* 查询表序列id
*/
@Override
public
Long
sequenceId
()
{
StringBuffer
buffer
=
new
StringBuffer
(
"SELECT SEQ_T_EXPERT_INFORMATION.NEXTVAL FROM DUAL "
);
return
jdbcTemplate
.
queryForObject
(
buffer
.
toString
(),
Long
.
class
);
}
/**
* 新增
*/
@Override
public
boolean
insert
(
ExpertInformation
entity
)
{
String
sql
=
"INSERT INTO T_EXPERT_INFORMATION(EI_ID, EI_NAME, EI_GENDER, EI_MAILBOX, EI_TELEPHONE, EI_USER_NAME, EI_EMPLOYMENT_DATE, EI_DEPARTMENT, EI_GROUP, EI_POSITION, EI_SCOPE_BUSINESS, EI_STATE, EI_SPECIALIZES_FIELDS, EI_EXPERT_INTRODUCTION, EI_ORGANIZATIONAL_CODE, EI_RECORD_TIME, EI_UPDATE_TIME, EI_PHOTO, EI_GROUP_ID, EI_DEPARTMENT_ID, EI_USER_ID, EI_SATISFACTION_SCORE, EI_LEVEL, EI_DISABLED, EI_REGION_CODE, EI_SORT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
;
int
result
=
0
;
try
{
result
=
jdbcTemplate
.
update
(
sql
,
entity
.
getId
(),
entity
.
getName
(),
entity
.
getGender
(),
entity
.
getMailbox
(),
entity
.
getTelephone
(),
entity
.
getUserName
(),
entity
.
getEmploymentDate
(),
entity
.
getDepartment
(),
entity
.
getGroup
(),
entity
.
getPosition
(),
entity
.
getScopeBusiness
(),
entity
.
getState
(),
entity
.
getSpecializesFields
(),
entity
.
getExpertIntroduction
(),
entity
.
getOrganizationalCode
(),
entity
.
getRecordTime
(),
entity
.
getUpdateTime
(),
entity
.
getPhoto
(),
entity
.
getGroupId
(),
entity
.
getDepartmentId
(),
entity
.
getUserId
(),
entity
.
getSatisfactionScore
(),
entity
.
getLevel
(),
entity
.
getDisabled
(),
entity
.
getRegionCode
(),
entity
.
getSort
());
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
//throw new ServiceException("新增 专家信息表 数据 失败。");
}
return
result
>
0
;
}
/**
* 更新
*/
@Override
public
boolean
update
(
ExpertInformation
entity
)
{
String
sql
=
"UPDATE T_EXPERT_INFORMATION SET EI_NAME = ?, EI_GENDER = ?, EI_MAILBOX = ?, EI_TELEPHONE = ?, EI_USER_NAME = ?, EI_EMPLOYMENT_DATE = ?, EI_DEPARTMENT = ?, EI_GROUP = ?, EI_POSITION = ?, EI_SCOPE_BUSINESS = ?, EI_STATE = ?, EI_SPECIALIZES_FIELDS = ?, EI_EXPERT_INTRODUCTION = ?, EI_ORGANIZATIONAL_CODE = ?, EI_RECORD_TIME = ?, EI_UPDATE_TIME = ?, EI_PHOTO = ?, EI_GROUP_ID = ?, EI_DEPARTMENT_ID = ?, EI_USER_ID = ?, EI_SATISFACTION_SCORE = ?, EI_LEVEL = ?, EI_DISABLED = ?, EI_REGION_CODE = ?, EI_SORT = ? WHERE EI_ID = ?"
;
int
result
=
0
;
try
{
result
=
jdbcTemplate
.
update
(
sql
,
entity
.
getName
(),
entity
.
getGender
(),
entity
.
getMailbox
(),
entity
.
getTelephone
(),
entity
.
getUserName
(),
entity
.
getEmploymentDate
(),
entity
.
getDepartment
(),
entity
.
getGroup
(),
entity
.
getPosition
(),
entity
.
getScopeBusiness
(),
entity
.
getState
(),
entity
.
getSpecializesFields
(),
entity
.
getExpertIntroduction
(),
entity
.
getOrganizationalCode
(),
entity
.
getRecordTime
(),
entity
.
getUpdateTime
(),
entity
.
getPhoto
(),
entity
.
getGroupId
(),
entity
.
getDepartmentId
(),
entity
.
getUserId
(),
entity
.
getSatisfactionScore
(),
entity
.
getLevel
(),
entity
.
getDisabled
(),
entity
.
getRegionCode
(),
entity
.
getSort
(),
entity
.
getId
());
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
//throw new ServiceException("更新 专家信息表 数据 失败。");
}
return
result
>=
0
;
}
/**
* 批量新增
*/
public
int
[]
batchInsert
(
List
<
ExpertInformation
>
list
)
{
String
sql
=
"INSERT INTO T_EXPERT_INFORMATION(EI_ID, EI_NAME, EI_GENDER, EI_MAILBOX, EI_TELEPHONE, EI_USER_NAME, EI_EMPLOYMENT_DATE, EI_DEPARTMENT, EI_GROUP, EI_POSITION, EI_SCOPE_BUSINESS, EI_STATE, EI_SPECIALIZES_FIELDS, EI_EXPERT_INTRODUCTION, EI_ORGANIZATIONAL_CODE, EI_RECORD_TIME, EI_UPDATE_TIME, EI_PHOTO, EI_GROUP_ID, EI_DEPARTMENT_ID, EI_USER_ID, EI_SATISFACTION_SCORE, EI_LEVEL, EI_DISABLED, EI_REGION_CODE, EI_SORT) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
;
int
[]
result
=
jdbcTemplate
.
batchUpdate
(
sql
,
new
BatchPreparedStatementSetter
()
{
@Override
public
void
setValues
(
PreparedStatement
ps
,
int
i
)
throws
SQLException
{
int
j
=
0
;
ExpertInformation
item
=
list
.
get
(
i
);
ps
.
setObject
(++
j
,
item
.
getId
());
ps
.
setString
(++
j
,
item
.
getName
());
ps
.
setString
(++
j
,
item
.
getGender
());
ps
.
setString
(++
j
,
item
.
getMailbox
());
ps
.
setString
(++
j
,
item
.
getTelephone
());
ps
.
setString
(++
j
,
item
.
getUserName
());
ps
.
setTimestamp
(++
j
,
item
.
getEmploymentDate
()
!=
null
?
new
Timestamp
(
item
.
getEmploymentDate
().
getTime
())
:
null
);
ps
.
setString
(++
j
,
item
.
getDepartment
());
ps
.
setString
(++
j
,
item
.
getGroup
());
ps
.
setString
(++
j
,
item
.
getPosition
());
ps
.
setString
(++
j
,
item
.
getScopeBusiness
());
ps
.
setString
(++
j
,
item
.
getState
());
ps
.
setString
(++
j
,
item
.
getSpecializesFields
());
ps
.
setString
(++
j
,
item
.
getExpertIntroduction
());
ps
.
setString
(++
j
,
item
.
getOrganizationalCode
());
ps
.
setTimestamp
(++
j
,
item
.
getRecordTime
()
!=
null
?
new
Timestamp
(
item
.
getRecordTime
().
getTime
())
:
null
);
ps
.
setTimestamp
(++
j
,
item
.
getUpdateTime
()
!=
null
?
new
Timestamp
(
item
.
getUpdateTime
().
getTime
())
:
null
);
ps
.
setString
(++
j
,
item
.
getPhoto
());
ps
.
setObject
(++
j
,
item
.
getGroupId
());
ps
.
setObject
(++
j
,
item
.
getDepartmentId
());
ps
.
setObject
(++
j
,
item
.
getUserId
());
ps
.
setBigDecimal
(++
j
,
item
.
getSatisfactionScore
());
ps
.
setString
(++
j
,
item
.
getLevel
());
ps
.
setString
(++
j
,
item
.
getDisabled
());
ps
.
setString
(++
j
,
item
.
getRegionCode
());
ps
.
setObject
(++
j
,
item
.
getSort
());
}
@Override
public
int
getBatchSize
()
{
return
list
.
size
();
}
});
return
result
;
}
/**
* 批量更新
*/
public
int
[]
batchUpdate
(
List
<
ExpertInformation
>
list
)
{
String
sql
=
"UPDATE T_EXPERT_INFORMATION SET EI_NAME = ?, EI_GENDER = ?, EI_MAILBOX = ?, EI_TELEPHONE = ?, EI_USER_NAME = ?, EI_EMPLOYMENT_DATE = ?, EI_DEPARTMENT = ?, EI_GROUP = ?, EI_POSITION = ?, EI_SCOPE_BUSINESS = ?, EI_STATE = ?, EI_SPECIALIZES_FIELDS = ?, EI_EXPERT_INTRODUCTION = ?, EI_ORGANIZATIONAL_CODE = ?, EI_RECORD_TIME = ?, EI_UPDATE_TIME = ?, EI_PHOTO = ?, EI_GROUP_ID = ?, EI_DEPARTMENT_ID = ?, EI_USER_ID = ?, EI_SATISFACTION_SCORE = ?, EI_LEVEL = ?, EI_DISABLED = ?, EI_REGION_CODE = ?, EI_SORT = ? WHERE EI_ID = ? "
;
int
[]
result
=
jdbcTemplate
.
batchUpdate
(
sql
,
new
BatchPreparedStatementSetter
()
{
@Override
public
void
setValues
(
PreparedStatement
ps
,
int
i
)
throws
SQLException
{
int
j
=
0
;
ExpertInformation
item
=
list
.
get
(
i
);
ps
.
setString
(++
j
,
item
.
getName
());
ps
.
setString
(++
j
,
item
.
getGender
());
ps
.
setString
(++
j
,
item
.
getMailbox
());
ps
.
setString
(++
j
,
item
.
getTelephone
());
ps
.
setString
(++
j
,
item
.
getUserName
());
ps
.
setTimestamp
(++
j
,
item
.
getEmploymentDate
()
!=
null
?
new
Timestamp
(
item
.
getEmploymentDate
().
getTime
())
:
null
);
ps
.
setString
(++
j
,
item
.
getDepartment
());
ps
.
setString
(++
j
,
item
.
getGroup
());
ps
.
setString
(++
j
,
item
.
getPosition
());
ps
.
setString
(++
j
,
item
.
getScopeBusiness
());
ps
.
setString
(++
j
,
item
.
getState
());
ps
.
setString
(++
j
,
item
.
getSpecializesFields
());
ps
.
setString
(++
j
,
item
.
getExpertIntroduction
());
ps
.
setString
(++
j
,
item
.
getOrganizationalCode
());
ps
.
setTimestamp
(++
j
,
item
.
getRecordTime
()
!=
null
?
new
Timestamp
(
item
.
getRecordTime
().
getTime
())
:
null
);
ps
.
setTimestamp
(++
j
,
item
.
getUpdateTime
()
!=
null
?
new
Timestamp
(
item
.
getUpdateTime
().
getTime
())
:
null
);
ps
.
setString
(++
j
,
item
.
getPhoto
());
ps
.
setObject
(++
j
,
item
.
getGroupId
());
ps
.
setObject
(++
j
,
item
.
getDepartmentId
());
ps
.
setObject
(++
j
,
item
.
getUserId
());
ps
.
setBigDecimal
(++
j
,
item
.
getSatisfactionScore
());
ps
.
setString
(++
j
,
item
.
getLevel
());
ps
.
setString
(++
j
,
item
.
getDisabled
());
ps
.
setString
(++
j
,
item
.
getRegionCode
());
ps
.
setObject
(++
j
,
item
.
getSort
());
ps
.
setObject
(++
j
,
item
.
getId
());
}
@Override
public
int
getBatchSize
()
{
return
list
.
size
();
}
});
return
result
;
}
/**
* 删除
*/
@Override
public
boolean
delete
(
String
id
)
{
String
sql
=
"DELETE FROM T_EXPERT_INFORMATION WHERE EI_ID = ?"
;
int
result
=
0
;
try
{
result
=
jdbcTemplate
.
update
(
sql
,
id
);
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
// throw new ServiceException("删除 专家信息表 数据 失败。");
}
return
result
>
0
;
}
/**
* 根据Id查询
*/
@Override
public
ExpertInformation
selectById
(
String
id
)
{
String
sql
=
"SELECT * FROM T_EXPERT_INFORMATION WHERE EI_ID = ? "
;
try
{
return
jdbcTemplate
.
queryForObject
(
sql
,
new
ExpertInformationRowMapper
(),
id
);
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
return
null
;
}
}
/**
* 根据查询条件查询单个对象
*/
@Override
public
ExpertInformation
selectOneByCriteria
(
ExpertInformationCriteria
criteria
)
{
StringBuffer
buffer
=
new
StringBuffer
(
"SELECT * FROM T_EXPERT_INFORMATION "
);
List
<
Object
>
list
=
OracleUtils
.
combinationSql
(
buffer
,
createCriteriaSql
(
criteria
),
1
,
1
);
try
{
return
jdbcTemplate
.
queryForObject
(
buffer
.
toString
(),
list
.
toArray
(),
new
ExpertInformationRowMapper
());
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
return
null
;
}
}
/**
* 根据查询条件查询对象集合
*/
@Override
public
List
<
ExpertInformation
>
selectByCriteria
(
ExpertInformationCriteria
criteria
)
{
StringBuffer
buffer
=
new
StringBuffer
(
"SELECT * FROM T_EXPERT_INFORMATION "
);
List
<
Object
>
list
=
OracleUtils
.
combinationSql
(
buffer
,
createCriteriaSql
(
criteria
));
try
{
return
jdbcTemplate
.
query
(
buffer
.
toString
(),
list
.
toArray
(),
new
ExpertInformationRowMapper
());
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
return
null
;
}
}
/**
* 根据查询条件分页查询对象结合
*/
@Override
public
List
<
ExpertInformation
>
selectCriteriaByPage
(
ExpertInformationCriteria
criteria
,
int
pageNum
,
int
pageSize
)
{
StringBuffer
buffer
=
new
StringBuffer
(
"SELECT * FROM T_EXPERT_INFORMATION "
);
List
<
Object
>
list
=
OracleUtils
.
combinationSql
(
buffer
,
createCriteriaSql
(
criteria
),
pageNum
,
pageSize
);
try
{
return
jdbcTemplate
.
query
(
buffer
.
toString
(),
list
.
toArray
(),
new
ExpertInformationRowMapper
());
}
catch
(
Exception
e
)
{
LogHelper
.
info
(
e
.
getMessage
());
return
null
;
}
}
/**
* 根据条件查询对象总记录数
*/
@Override
public
Integer
selectCountByCriteria
(
ExpertInformationCriteria
criteria
)
{
StringBuffer
buffer
=
new
StringBuffer
(
"SELECT COUNT(*) FROM T_EXPERT_INFORMATION "
);
List
<
Object
>
list
=
OracleUtils
.
combinationSql
(
buffer
,
createCriteriaSql
(
criteria
));
int
count
=
jdbcTemplate
.
queryForObject
(
buffer
.
toString
(),
list
.
toArray
(),
int
.
class
);
return
count
;
}
/**
* RowMapper
*/
private
class
ExpertInformationRowMapper
implements
RowMapper
<
ExpertInformation
>
{
@Override
public
ExpertInformation
mapRow
(
ResultSet
rs
,
int
i
)
throws
SQLException
{
return
new
ExpertInformation
(
rs
.
getObject
(
"EI_ID"
)
!=
null
?
rs
.
getInt
(
"EI_ID"
)
:
null
,
rs
.
getString
(
"EI_NAME"
),
rs
.
getString
(
"EI_GENDER"
),
rs
.
getString
(
"EI_MAILBOX"
),
rs
.
getString
(
"EI_TELEPHONE"
),
rs
.
getString
(
"EI_USER_NAME"
),
rs
.
getTimestamp
(
"EI_EMPLOYMENT_DATE"
),
rs
.
getString
(
"EI_DEPARTMENT"
),
rs
.
getString
(
"EI_GROUP"
),
rs
.
getString
(
"EI_POSITION"
),
rs
.
getString
(
"EI_SCOPE_BUSINESS"
),
rs
.
getString
(
"EI_STATE"
),
rs
.
getString
(
"EI_SPECIALIZES_FIELDS"
),
rs
.
getString
(
"EI_EXPERT_INTRODUCTION"
),
rs
.
getString
(
"EI_ORGANIZATIONAL_CODE"
),
rs
.
getTimestamp
(
"EI_RECORD_TIME"
),
rs
.
getTimestamp
(
"EI_UPDATE_TIME"
),
rs
.
getString
(
"EI_PHOTO"
),
rs
.
getObject
(
"EI_GROUP_ID"
)
!=
null
?
rs
.
getInt
(
"EI_GROUP_ID"
)
:
null
,
rs
.
getObject
(
"EI_DEPARTMENT_ID"
)
!=
null
?
rs
.
getInt
(
"EI_DEPARTMENT_ID"
)
:
null
,
rs
.
getObject
(
"EI_USER_ID"
)
!=
null
?
rs
.
getInt
(
"EI_USER_ID"
)
:
null
,
rs
.
getBigDecimal
(
"EI_SATISFACTION_SCORE"
),
rs
.
getString
(
"EI_LEVEL"
),
rs
.
getString
(
"EI_DISABLED"
),
rs
.
getString
(
"EI_REGION_CODE"
),
rs
.
getObject
(
"EI_SORT"
)
!=
null
?
rs
.
getInt
(
"EI_SORT"
)
:
null
);
}
}
/**
* 创建查询条件
*/
private
Map
<
String
,
Object
>
createCriteriaSql
(
ExpertInformationCriteria
criteria
)
{
Map
<
String
,
Object
>
andMap
=
new
LinkedHashMap
<>();
if
(
criteria
==
null
)
return
andMap
;
//if (criteria.byId())
// andMap.put(criteria.getId() == null ? " T_Id IS NULL " : " T_Id = ? ", criteria.getId());
//专家姓名
if
(
criteria
.
byName
())
andMap
.
put
(
criteria
.
getName
()
==
null
?
" EI_NAME IS NULL "
:
" EI_NAME = ? "
,
criteria
.
getName
());
//专家姓名(LIKE)
if
(
criteria
.
byNameContain
())
andMap
.
put
(
" EI_NAME LIKE ? "
,
"%"
+
criteria
.
getNameContain
()
+
"%"
);
//专家性别
if
(
criteria
.
byGender
())
andMap
.
put
(
criteria
.
getGender
()
==
null
?
" EI_GENDER IS NULL "
:
" EI_GENDER = ? "
,
criteria
.
getGender
());
//专家性别(LIKE)
if
(
criteria
.
byGenderContain
())
andMap
.
put
(
" EI_GENDER LIKE ? "
,
"%"
+
criteria
.
getGenderContain
()
+
"%"
);
//专家邮箱
if
(
criteria
.
byMailbox
())
andMap
.
put
(
criteria
.
getMailbox
()
==
null
?
" EI_MAILBOX IS NULL "
:
" EI_MAILBOX = ? "
,
criteria
.
getMailbox
());
//专家邮箱(LIKE)
if
(
criteria
.
byMailboxContain
())
andMap
.
put
(
" EI_MAILBOX LIKE ? "
,
"%"
+
criteria
.
getMailboxContain
()
+
"%"
);
//专家电话
if
(
criteria
.
byTelephone
())
andMap
.
put
(
criteria
.
getTelephone
()
==
null
?
" EI_TELEPHONE IS NULL "
:
" EI_TELEPHONE = ? "
,
criteria
.
getTelephone
());
//专家电话(LIKE)
if
(
criteria
.
byTelephoneContain
())
andMap
.
put
(
" EI_TELEPHONE LIKE ? "
,
"%"
+
criteria
.
getTelephoneContain
()
+
"%"
);
//专家OA用户名
if
(
criteria
.
byUserName
())
andMap
.
put
(
criteria
.
getUserName
()
==
null
?
" EI_USER_NAME IS NULL "
:
" EI_USER_NAME = ? "
,
criteria
.
getUserName
());
//专家OA用户名(LIKE)
if
(
criteria
.
byUserNameContain
())
andMap
.
put
(
" EI_USER_NAME LIKE ? "
,
"%"
+
criteria
.
getUserNameContain
()
+
"%"
);
//入职时间
if
(
criteria
.
byEmploymentDate
())
andMap
.
put
(
criteria
.
getEmploymentDate
()
==
null
?
" EI_EMPLOYMENT_DATE IS NULL "
:
" EI_EMPLOYMENT_DATE = ? "
,
criteria
.
getEmploymentDate
());
//专家部门
if
(
criteria
.
byDepartment
())
andMap
.
put
(
criteria
.
getDepartment
()
==
null
?
" EI_DEPARTMENT IS NULL "
:
" EI_DEPARTMENT = ? "
,
criteria
.
getDepartment
());
//专家部门(LIKE)
if
(
criteria
.
byDepartmentContain
())
andMap
.
put
(
" EI_DEPARTMENT LIKE ? "
,
"%"
+
criteria
.
getDepartmentContain
()
+
"%"
);
//专家科室
if
(
criteria
.
byGroup
())
andMap
.
put
(
criteria
.
getGroup
()
==
null
?
" EI_GROUP IS NULL "
:
" EI_GROUP = ? "
,
criteria
.
getGroup
());
//专家科室(LIKE)
if
(
criteria
.
byGroupContain
())
andMap
.
put
(
" EI_GROUP LIKE ? "
,
"%"
+
criteria
.
getGroupContain
()
+
"%"
);
//职位
if
(
criteria
.
byPosition
())
andMap
.
put
(
criteria
.
getPosition
()
==
null
?
" EI_POSITION IS NULL "
:
" EI_POSITION = ? "
,
criteria
.
getPosition
());
//职位(LIKE)
if
(
criteria
.
byPositionContain
())
andMap
.
put
(
" EI_POSITION LIKE ? "
,
"%"
+
criteria
.
getPositionContain
()
+
"%"
);
//业务范围
if
(
criteria
.
byScopeBusiness
())
andMap
.
put
(
criteria
.
getScopeBusiness
()
==
null
?
" EI_SCOPE_BUSINESS IS NULL "
:
" EI_SCOPE_BUSINESS = ? "
,
criteria
.
getScopeBusiness
());
//业务范围(LIKE)
if
(
criteria
.
byScopeBusinessContain
())
andMap
.
put
(
" EI_SCOPE_BUSINESS LIKE ? "
,
"%"
+
criteria
.
getScopeBusinessContain
()
+
"%"
);
//调用状态
if
(
criteria
.
byState
())
andMap
.
put
(
criteria
.
getState
()
==
null
?
" EI_STATE IS NULL "
:
" EI_STATE = ? "
,
criteria
.
getState
());
//调用状态(LIKE)
if
(
criteria
.
byStateContain
())
andMap
.
put
(
" EI_STATE LIKE ? "
,
"%"
+
criteria
.
getStateContain
()
+
"%"
);
//擅长领域
if
(
criteria
.
bySpecializesFields
())
andMap
.
put
(
criteria
.
getSpecializesFields
()
==
null
?
" EI_SPECIALIZES_FIELDS IS NULL "
:
" EI_SPECIALIZES_FIELDS = ? "
,
criteria
.
getSpecializesFields
());
//擅长领域(LIKE)
if
(
criteria
.
bySpecializesFieldsContain
())
andMap
.
put
(
" EI_SPECIALIZES_FIELDS LIKE ? "
,
"%"
+
criteria
.
getSpecializesFieldsContain
()
+
"%"
);
//专家简介
if
(
criteria
.
byExpertIntroduction
())
andMap
.
put
(
criteria
.
getExpertIntroduction
()
==
null
?
" EI_EXPERT_INTRODUCTION IS NULL "
:
" EI_EXPERT_INTRODUCTION = ? "
,
criteria
.
getExpertIntroduction
());
//专家简介(LIKE)
if
(
criteria
.
byExpertIntroductionContain
())
andMap
.
put
(
" EI_EXPERT_INTRODUCTION LIKE ? "
,
"%"
+
criteria
.
getExpertIntroductionContain
()
+
"%"
);
//所属OA组织编码
if
(
criteria
.
byOrganizationalCode
())
andMap
.
put
(
criteria
.
getOrganizationalCode
()
==
null
?
" EI_ORGANIZATIONAL_CODE IS NULL "
:
" EI_ORGANIZATIONAL_CODE = ? "
,
criteria
.
getOrganizationalCode
());
//所属OA组织编码(LIKE)
if
(
criteria
.
byOrganizationalCodeContain
())
andMap
.
put
(
" EI_ORGANIZATIONAL_CODE LIKE ? "
,
"%"
+
criteria
.
getOrganizationalCodeContain
()
+
"%"
);
//专家职称
if
(
criteria
.
byLevel
())
andMap
.
put
(
criteria
.
getLevel
()
==
null
?
" EI_LEVEL IS NULL "
:
" EI_LEVEL = ? "
,
criteria
.
getLevel
());
//专家职称(LIKE)
if
(
criteria
.
byLevelContain
())
andMap
.
put
(
" EI_LEVEL LIKE ? "
,
"%"
+
criteria
.
getLevelContain
()
+
"%"
);
//所属地市
if
(
criteria
.
byRegionCode
())
andMap
.
put
(
criteria
.
getRegionCode
()
==
null
?
" EI_REGION_CODE IS NULL "
:
" EI_REGION_CODE = ? "
,
criteria
.
getRegionCode
());
//所属地市(LIKE)
if
(
criteria
.
byRegionCodeContain
())
andMap
.
put
(
" EI_REGION_CODE LIKE ? "
,
"%"
+
criteria
.
getRegionCodeContain
()
+
"%"
);
return
andMap
;
}
}
src/main/resources/static/pages/test/ai-chat.html
0 → 100644
View file @
6aab2c93
<!DOCTYPE html>
<html
lang=
"zh-CN"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
智能问答
</title>
<link
rel=
"stylesheet"
href=
"style/ai-chat.css"
>
<style>
[
v-cloak
]
{
display
:
none
;
}
</style>
</head>
<body>
<div
id=
"app"
class=
"main-container"
:class=
"{'dark-theme': isDarkTheme}"
v-cloak
>
<!-- 左侧历史对话列表 -->
<div
class=
"sidebar"
>
<div
class=
"sidebar-header"
>
<h1>
智能问答
</h1>
<!-- 添加主题切换按钮 -->
<div
id=
"theme-toggle"
class=
"theme-toggle"
title=
"切换主题"
@
click=
"toggleTheme"
>
<svg
id=
"light-icon"
viewBox=
"0 0 24 24"
:style=
"{display: isDarkTheme ? 'block' : 'none'}"
>
<path
d=
"M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"
></path>
</svg>
<svg
id=
"dark-icon"
viewBox=
"0 0 24 24"
:style=
"{display: isDarkTheme ? 'none' : 'block'}"
>
<path
d=
"M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"
></path>
</svg>
</div>
<button
id=
"new-chat-btn"
class=
"new-chat-btn"
@
click=
"newChat"
>
<span
class=
"plus-icon"
>
+
</span>
新对话
</button>
</div>
<div
class=
"history-list"
>
<div
v-for=
"(section, sectionIndex) in historySections"
:key=
"sectionIndex"
class=
"history-section"
>
<div
class=
"time-label"
>
{{ section.label }}
</div>
<div
v-for=
"(item, itemIndex) in section.items"
:key=
"item.id"
class=
"history-item"
:class=
"{ active: item.active }"
:data-id=
"item.id"
@
click=
"loadChatHistory(item)"
>
<div
class=
"history-title"
>
{{ item.title }}
</div>
<button
class=
"delete-btn"
@
click
.
stop=
"deleteChat(item.id)"
>
<svg
viewBox=
"0 0 24 24"
width=
"16"
height=
"16"
stroke=
"currentColor"
stroke-width=
"2"
fill=
"none"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<path
d=
"M3 6h18"
></path>
<path
d=
"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"
></path>
<path
d=
"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
></path>
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- 右侧聊天区域 -->
<div
class=
"chat-area"
>
<!-- 消息历史区域 -->
<div
id=
"scrollContainer"
class=
"scrollContainer"
>
<div
class=
"fist-loading"
v-if=
"fistLoading"
>
<p>
快速查找
</p>
<div
class=
"expert-guides-container"
>
<div
class=
"expert-guides-scroll"
:style=
"scrollStyle"
>
<div
v-for=
"(item, index) in extendedGuides"
:key=
"index"
class=
"expert-guide-item"
@
click=
"questionClick(item)"
>
<p>
{{ item }}
</p>
</div>
</div>
</div>
</div>
<div
id=
"chat-messages"
class=
"chat-messages"
v-if=
"!fistLoading"
>
<div
v-for=
"(message, index) in messages"
:key=
"index"
class=
"message"
:class=
"message.role + '-message'"
>
<div
class=
"avatar"
>
{{ message.role === 'user' ? '我' : 'AI' }}
</div>
<div
class=
"content"
>
<p
v-html=
"message.content"
></p>
<!--v-html可能会有xss攻击,但是数据来源于大模型,是否需要清洗数据然后再显示?-->
<div
v-if=
"message.typing"
class=
"typing-indicator"
></div>
</div>
</div>
<div
class=
"question"
>
<div
class=
"question_left"
></div>
<div
v-if=
"questions.length"
class=
"question_right"
>
<p>
您可以继续问我:
</p>
<div
class=
"questionContent"
v-for=
"(q, i) in questions"
:key=
"i"
@
click=
"questionClick(q)"
>
<p>
{{ q }}
</p>
</div>
</div>
</div>
</div>
</div>
<!-- 输入区域 -->
<div
class=
"input-area"
>
<textarea
id=
"user-input"
v-model=
"userInput"
placeholder=
"请输入您的问题 shift+enter换行"
rows=
"3"
></textarea>
<div
class=
"input-area-content"
>
<div
style=
"display: flex;align-items: center;justify-content: flex-start;"
>
<div
class=
"custom-select"
v-click-outside=
"closeExpertDropdown"
style=
"display: none"
>
<div
class=
"selected-option"
@
click
.
stop=
"selectExpert('内部专家')"
:class=
"{ 'active': selectedExpert === '内部专家' }"
>
<span>
内部专家
</span>
<!-- <svg class="dropdown-icon" :class="{ 'rotated': showExpertDropdown }" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none">-->
<!-- <polyline points="6 9 12 15 18 9"></polyline>-->
<!-- </svg>-->
</div>
<!-- <div class="dropdown-menu" v-show="showExpertDropdown">-->
<!-- <div class="dropdown-item" @click.stop="selectExpert('内部专家')" :class="{ 'active': selectedExpert === '内部专家' }">-->
<!-- <span>内部专家</span>-->
<!-- </div>-->
<!--<!– <div class="dropdown-item" @click.stop="selectExpert('外部专家')" :class="{ 'active': selectedExpert === '外部专家' }">–>-->
<!--<!– <span>外部专家</span>–>-->
<!--<!– </div>–>-->
<!-- </div>-->
</div>
<div
class=
"custom-select"
v-click-outside=
"closeExpertDropdown"
style=
"display: none"
>
<div
class=
"selected-option"
@
click
.
stop=
"selectExpert('外部专家')"
:class=
"{ 'active': selectedExpert === '外部专家' }"
>
<span>
外部专家
</span>
</div>
</div>
<div
class=
"custom-select"
v-click-outside=
"closeOrgDropdown"
v-show=
"showOrgSelection"
>
<div
class=
"selected-option"
@
click
.
stop=
"toggleOrgDropdown"
style=
"background-color: rgba(230, 220, 250, 0.5);color: #6633ff;"
>
<span>
{{ selectedOrg }}
</span>
<svg
class=
"dropdown-icon"
:class=
"{ 'rotated': showOrgDropdown }"
viewBox=
"0 0 24 24"
width=
"16"
height=
"16"
stroke=
"currentColor"
stroke-width=
"2"
fill=
"none"
>
<polyline
points=
"6 9 12 15 18 9"
></polyline>
</svg>
</div>
<div
class=
"dropdown-menu"
v-show=
"showOrgDropdown"
>
<div
class=
"dropdown-item"
@
click
.
stop=
"selectOrg('全部组织')"
:class=
"{ 'active': selectedOrg === '全部组织' }"
>
<span>
全部
</span>
</div>
<div
class=
"dropdown-item"
@
click
.
stop=
"selectOrg('组织内')"
:class=
"{ 'active': selectedOrg === '组织内' }"
>
<span>
组织内
</span>
</div>
<div
class=
"dropdown-item"
@
click
.
stop=
"selectOrg('组织外')"
:class=
"{ 'active': selectedOrg === '组织外' }"
>
<span>
组织外
</span>
</div>
</div>
</div>
</div>
<div>
<button
id=
"send-btn"
class=
"send-btn"
@
click=
"sendMessage"
v-show=
"!isResponding"
>
<svg
class=
"send-icon"
viewBox=
"0 0 24 24"
width=
"18"
height=
"18"
stroke=
"currentColor"
stroke-width=
"2"
fill=
"none"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<line
x1=
"12"
y1=
"19"
x2=
"12"
y2=
"5"
></line>
<polyline
points=
"5 12 12 5 19 12"
></polyline>
</svg>
</button>
<button
id=
"stop-btn"
class=
"stop-btn"
@
click=
"stopResponse"
v-show=
"isResponding"
>
<svg
viewBox=
"0 0 24 24"
width=
"18"
height=
"18"
stroke=
"currentColor"
stroke-width=
"2"
fill=
"none"
stroke-linecap=
"round"
stroke-linejoin=
"round"
class=
"stop-icon"
>
<rect
x=
"6"
y=
"6"
width=
"12"
height=
"12"
rx=
"2"
ry=
"2"
></rect>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
<script
type=
"text/javascript"
src=
"../../libs/require.js/require.min.js"
></script>
<script
type=
"text/javascript"
src=
"../../scripts/require-config.js"
></script>
<!-- 引入Vue相关JS -->
<script
type=
"text/javascript"
src=
"js/ai-chat-vue.js"
></script>
</body>
</html>
\ No newline at end of file
src/main/resources/static/pages/test/images/reload.png
0 → 100644
View file @
6aab2c93
1.94 KB
src/main/resources/static/pages/test/images/service_head.png
0 → 100644
View file @
6aab2c93
640 Bytes
src/main/resources/static/pages/test/images/service_img1.png
0 → 100644
View file @
6aab2c93
600 Bytes
src/main/resources/static/pages/test/images/service_img2.png
0 → 100644
View file @
6aab2c93
265 Bytes
src/main/resources/static/pages/test/images/service_img3.png
0 → 100644
View file @
6aab2c93
528 Bytes
src/main/resources/static/pages/test/images/service_img4.png
0 → 100644
View file @
6aab2c93
659 Bytes
src/main/resources/static/pages/test/images/service_img5.png
0 → 100644
View file @
6aab2c93
649 Bytes
src/main/resources/static/pages/test/images/service_img6.png
0 → 100644
View file @
6aab2c93
703 Bytes
src/main/resources/static/pages/test/images/user_head.png
0 → 100644
View file @
6aab2c93
10.8 KB
src/main/resources/static/pages/test/js/ai-chat-vue.js
0 → 100644
View file @
6aab2c93
/**
* AI聊天页面Vue应用
*/
require
([
'jquery'
,
'vue'
,
'utils'
,
'marked'
,
'markdown'
,
'global'
],
function
(
$
,
Vue
,
utils
,
marked
,
markdown
)
{
// 添加点击外部关闭指令
Vue
.
directive
(
'click-outside'
,
{
bind
:
function
(
el
,
binding
,
vnode
)
{
el
.
clickOutsideEvent
=
function
(
event
)
{
if
(
!
(
el
==
event
.
target
||
el
.
contains
(
event
.
target
)))
{
vnode
.
context
[
binding
.
expression
](
event
);
}
};
document
.
body
.
addEventListener
(
'click'
,
el
.
clickOutsideEvent
);
},
unbind
:
function
(
el
)
{
document
.
body
.
removeEventListener
(
'click'
,
el
.
clickOutsideEvent
);
}
});
const
app
=
new
Vue
({
el
:
'#app'
,
data
:
{
// 用户相关数据
currentLoginUser
:
{},
fistLoading
:
true
,
// 聊天相关数据
chatHistory
:
[],
sessionId
:
""
,
currentEventSource
:
null
,
// UI相关数据
theme
:
localStorage
.
getItem
(
'ai-chat-theme'
)
||
'light'
,
isResponding
:
false
,
userInput
:
""
,
// 专家选择相关数据
selectedExpert
:
'内部专家'
,
showExpertDropdown
:
false
,
// 组织内网选择相关数据
selectedOrg
:
'全部组织'
,
showOrgDropdown
:
false
,
questions
:[],
guides
:[
'引上光缆在维护下架里面是否能算距离。'
,
'保险是否有雇主险要求。'
,
'线路迁改列投资是否有统一规范的原则?'
,
'短距离的管道的维护和整治费用,如何计取?'
],
scrollOffset
:
0
,
scrollInterval
:
null
,
transitioning
:
true
,
// 历史对话分类
historySections
:
[
],
// 消息列表
messages
:
[
// { role: 'ai', content: '您好!我是您的专家推荐助手,有什么可以帮助您的吗?' }
],
showOrgSelection
:
false
},
computed
:
{
isDarkTheme
()
{
return
this
.
theme
===
'dark'
;
},
extendedGuides
()
{
// 克隆前3项到末尾
return
[...
this
.
guides
,
...
this
.
guides
.
slice
(
0
,
3
)];
},
scrollStyle
()
{
return
{
transform
:
`translateY(-
${
this
.
scrollOffset
}
px)`
,
transition
:
this
.
transitioning
?
'transform 0.5s ease'
:
'none'
,
};
}
},
created
:
function
()
{
this
.
currentUser
();
this
.
getSessionId
();
this
.
getConversationHistory
();
},
mounted
:
function
()
{
// 监听输入框的键盘事件
this
.
$nextTick
(()
=>
{
const
textarea
=
document
.
getElementById
(
'user-input'
);
if
(
textarea
)
{
textarea
.
addEventListener
(
'keypress'
,
this
.
handleKeyPress
);
}
// 启动自动滚动
this
.
startAutoScroll
();
// 添加鼠标悬停事件监听
this
.
$watch
(
'fistLoading'
,
(
newVal
)
=>
{
if
(
newVal
)
{
// 等待DOM更新
this
.
$nextTick
(()
=>
{
const
guideItems
=
document
.
querySelectorAll
(
'.expert-guide-item'
);
guideItems
.
forEach
(
item
=>
{
item
.
addEventListener
(
'mouseenter'
,
this
.
pauseAutoScroll
);
item
.
addEventListener
(
'mouseleave'
,
this
.
resumeAutoScroll
);
});
});
}
},
{
immediate
:
true
});
});
},
beforeDestroy
:
function
()
{
// 清除自动滚动定时器
this
.
stopAutoScroll
();
// 移除事件监听器
const
guideItems
=
document
.
querySelectorAll
(
'.expert-guide-item'
);
guideItems
.
forEach
(
item
=>
{
item
.
removeEventListener
(
'mouseenter'
,
this
.
pauseAutoScroll
);
item
.
removeEventListener
(
'mouseleave'
,
this
.
resumeAutoScroll
);
});
},
methods
:
{
// 自动滚动相关方法
startAutoScroll
:
function
()
{
const
itemHeight
=
80
;
const
visibleItems
=
3
;
const
totalItems
=
this
.
guides
.
length
;
this
.
scrollInterval
=
setInterval
(()
=>
{
this
.
transitioning
=
true
;
this
.
scrollOffset
+=
itemHeight
;
// 判断是否滚动到克隆项部分(即第 totalItems 行之后)
if
(
this
.
scrollOffset
>=
itemHeight
*
(
totalItems
))
{
// 短暂延迟后瞬间回到原始位置
setTimeout
(()
=>
{
this
.
transitioning
=
false
;
this
.
scrollOffset
=
0
;
},
500
);
// 等待动画结束
}
},
2000
);
},
stopAutoScroll
:
function
()
{
if
(
this
.
scrollInterval
)
{
clearInterval
(
this
.
scrollInterval
);
this
.
scrollInterval
=
null
;
}
},
pauseAutoScroll
:
function
()
{
this
.
stopAutoScroll
();
},
resumeAutoScroll
:
function
()
{
if
(
!
this
.
scrollInterval
&&
this
.
fistLoading
)
{
this
.
startAutoScroll
();
}
},
// 用户相关方法
currentUser
:
function
()
{
const
that
=
this
;
$
.
ajax
({
url
:
"../../auth/current-user"
,
type
:
"get"
,
dataType
:
"json"
,
contentType
:
"application/json;charset=UTF-8"
,
async
:
false
,
success
:
function
(
data
)
{
that
.
currentLoginUser
=
data
.
data
;
}
});
},
// 主题相关方法
toggleTheme
()
{
this
.
theme
=
this
.
theme
===
'light'
?
'dark'
:
'light'
;
localStorage
.
setItem
(
'ai-chat-theme'
,
this
.
theme
);
document
.
body
.
classList
.
toggle
(
'dark-theme'
,
this
.
theme
===
'dark'
);
},
// 会话相关方法
async
getSessionId
()
{
try
{
//const response = await fetch('../../api/langchain/getSessionId');
const
response
=
await
fetch
(
'../../api/langchain/getDialogId'
);
const
dataJson
=
await
response
.
json
();
this
.
sessionId
=
dataJson
.
data
;
}
catch
(
error
)
{
console
.
error
(
'会话ID获取失败'
,
error
);
}
},
async
getConversationHistory
()
{
try
{
//const response = await fetch('../../api/langchain/getSessionId');
// const response = await fetch('../../api/langchain/conversationHistory');
// const dataJson = await response.json();
// this.historySections = dataJson.data;
}
catch
(
error
)
{
console
.
error
(
'会话获取失败'
,
error
);
}
},
// 聊天相关方法
handleKeyPress
(
e
)
{
if
(
e
.
key
===
'Enter'
&&
!
e
.
shiftKey
)
{
e
.
preventDefault
();
this
.
sendMessage
();
}
},
questionClick
:
function
(
message
){
this
.
userInput
=
message
;
this
.
sendMessage
();
},
sendMessage
()
{
// if (!this.selectedExpert) {
// this.showToast('请先选择专家类型(内部/外部专家)');
// return;
// }
const
message
=
this
.
userInput
.
trim
();
if
(
!
message
)
return
;
if
(
this
.
fistLoading
)
{
this
.
fistLoading
=
false
;
// 停止自动滚动
this
.
stopAutoScroll
();
}
this
.
questions
=
[];
this
.
stopResponse
();
// 添加用户消息
this
.
addMessage
(
'user'
,
message
);
this
.
userInput
=
''
;
// 显示终止按钮,隐藏发送按钮
this
.
isResponding
=
true
;
// 调用API获取响应
this
.
connectSSE
(
message
);
},
stopResponse
()
{
if
(
this
.
currentEventSource
)
{
this
.
currentEventSource
.
close
();
this
.
currentEventSource
=
null
;
// 切换回发送按钮
this
.
isResponding
=
false
;
// 在最后一条AI消息后添加"(已终止)"标记
const
aiMessages
=
this
.
messages
.
filter
(
msg
=>
msg
.
role
===
'ai'
);
if
(
aiMessages
.
length
>
0
)
{
const
lastAIMessage
=
aiMessages
[
aiMessages
.
length
-
1
];
lastAIMessage
.
typing
=
false
;
if
(
!
lastAIMessage
.
content
.
includes
(
'(已手动结束回答)'
))
{
lastAIMessage
.
content
+=
' (已手动结束回答)'
;
}
}
}
},
addMessage
(
role
,
content
)
{
this
.
messages
.
push
({
role
,
content
});
this
.
chatHistory
.
push
({
role
,
content
});
// 自动滚动到底部
this
.
$nextTick
(()
=>
{
const
messagesDiv
=
document
.
getElementById
(
'scrollContainer'
);
if
(
messagesDiv
)
{
messagesDiv
.
scrollTop
=
messagesDiv
.
scrollHeight
;
}
});
},
connectSSE
(
chatMessage
)
{
// 在消息列表中添加一个带"正在输入"指示器的AI消息
const
aiMessageIndex
=
this
.
messages
.
length
;
this
.
messages
.
push
({
role
:
'ai'
,
content
:
''
,
typing
:
true
});
// 自动滚动到底部
this
.
$nextTick
(()
=>
{
const
messagesDiv
=
document
.
getElementById
(
'scrollContainer'
);
if
(
messagesDiv
)
{
messagesDiv
.
scrollTop
=
messagesDiv
.
scrollHeight
;
}
});
// 连接SSE
this
.
currentEventSource
=
new
EventSource
(
'../../api/langchain/sseTest?chatMessage='
+
chatMessage
+
"&dialogId="
+
this
.
sessionId
+
"&selectedExpert="
+
this
.
selectedExpert
+
"&selectedOrg="
+
this
.
selectedOrg
);
//sseIntelligent
let
responseText
=
''
;
var
md
=
new
markdown
({
html
:
true
,
// 允许解析 HTML 标签
linkify
:
true
,
// 自动识别链接
typographer
:
true
,
// 启用排版优化
breaks
:
true
,
// 将单个换行符视为换行
});
this
.
currentEventSource
.
onmessage
=
(
event
)
=>
{
const
data
=
JSON
.
parse
(
event
.
data
);
const
content
=
data
.
dataToSend
[
1
].
data
;
if
(
content
!==
"stop"
)
{
const
match
=
content
.
match
(
/SUGGEST
\[(
.*
?)\]
SUGGEST/
);
if
(
match
)
{
const
suggestionsJson
=
`[
${
match
[
1
]}
]`
;
const
suggestions
=
JSON
.
parse
(
suggestionsJson
);
if
(
Array
.
isArray
(
suggestions
))
{
this
.
questions
=
suggestions
;
}
}
else
{
//提示词不展示
responseText
+=
content
;
}
this
.
messages
[
aiMessageIndex
].
content
=
marked
.
parse
(
responseText
);
//md.render(responseText);
}
else
{
// 移除输入指示器
this
.
messages
[
aiMessageIndex
].
typing
=
false
;
this
.
chatHistory
.
push
({
role
:
'ai'
,
content
:
responseText
});
// 切换回发送按钮
this
.
isResponding
=
false
;
// 关闭事件源
this
.
currentEventSource
.
close
();
this
.
currentEventSource
=
null
;
}
// 自动滚动到底部
this
.
$nextTick
(()
=>
{
const
messagesDiv
=
document
.
getElementById
(
'scrollContainer'
);
if
(
messagesDiv
)
{
messagesDiv
.
scrollTop
=
messagesDiv
.
scrollHeight
;
}
});
};
this
.
currentEventSource
.
onerror
=
()
=>
{
console
.
error
(
'SSE连接异常'
);
// 移除输入指示器,显示错误信息
this
.
messages
[
aiMessageIndex
].
typing
=
false
;
this
.
messages
[
aiMessageIndex
].
content
=
responseText
||
'抱歉,连接出现问题,请稍后再试。'
;
// 切换回发送按钮
this
.
isResponding
=
false
;
// 关闭事件源
this
.
currentEventSource
.
close
();
this
.
currentEventSource
=
null
;
};
},
clearChat
()
{
// 清空消息,保留欢迎消息
this
.
messages
=
[
{
role
:
'ai'
,
content
:
'您好!我是您的AI助手,有什么可以帮助您的吗?'
}
];
// 清空历史记录
this
.
chatHistory
=
[];
},
newChat
()
{
// 终止当前响应(如果有)
if
(
this
.
currentEventSource
)
{
this
.
currentEventSource
.
close
();
this
.
currentEventSource
=
null
;
this
.
isResponding
=
false
;
}
this
.
questions
=
[];
// 获取新的会话ID并清空对话
this
.
getSessionId
().
then
(()
=>
{
this
.
clearChat
();
// 这里可以添加将新对话添加到历史列表的逻辑
// this.addChatToHistory('新对话', new Date());
});
this
.
fistLoading
=
true
;
// this.selectedExpert = '内部专家';
// this.showOrgSelection = this.selectedExpert === '内部专家';
// this.selectedOrg = '全部组织';
// 重置滚动位置并重新启动自动滚动
this
.
scrollOffset
=
0
;
this
.
startAutoScroll
();
},
loadChatHistory
(
chat
)
{
var
that
=
this
var
chatId
=
chat
.
id
;
// 关闭所有菜单
this
.
historySections
.
forEach
(
section
=>
{
section
.
items
.
forEach
(
item
=>
{
item
.
showMenu
=
false
;
});
});
//this.addMessage('user', "123456");
// 设置活跃状态
this
.
historySections
.
forEach
(
section
=>
{
section
.
items
.
forEach
(
item
=>
{
item
.
active
=
(
item
.
id
===
chatId
);
});
});
//
this
.
sessionId
=
chatId
;
// this.clearChat();
this
.
questions
=
[];
this
.
messages
=
[];
// 如果正在显示初始推荐,停止自动滚动
if
(
this
.
fistLoading
)
{
this
.
stopAutoScroll
();
}
this
.
fistLoading
=
false
;
// this.selectedExpert = '内部专家';
// this.showOrgSelection = this.selectedExpert === '内部专家';
// this.selectedOrg = '全部组织';
//这里添加加载对应对话历史的逻辑
//实际实现时可以调用API获取历史记录
$
.
ajax
({
url
:
"../../api/langchain/conversationMessages?sessionId="
+
chatId
,
type
:
"get"
,
dataType
:
"json"
,
contentType
:
"application/json;charset=UTF-8"
,
async
:
false
,
success
:
function
(
data
)
{
var
conversationMessages
=
data
.
data
;
if
(
conversationMessages
&&
conversationMessages
.
length
>
0
){
that
.
fistLoading
=
false
;
conversationMessages
.
forEach
(
section
=>
{
that
.
addMessage
(
section
.
role
,
section
.
content
);
});
}
}
});
},
// 删除对话
deleteChat
(
chatId
)
{
// 关闭菜单
this
.
historySections
.
forEach
(
section
=>
{
const
item
=
section
.
items
.
find
(
item
=>
item
.
id
===
chatId
);
if
(
item
)
{
item
.
showMenu
=
false
;
}
});
// 从历史记录中删除
this
.
historySections
.
forEach
(
section
=>
{
section
.
items
=
section
.
items
.
filter
(
item
=>
item
.
id
!==
chatId
);
});
// 如果删除的是当前活跃的对话,则清空聊天记录
const
isActiveChat
=
this
.
historySections
.
some
(
section
=>
section
.
items
.
some
(
item
=>
item
.
id
===
chatId
&&
item
.
active
)
);
if
(
isActiveChat
)
{
this
.
clearChat
();
}
$
.
ajax
({
url
:
"../../api/langchain/deleteChat"
,
type
:
"post"
,
dataType
:
"json"
,
contentType
:
"application/json;charset=UTF-8"
,
data
:
chatId
,
async
:
false
,
success
:
function
(
data
)
{
}
});
},
// 专家选择相关方法
toggleExpertDropdown
()
{
this
.
showExpertDropdown
=
!
this
.
showExpertDropdown
;
},
closeExpertDropdown
()
{
this
.
showExpertDropdown
=
false
;
},
selectExpert
(
expert
)
{
// this.selectedExpert = expert;
if
(
this
.
selectedExpert
===
expert
)
{
this
.
selectedExpert
=
''
;
}
else
{
this
.
selectedExpert
=
expert
;
}
this
.
showOrgSelection
=
expert
===
'内部专家'
;
this
.
selectedOrg
=
'全部组织'
;
// 立即关闭下拉框
this
.
showExpertDropdown
=
false
;
},
//组织内外选择相关方法
toggleOrgDropdown
()
{
this
.
showOrgDropdown
=
!
this
.
showOrgDropdown
;
},
closeOrgDropdown
()
{
this
.
showOrgDropdown
=
false
;
},
selectOrg
(
org
)
{
this
.
selectedOrg
=
org
;
// 立即关闭下拉框
this
.
showOrgDropdown
=
false
;
},
showToast
(
message
)
{
// 使用你项目中已有的提示组件,或创建一个简单的提示
const
toast
=
document
.
createElement
(
'div'
);
toast
.
className
=
'expert-toast'
;
toast
.
textContent
=
message
;
document
.
body
.
appendChild
(
toast
);
setTimeout
(()
=>
{
toast
.
remove
();
},
3000
);
}
}
});
});
\ No newline at end of file
src/main/resources/static/pages/test/style/ai-chat.css
0 → 100644
View file @
6aab2c93
/* 全局样式重置 */
*
{
margin
:
0
;
padding
:
0
;
box-sizing
:
border-box
;
font-family
:
'PingFang SC'
,
'Microsoft YaHei'
,
sans-serif
;
}
:root
{
/* 浅色主题变量 */
--bg-color
:
#f5f7fa
;
--sidebar-bg
:
#fff
;
--sidebar-border
:
#e8e8e8
;
--primary-color
:
#1890ff
;
--primary-hover
:
#40a9ff
;
--text-color
:
#333
;
--text-secondary
:
#8c8c8c
;
--message-bg
:
#fff
;
--message-user-bg
:
#f5f7fa
;
--message-border
:
#e8e8e8
;
--input-area-bg
:
#fff
;
--hover-bg
:
#f0f2f5
;
--active-bg
:
#e6f7ff
;
--avatar-bg
:
#1890ff
;
--avatar-user-bg
:
#722ed1
;
--scrollbar-track
:
#f1f1f1
;
--scrollbar-thumb
:
#c1c1c1
;
--scrollbar-hover
:
#a8a8a8
;
--box-shadow
:
rgba
(
0
,
0
,
0
,
0.08
);
--question-text
:
#676c90
;
}
.dark-theme
{
/* 深色主题变量 */
--bg-color
:
#1f1f1f
;
--sidebar-bg
:
#2d2d2d
;
--sidebar-border
:
#3a3a3a
;
--primary-color
:
#177ddc
;
--primary-hover
:
#3c9ae8
;
--text-color
:
#e0e0e0
;
--text-secondary
:
#aaaaaa
;
--message-bg
:
#2d2d2d
;
--message-user-bg
:
#363636
;
--message-border
:
#404040
;
--input-area-bg
:
#363636
;
--hover-bg
:
#404040
;
--active-bg
:
#1a365d
;
--avatar-bg
:
#177ddc
;
--avatar-user-bg
:
#722ed1
;
--scrollbar-track
:
#2d2d2d
;
--scrollbar-thumb
:
#555555
;
--scrollbar-hover
:
#777777
;
--box-shadow
:
rgba
(
0
,
0
,
0
,
0.2
);
--question-text
:
#dbdef8
;
}
body
{
background-color
:
var
(
--bg-color
);
color
:
var
(
--text-color
);
line-height
:
1.6
;
height
:
100vh
;
overflow
:
hidden
;
}
/* 主容器样式 */
.main-container
{
display
:
flex
;
height
:
100vh
;
width
:
100%
;
overflow
:
hidden
;
}
/* 左侧边栏样式 */
.sidebar
{
width
:
280px
;
background-color
:
var
(
--sidebar-bg
);
border-right
:
1px
solid
var
(
--sidebar-border
);
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
}
.sidebar-header
{
padding
:
16px
;
border-bottom
:
1px
solid
var
(
--sidebar-border
);
position
:
relative
;
}
.sidebar-header
h1
{
font-size
:
1.2rem
;
font-weight
:
600
;
color
:
var
(
--primary-color
);
margin-bottom
:
16px
;
}
.new-chat-btn
{
width
:
100%
;
padding
:
10px
;
background-color
:
var
(
--primary-color
);
color
:
white
;
border
:
none
;
border-radius
:
6px
;
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-weight
:
500
;
transition
:
background-color
0.3s
;
}
.new-chat-btn
:hover
{
background-color
:
var
(
--primary-hover
);
}
.plus-icon
{
margin-right
:
8px
;
font-size
:
16px
;
font-weight
:
bold
;
}
/* 主题切换按钮 */
.theme-toggle
{
position
:
absolute
;
right
:
16px
;
top
:
16px
;
cursor
:
pointer
;
width
:
30px
;
height
:
30px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
border-radius
:
50%
;
transition
:
background-color
0.2s
;
}
.theme-toggle
:hover
{
background-color
:
var
(
--hover-bg
);
}
.theme-toggle
svg
{
width
:
18px
;
height
:
18px
;
fill
:
var
(
--text-secondary
);
}
/* 历史对话列表样式 */
.history-list
{
flex
:
1
;
overflow-y
:
auto
;
padding
:
10px
;
scrollbar-width
:
thin
;
scrollbar-color
:
var
(
--scrollbar-thumb
)
var
(
--scrollbar-track
);
max-height
:
calc
(
100vh
-
90px
);
}
.history-section
{
margin-bottom
:
16px
;
}
.time-label
{
font-size
:
0.8rem
;
color
:
var
(
--text-secondary
);
padding
:
5px
10px
;
margin-bottom
:
5px
;
}
.history-item
{
padding
:
10px
;
border-radius
:
6px
;
cursor
:
pointer
;
transition
:
background-color
0.2s
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.history-item
:hover
{
background-color
:
var
(
--hover-bg
);
}
.history-item.active
{
background-color
:
var
(
--active-bg
);
border-left
:
3px
solid
var
(
--primary-color
);
}
.history-title
{
font-size
:
0.9rem
;
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
max-width
:
180px
;
color
:
var
(
--text-color
);
}
.delete-btn
{
background
:
none
;
border
:
none
;
cursor
:
pointer
;
padding
:
5px
;
opacity
:
0.5
;
transition
:
opacity
0.2s
;
color
:
red
;
}
.delete-btn
:hover
{
opacity
:
1
;
}
.delete-btn
svg
{
display
:
block
;
}
.history-time
{
font-size
:
0.75rem
;
color
:
var
(
--text-secondary
);
}
/* 右侧聊天区域 */
.fist-loading
{
width
:
900px
;
margin
:
8%
auto
10px
;
}
.fist-loading
>
p
{
color
:
var
(
--primary-color
);
font-weight
:
bold
;
font-size
:
20px
;
width
:
500px
;
margin
:
0
auto
;
}
.expert-guides-container
{
width
:
500px
;
height
:
240px
;
/* 高度为每条推荐项高度的3倍 */
margin
:
0
auto
;
overflow
:
hidden
;
position
:
relative
;
}
.expert-guides-scroll
{
width
:
100%
;
position
:
absolute
;
transition
:
transform
0.5s
ease
;
}
.expert-guide-item
{
width
:
500px
;
height
:
70px
;
line-height
:
70px
;
border-radius
:
16px
;
padding
:
0
16px
;
background-color
:
var
(
--sidebar-bg
);
border
:
1px
solid
var
(
--box-shadow
);
/*box-shadow: 0 1px 8px var(--box-shadow);*/
/*box-sizing: border-box;*/
align-items
:
center
;
margin
:
10px
auto
0
;
font-size
:
16px
;
cursor
:
pointer
;
color
:
var
(
--question-text
);
}
.expert-guide-item
:hover
{
background-color
:
#e5eaf6
;
color
:
#475ada
;
}
.chat-area
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
position
:
relative
;
height
:
100vh
;
overflow-y
:
auto
;
/* 使整个聊天区域可滚动,滚动条显示在最右边 */
overflow-x
:
hidden
;
background-color
:
var
(
--bg-color
);
}
.scrollContainer
{
width
:
100%
;
overflow-y
:
auto
;
/* 让内容继续流动 */
height
:
calc
(
100vh
-
150px
);
/* 确保占据足够高度 */
overflow-x
:
hidden
;
padding-top
:
20px
;
}
/* 聊天消息区域 */
.chat-messages
{
width
:
900px
;
margin
:
0
auto
10px
;
}
/* 输入区域 */
.input-area
{
width
:
900px
;
max-width
:
95%
;
margin
:
0
auto
30px
auto
;
padding
:
8px
10px
;
display
:
flex
;
background-color
:
var
(
--input-area-bg
);
border-radius
:
15px
;
box-shadow
:
0
1px
8px
var
(
--box-shadow
);
position
:
sticky
;
bottom
:
30px
;
flex-shrink
:
0
;
/* 防止被压缩 */
flex-direction
:
column
;
justify-content
:
flex-start
;
}
.input-area-content
{
display
:
flex
;
justify-content
:
space-between
;
padding-left
:
10px
;
}
/* 单条消息样式 */
.message
{
display
:
flex
;
margin-bottom
:
20px
;
align-items
:
flex-start
;
}
/* 用户消息 */
.question
{
display
:
flex
;
justify-content
:
flex-start
;
}
.question_left
{
width
:
40px
;
margin
:
0
10px
;
}
.question_right
{
padding
:
0
6px
;
}
.question_right
>
p
{
font-size
:
14px
;
color
:
var
(
--question-text
);
}
.questionContent
{
font-size
:
13px
;
color
:
var
(
--question-text
);
background-color
:
var
(
--input-area-bg
);
border-radius
:
6px
;
box-shadow
:
0
16px
20px
0
rgba
(
174
,
167
,
223
,
.06
);
line-height
:
20px
;
max-width
:
800px
;
overflow
:
hidden
;
padding
:
8px
16px
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
width
:
-moz-fit-content
;
width
:
fit-content
;
margin
:
10px
0
;
cursor
:
pointer
;
}
.questionContent
:hover
{
background-color
:
#e5eaf6
;
color
:
#475ada
;
}
.user-message
{
flex-direction
:
row-reverse
;
}
.avatar
{
width
:
40px
;
height
:
40px
;
border-radius
:
50%
;
background-color
:
var
(
--avatar-bg
);
color
:
white
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-weight
:
bold
;
flex-shrink
:
0
;
margin
:
0
10px
;
}
.user-message
.avatar
{
background-color
:
var
(
--avatar-user-bg
);
}
.message
.content
{
max-width
:
87%
;
padding
:
12px
16px
;
border-radius
:
12px
;
box-shadow
:
0
1px
2px
var
(
--box-shadow
);
}
.ai-message
.content
{
background-color
:
var
(
--message-bg
);
border-top-left-radius
:
0
;
}
.user-message
.content
{
background-color
:
var
(
--message-user-bg
);
border
:
1px
solid
var
(
--message-border
);
color
:
var
(
--text-color
);
border-top-right-radius
:
0
;
}
.content
p
{
white-space
:
pre-wrap
;
word-break
:
break-word
;
color
:
var
(
--text-color
);
}
#user-input
{
flex
:
1
;
padding
:
8px
10px
;
border
:
none
;
border-radius
:
0
;
resize
:
none
;
outline
:
none
;
height
:
100px
;
max-height
:
150px
;
background-color
:
transparent
;
transition
:
all
0.3s
;
margin-right
:
8px
;
line-height
:
20px
;
box-shadow
:
none
;
overflow-y
:
auto
;
color
:
var
(
--text-color
);
}
#user-input
:focus
{
box-shadow
:
none
;
}
#user-input
::placeholder
{
color
:
var
(
--text-secondary
);
}
.send-btn
,
.stop-btn
{
width
:
36px
;
height
:
36px
;
min-height
:
36px
;
background-color
:
var
(
--primary-color
);
color
:
white
;
border
:
none
;
border-radius
:
50%
;
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
transition
:
all
0.3s
;
padding
:
0
;
}
.send-btn
:hover
,
.stop-btn
:hover
{
background-color
:
var
(
--primary-hover
);
}
.stop-btn
{
background-color
:
#ff4d4f
;
}
.stop-btn
:hover
{
background-color
:
#ff7875
;
}
.stop-icon
,
.send-icon
{
width
:
18px
;
height
:
18px
;
stroke
:
white
;
}
/* 打字指示器样式 */
.typing-indicator
{
display
:
inline-block
;
position
:
relative
;
min-height
:
20px
;
font-size
:
25px
;
font-weight
:
bold
;
}
.typing-indicator
::after
{
content
:
"···"
;
animation
:
typing
1.5s
infinite
;
}
@keyframes
typing
{
0
%,
100
%
{
content
:
"."
;
}
33
%
{
content
:
".."
;
}
66
%
{
content
:
"..."
;
}
}
@media
(
max-width
:
1190px
){
.chat-messages
{
width
:
800px
;
}
}
@media
(
max-width
:
1090px
){
.chat-messages
{
width
:
700px
;
}
}
@media
(
max-width
:
990px
){
.chat-messages
{
width
:
600px
;
}
}
/* 响应式设计 */
@media
(
max-width
:
768px
)
{
.sidebar
{
position
:
absolute
;
left
:
-280px
;
height
:
100vh
;
z-index
:
10
;
transition
:
left
0.3s
;
}
.sidebar.visible
{
left
:
0
;
}
.chat-messages
,
.input-area
{
width
:
100%
;
max-width
:
100%
;
}
.message
.content
{
max-width
:
85%
;
}
}
/* 滚动条样式 */
::-webkit-scrollbar
{
width
:
6px
;
}
::-webkit-scrollbar-track
{
background
:
var
(
--scrollbar-track
);
}
::-webkit-scrollbar-thumb
{
background
:
var
(
--scrollbar-thumb
);
border-radius
:
3px
;
}
::-webkit-scrollbar-thumb:hover
{
background
:
var
(
--scrollbar-hover
);
}
/* 动画效果 */
.message
{
animation
:
fadeIn
0.3s
ease-out
;
}
@keyframes
fadeIn
{
from
{
opacity
:
0
;
transform
:
translateY
(
10px
);
}
to
{
opacity
:
1
;
transform
:
translateY
(
0
);
}
}
/* 自定义选择器样式 */
.custom-select
{
position
:
relative
;
width
:
auto
;
min-width
:
70px
;
cursor
:
pointer
;
user-select
:
none
;
margin-right
:
10px
;
margin-left
:
0
;
}
.selected-option
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
2px
5px
;
border-radius
:
8px
;
/*background-color: rgba(230, 220, 250, 0.5);*/
background-color
:
#f5f6fa
;
/*color: #6633ff;*/
color
:
#4c4c4c
;
font-size
:
14px
;
transition
:
all
0.2s
;
}
.selected-option
span
{
margin-right
:
2px
;
text-align
:
center
;
display
:
inline-block
;
width
:
100%
;
}
.dark-theme
.selected-option
{
background-color
:
rgba
(
130
,
100
,
200
,
0.2
);
color
:
#9980ff
;
}
.selected-option
:hover
{
background-color
:
rgba
(
210
,
200
,
250
,
0.7
);
}
.dark-theme
.selected-option
:hover
{
background-color
:
rgba
(
150
,
120
,
220
,
0.3
);
}
.dropdown-icon
{
transition
:
transform
0.2s
;
margin-left
:
2px
;
flex-shrink
:
0
;
stroke
:
#6633ff
;
}
.dark-theme
.dropdown-icon
{
stroke
:
#9980ff
;
}
.dropdown-icon.rotated
{
transform
:
rotate
(
180deg
);
}
.dropdown-menu
{
position
:
absolute
;
bottom
:
100%
;
left
:
0
;
width
:
100%
;
margin-bottom
:
5px
;
background-color
:
var
(
--message-bg
);
border-radius
:
8px
;
box-shadow
:
0
2px
10px
var
(
--box-shadow
);
z-index
:
100
;
overflow
:
hidden
;
}
.dropdown-item
{
padding
:
6px
8px
;
transition
:
background-color
0.2s
;
font-size
:
13px
;
color
:
var
(
--text-color
);
text-align
:
center
;
}
.dropdown-item
:hover
{
background-color
:
var
(
--hover-bg
);
}
.dropdown-item.active
{
background-color
:
var
(
--active-bg
);
font-weight
:
500
;
}
/* 输入区域内容样式 */
.input-area-content
{
display
:
flex
;
align-items
:
center
;
}
.selected-option.active
{
/* 选中样式 */
/*background-color: #f5f6fa;*/
background-color
:
rgba
(
230
,
220
,
250
,
0.5
);
/*color: #272933;*/
color
:
#6633ff
;
}
.expert-toast
{
position
:
fixed
;
left
:
50%
;
top
:
65%
;
/* 垂直居中 */
background-color
:
rgba
(
230
,
220
,
250
,
0.5
);
color
:
#6633ff
;
padding
:
10px
20px
;
border-radius
:
4px
;
z-index
:
1000
;
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment