forked from Gitlink/forgeplus-react
atwho列表
This commit is contained in:
parent
3498390974
commit
8021d96cd8
|
@ -148,14 +148,6 @@ class MergeForm extends Component {
|
|||
values.issue_tag_ids = [];
|
||||
}
|
||||
const { desc , atWhoLoginList } = this.state;
|
||||
//发送消息
|
||||
if(atWhoLoginList.length != 0){
|
||||
axios.post(`/users/${owner}/messages.json`,{
|
||||
type:"atme",
|
||||
receivers_login:atWhoLoginList,
|
||||
atmeable_type:"PullRequest"
|
||||
})
|
||||
}
|
||||
if (merge_type === "new") {
|
||||
let url = `/${owner}/${projectsId}/pulls.json`;
|
||||
axios.post(url, {
|
||||
|
@ -167,7 +159,8 @@ class MergeForm extends Component {
|
|||
fork_project_id: data && data.fork_project_id,
|
||||
merge_user_login: data && data.merge_user_login,
|
||||
files_count,
|
||||
commits_count
|
||||
commits_count,
|
||||
receivers_login:atWhoLoginList,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
|
@ -197,6 +190,7 @@ class MergeForm extends Component {
|
|||
body: desc,
|
||||
head: pull,
|
||||
base: merge,
|
||||
receivers_login:atWhoLoginList,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
|
|
|
@ -154,15 +154,6 @@ class order_form extends Component {
|
|||
values.issue_tag_ids = [values.issue_tag_ids];
|
||||
}
|
||||
const { description, start_date, due_date, issue_type , atWhoLoginList } = this.state;
|
||||
//发送消息
|
||||
if(atWhoLoginList.length != 0){
|
||||
console.log('issue发送消息',atWhoLoginList);
|
||||
axios.post(`/users/${owner}/messages.json`,{
|
||||
type:"atme",
|
||||
receivers_login:atWhoLoginList,
|
||||
atmeable_type:"Issue"
|
||||
})
|
||||
}
|
||||
if (form_type !== "edit") {
|
||||
const url = `/${owner}/${projectsId}/issues.json`;
|
||||
axios.post(url, {
|
||||
|
@ -172,6 +163,7 @@ class order_form extends Component {
|
|||
start_date: start_date,
|
||||
due_date: due_date,
|
||||
issue_type: issue_type,
|
||||
receivers_login:atWhoLoginList,
|
||||
}).then((result) => {
|
||||
if (result && result.data.id) {
|
||||
this.props.showNotification("任务创建成功!");
|
||||
|
@ -198,6 +190,7 @@ class order_form extends Component {
|
|||
due_date: due_date,
|
||||
issue_type: issue_type,
|
||||
...values,
|
||||
receivers_login:atWhoLoginList,
|
||||
}).then((result) => {
|
||||
if (result) {
|
||||
this.props.history.push(`/${owner}/${projectsId}/issues/${orderId}`);
|
||||
|
|
|
@ -65,15 +65,6 @@ class comments extends Component {
|
|||
|
||||
const { owner } = this.props.match.params;
|
||||
|
||||
//发送消息
|
||||
if(atWhoLoginList.length != 0){
|
||||
axios.post(`/users/${owner}/messages.json`,{
|
||||
type:"atme",
|
||||
receivers_login:atWhoLoginList,
|
||||
atmeable_type:"Issue"
|
||||
})
|
||||
}
|
||||
|
||||
const url = `/issues/${orderId}/journals.json`;
|
||||
axios
|
||||
.post(url, {
|
||||
|
@ -82,6 +73,7 @@ class comments extends Component {
|
|||
issue_id: orderId,
|
||||
attachment_ids: fileList,
|
||||
parent_id: reply_id,
|
||||
receivers_login:atWhoLoginList,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data.status === 0) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
/*md编辑器中输入@弹出可选人列表样式*/
|
||||
.at_who_list{
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
z-index: 100;
|
||||
width: 180px;
|
||||
max-height: 160px;
|
||||
background: #FFFFFF;
|
||||
|
@ -26,7 +26,7 @@
|
|||
border-bottom: 1px solid rgba(212, 212, 212, 0.5);
|
||||
padding: 0 4px;
|
||||
}
|
||||
.at_who:hover{
|
||||
.active{
|
||||
background: #F3F4F6;
|
||||
}
|
||||
.at_who img{
|
||||
|
@ -35,3 +35,7 @@
|
|||
border-radius:50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.blur_atWho{
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
}
|
|
@ -2,6 +2,7 @@ import React, { Fragment, useEffect, useRef, useState } from 'react';
|
|||
import { getUploadActionUrl, getUrl } from 'educoder';
|
||||
import ResizeObserver from 'resize-observer-polyfill';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import axios from 'axios';
|
||||
import '../../courses/css/Courses.css';
|
||||
import './css/TPMchallengesnew.css';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
|
@ -80,16 +81,23 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
const [editorInstance, setEditorInstance] = useState();
|
||||
const [atWhoVisible, setAtWhoVisible] = useState(false);
|
||||
const [atWhoLoginListState, setAtWhoLoginListState] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
const atWhoLoginList = useRef([]);
|
||||
const containerId = `mdEditor_${mdID}`;
|
||||
const editorBodyId = `mdEditors_${mdID}`;
|
||||
const tipId = `e_tips_mdEditor_${mdID}`;
|
||||
|
||||
const users = [{image_url: "system/lets/letter_avatars/2/J/241_157_191/120.png",login: "jasonjun",profile_completed: false,user_id: 84965,username: "jasonjun"},
|
||||
{image_url: "system/lets/letter_avatars/2/E/122_185_146/120.png",login: "Eo9ygbqns",profile_completed: false,user_id: 84963,username: "Eo9ygbqns"},
|
||||
{image_url: "system/lets/letter_avatars/2/P/238_117_19/120.png",login: "postwoman",profile_completed: true,user_id: 84961,username: "PostWoman"},
|
||||
{image_url: "system/lets/letter_avatars/2/X/70_163_90/120.png",login: "xuzhun",profile_completed: false,user_id: 89516,username: "徐准"},
|
||||
{image_url: "system/lets/letter_avatars/2/X/70_163_90/120.png",login: "Es5ghtfik",profile_completed: false,user_id: 89516,username: "徐准1"}]
|
||||
useEffect(()=>{
|
||||
isCanAtme && axios.get('/users/list.json',{
|
||||
params: {
|
||||
search: 'admin',
|
||||
},
|
||||
}).then(response=>{
|
||||
if(response && response.status === 200){
|
||||
setUsers(response.data.users);
|
||||
}
|
||||
})
|
||||
},[])
|
||||
|
||||
function onLayout() {
|
||||
let ro;
|
||||
|
@ -116,10 +124,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
const line = cursor.line;//行
|
||||
const ch = cursor.ch;//列
|
||||
//替换最后的内容
|
||||
// cm.getLine(line).endsWith("@") ? cm.replaceRange(username+" ",{line,ch},{line,ch}) : cm.replaceRange("@"+username+" ",{line,ch},{line,ch})
|
||||
cm.replaceRange(username+" ",{line,ch},{line,ch});
|
||||
//鼠标聚焦到此行的最后
|
||||
editorInstance.focus();
|
||||
editorInstance.setCursor({line,ch:ch+username.length+1});
|
||||
//鼠标聚焦
|
||||
cm.focus();
|
||||
//将此user的login存储到atWhoLoginList集合中
|
||||
const list = new Set(atWhoLoginList.current);
|
||||
users.map((item)=>{
|
||||
|
@ -129,6 +137,92 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
setAtWhoLoginListState(Array.from(list));
|
||||
}
|
||||
|
||||
function onMouseOver(key){
|
||||
document.getElementsByClassName("at_who active")[0].className="at_who";
|
||||
document.getElementsByClassName("at_who")[key].className="at_who active";
|
||||
}
|
||||
|
||||
//markdown编辑器中输入的键盘监听事件
|
||||
function mdKeyDown(){
|
||||
document.onkeydown = e=>{
|
||||
console.log("markdown",atWhoVisible);
|
||||
if (e.key === "@") {
|
||||
// 输入@键后在对应的位置显示可选的项目成员
|
||||
setAtWhoVisible(true);
|
||||
//获取光标位置
|
||||
const cssStyle = document.getElementsByClassName("CodeMirror cm-s-default CodeMirror-wrap")[0].firstChild.style;
|
||||
//设置弹框位置
|
||||
document.getElementById("at_who_list").style.top = (parseInt(cssStyle.getPropertyValue("top").replace("px",""))+60)+"px";
|
||||
document.getElementById("at_who_list").style.left = (parseInt(cssStyle.getPropertyValue("left").replace("px",""))+20)+"px";
|
||||
//将第一个用户默认选中
|
||||
const at_who_divs = document.getElementsByClassName("at_who");
|
||||
at_who_divs[0].className = "at_who active";
|
||||
} else {
|
||||
setAtWhoVisible(false);
|
||||
}
|
||||
//处理本来@了某人 -> 删掉 -> 撤回 的情况
|
||||
if(e.code === "KeyZ" && users.length != 0){
|
||||
const codemirror = editorInstance.cm;
|
||||
let value = codemirror.getValue();
|
||||
//处理初始内容就自带@谁的情况
|
||||
if(initValue){
|
||||
const del = [];
|
||||
users.map(item=>{
|
||||
if(initValue.indexOf(item.username)!=-1 && initValue.charAt(initValue.indexOf(item.username)-1) === "@" && initValue.indexOf(`@${item.username}`)===value.indexOf(`@${item.username}`)){
|
||||
//初始内容中有符合@+名字的格式并且当前内容未删除初始内容
|
||||
del[del.length] = `@${item.username}`;
|
||||
}
|
||||
})
|
||||
del.length!=0 && del.map(str=>{
|
||||
value = value.replace(str,"");
|
||||
})
|
||||
}
|
||||
//判断value是否包含@符号
|
||||
value.indexOf("@") != -1 && users.map(item =>{
|
||||
if(value.indexOf(item.username)!=-1 && value.charAt(value.indexOf(item.username)-1) ==="@"){
|
||||
//将此user的login存储到atWhoLoginList集合中
|
||||
const list = new Set(atWhoLoginList.current);
|
||||
list.add(item.login);
|
||||
atWhoLoginList.current = Array.from(list);
|
||||
setAtWhoLoginListState(Array.from(list));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//弹出可选@用户列表之后的键盘监听事件
|
||||
function atWhoKeyDown(){
|
||||
//监听上下和enter键
|
||||
document.onkeydown = (e) =>{
|
||||
console.log("atwho列表",atWhoVisible);
|
||||
const atWhoListDiv = document.getElementById("at_who_list");
|
||||
const atWhoDivs = document.getElementsByClassName("at_who");
|
||||
let index;
|
||||
for(let i = 0; i<atWhoDivs.length;i++){
|
||||
atWhoDivs[i].className === "at_who active" && (index = i);
|
||||
}
|
||||
if(e.key === "ArrowUp" && index > 0){
|
||||
// index >=4 && (atWhoListDiv.scrollTop -=40)
|
||||
atWhoListDiv.scrollTop -= 40;
|
||||
atWhoDivs[index].className = "at_who";
|
||||
atWhoDivs[index-1].className = "at_who active";
|
||||
}
|
||||
if(e.key === "ArrowDown" && index < atWhoDivs.length-1){
|
||||
// index >=3 && (atWhoListDiv.scrollTop +=40)
|
||||
atWhoListDiv.scrollTop += 40;
|
||||
atWhoDivs[index].className = "at_who";
|
||||
atWhoDivs[index+1].className = "at_who active";
|
||||
}
|
||||
if(e.key === "Enter"){
|
||||
//阻止默认事件
|
||||
e.preventDefault();
|
||||
//找到classname为at_who active的div,执行click事件
|
||||
document.getElementsByClassName("at_who active")[0].click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
console.log('@谁列表发生变化,atWhoLoginList.current:',atWhoLoginList.current,'atWhoLoginListState: ',atWhoLoginListState);
|
||||
changeAtWhoLoginList && changeAtWhoLoginList(atWhoLoginListState);
|
||||
|
@ -138,8 +232,8 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
<div className="at_who_list" id="at_who_list" >
|
||||
{users && users.map((item,key)=>{
|
||||
return(
|
||||
<div key={key} className="at_who" onClick={()=>{selectAtWho(item.username)}}>
|
||||
{ item.image_url && <img src={getImageUrl(item.image_url)}></img> }
|
||||
<div key={key} className="at_who" onClick={()=>{selectAtWho(item.username)}} onMouseOver={()=>{onMouseOver(key)}}>
|
||||
{item.image_url && <img src={getImageUrl(item.image_url)}></img>}
|
||||
<span>{item.username}</span>
|
||||
</div>
|
||||
)
|
||||
|
@ -153,10 +247,9 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
|
||||
useEffect(()=>{
|
||||
//当atWhoVisible为true的时候,失焦,监听上下和enter键
|
||||
if(atWhoVisible && editorInstance && editorInstance.cm){
|
||||
console.log('弹框啦');
|
||||
//焦点转移到非monaco-editer编辑器上
|
||||
editorInstance.cm.addEventListener('blur',()=>{})
|
||||
if(atWhoVisible){
|
||||
document.activeElement.id !== "blur_atWho" && document.getElementById("blur_atWho").focus();
|
||||
document.addEventListener("keydown",atWhoKeyDown());
|
||||
}
|
||||
},[atWhoVisible])
|
||||
|
||||
|
@ -260,52 +353,10 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
//isCanAtme:只有issue和合并请求以及评论部分可以@他人操作
|
||||
//当光标或选中内容时触发绑定@事件
|
||||
isCanAtme && editorInstance.cm.on("focus", () => {
|
||||
document.onkeydown = (e) => {
|
||||
if (e.key === "@") {
|
||||
// 输入@键后在对应的位置显示可选的项目成员
|
||||
setAtWhoVisible(true);
|
||||
//获取光标位置
|
||||
const cssStyle = document.getElementsByClassName("CodeMirror cm-s-default CodeMirror-wrap")[0].firstChild.style;
|
||||
//设置弹框位置
|
||||
document.getElementById("at_who_list").style.top = (parseInt(cssStyle.getPropertyValue("top").replace("px",""))+60)+"px";
|
||||
document.getElementById("at_who_list").style.left = (parseInt(cssStyle.getPropertyValue("left").replace("px",""))+20)+"px";
|
||||
} else {
|
||||
setAtWhoVisible(false);
|
||||
}
|
||||
//处理本来@了某人 -> 删掉 -> 撤回 的情况
|
||||
if(e.code === "KeyZ" && users.length != 0){
|
||||
const codemirror = editorInstance.cm;
|
||||
let value = codemirror.getValue();
|
||||
//处理初始内容就自带@谁的情况
|
||||
if(initValue){
|
||||
const del = [];
|
||||
users.map(item=>{
|
||||
if(initValue.indexOf(item.username)!=-1 && initValue.charAt(initValue.indexOf(item.username)-1) === "@" && initValue.indexOf(`@${item.username}`)===value.indexOf(`@${item.username}`)){
|
||||
//初始内容中有符合@+名字的格式并且当前内容未删除初始内容
|
||||
del[del.length] = `@${item.username}`;
|
||||
}
|
||||
})
|
||||
del.length!=0 && del.map(str=>{
|
||||
value = value.replace(str,"");
|
||||
})
|
||||
}
|
||||
//判断value是否包含@符号
|
||||
if(value.indexOf("@") != -1){
|
||||
users.map(item =>{
|
||||
if(value.indexOf(item.username)!=-1 && value.charAt(value.indexOf(item.username)-1) ==="@"){
|
||||
//将此user的login存储到atWhoLoginList集合中
|
||||
const list = new Set(atWhoLoginList.current);
|
||||
list.add(item.login);
|
||||
atWhoLoginList.current = Array.from(list);
|
||||
setAtWhoLoginListState(Array.from(list));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", mdKeyDown());
|
||||
});
|
||||
editorInstance.cm.on("blur", () => {
|
||||
document.onkeydown = null ;
|
||||
isCanAtme && editorInstance.cm.on("blur", () => {
|
||||
document.removeEventListener("keydown",mdKeyDown());
|
||||
});
|
||||
editorInstance.cm.on("change", (cm) => {
|
||||
onChange && onChange(cm.getValue());
|
||||
|
@ -428,6 +479,7 @@ export default ({ mdID, onChange, onCMBeforeChange, onCMBlur, error = false, cla
|
|||
<div className={`edu-back-greyf5 radius4 editormd ${error ? 'error' : ''}`} id={containerId} >
|
||||
<textarea style={{ display: 'none' }} id={editorBodyId} name="content"></textarea>
|
||||
<div className="CodeMirror cm-s-defualt"></div>
|
||||
<input id ="blur_atWho" className="blur_atWho"/>
|
||||
{atWhoVisible && atWhoList}
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue