migrate from github

This commit is contained in:
2026-07-15 22:51:56 +08:00
commit a1cccc8068
215 changed files with 38318 additions and 0 deletions
@@ -0,0 +1,286 @@
import { ElMessage, ElMessageBox } from 'element-plus';
import {
listDocumentComments,
createDocumentComment,
deleteDocumentComment,
updateDocumentComment
} from '@/services/api';
import { resolveFileUrl } from '@/utils/fileUrl';
export function useInlineCommentCrud({
t,
getDocId,
getInlineEnabled,
getUserInfo,
commentList,
userDisplayName,
maybeRemoveAnchor,
onCommentMutated
}) {
const buildLocalId = () => `temp_${Date.now()}_${Math.random().toString(36).slice(2)}`;
const createTempComment = ({ parent, anchorId }) => {
const userInfo = getUserInfo?.();
return {
local_id: buildLocalId(),
external_id: '',
parent_external_id: parent?.external_id || '',
content: '',
created_at: '',
creator_name: userDisplayName.value,
creator_user_external_id: userInfo?.external_id || '',
creator_avatar: resolveFileUrl(userInfo?.avatar || ''),
anchor_id: `${anchorId || parent?.anchor_id || ''}`.trim(),
editing: true,
draft: '',
saving: false
};
};
const canModify = (item) => {
if (!item) return false;
if (!item.external_id) return true;
const userInfo = getUserInfo?.();
const currentExternalId = userInfo?.external_id;
if (!currentExternalId) return false;
if (item.creator_user_external_id === currentExternalId) {
return true;
}
return userInfo?.username === 'admin';
};
const getActions = (item) => {
const editable = canModify(item);
return [
{ key: 'copy', label: t('common.copy') },
{ key: 'edit', label: t('common.edit'), disabled: !editable },
{ key: 'delete', label: t('document.commentDelete'), danger: true, disabled: !editable }
];
};
const insertAfter = (list, predicate, item) => {
const index = list.findIndex(predicate);
if (index === -1) {
list.unshift(item);
return;
}
list.splice(index + 1, 0, item);
};
const handleReply = (item) => {
const temp = createTempComment({ parent: item });
insertAfter(commentList.value, (entry) => entry.external_id === item.external_id, temp);
};
const startEdit = (item) => {
if (!item || item.editing) return;
item.draft = item.content || '';
item.editing = true;
};
const cancelEdit = (item) => {
if (!item) return;
if (!item.external_id) {
const nextList = commentList.value.filter((entry) => entry.local_id !== item.local_id);
commentList.value = nextList;
maybeRemoveAnchor(item.anchor_id, nextList);
return;
}
item.editing = false;
item.draft = '';
};
const saveEdit = async (item) => {
if (!item) return;
const content = (item.draft || '').trim();
if (!content) {
ElMessage.error(t('document.inlineCommentContentRequired'));
return;
}
if (!item.anchor_id) {
ElMessage.error(t('document.inlineCommentAnchorMissing'));
return;
}
if (item.saving) return;
const docId = getDocId?.();
if (!docId) {
return;
}
item.saving = true;
try {
if (item.external_id) {
const resp = await updateDocumentComment({
external_id: item.external_id,
content
});
const saved = resp.comment;
item.content = saved?.content || content;
item.created_at = saved?.created_at || item.created_at;
item.creator_name = saved?.creator_name || item.creator_name;
item.creator_avatar = saved?.creator_avatar || item.creator_avatar;
item.creator_user_external_id = saved?.creator_user_external_id || item.creator_user_external_id;
item.editing = false;
item.draft = '';
if (typeof onCommentMutated === 'function') {
onCommentMutated({ type: 'update', comment_id: item.external_id, anchor_id: item.anchor_id });
}
} else {
const resp = await createDocumentComment({
document_external_id: docId,
content,
parent_external_id: item.parent_external_id || undefined,
anchor_id: item.anchor_id,
mentioned_user_external_ids: item.mentionedUserExternalIds || []
});
const saved = resp.comment;
item.content = saved?.content || content;
item.external_id = saved?.external_id || item.external_id;
item.local_id = item.external_id || item.local_id;
item.created_at = saved?.created_at || new Date().toISOString();
item.creator_name = saved?.creator_name || item.creator_name;
item.creator_avatar = saved?.creator_avatar || item.creator_avatar;
item.creator_user_external_id = saved?.creator_user_external_id || item.creator_user_external_id;
item.anchor_id = saved?.anchor_id || item.anchor_id;
item.editing = false;
item.draft = '';
item.mentionedUserExternalIds = [];
if (typeof onCommentMutated === 'function') {
onCommentMutated({ type: 'create', comment_id: item.external_id, anchor_id: item.anchor_id });
}
}
} catch (error) {
ElMessage.error(t('common.requestFailed'));
} finally {
item.saving = false;
}
};
const deleteCommentItem = async (item) => {
if (!item) return;
const deletedAnchorId = item.anchor_id;
if (item.external_id) {
try {
await ElMessageBox.confirm(
t('document.commentDeleteConfirm'),
t('document.commentDelete'),
{
confirmButtonText: t('button.confirm'),
cancelButtonText: t('button.cancel'),
type: 'warning'
}
);
await deleteDocumentComment(item.external_id);
if (typeof onCommentMutated === 'function') {
onCommentMutated({ type: 'delete', comment_id: item.external_id, anchor_id: deletedAnchorId });
}
} catch (error) {
return;
}
}
const nextList = commentList.value.filter((entry) => entry.local_id !== item.local_id);
commentList.value = nextList;
maybeRemoveAnchor(item.anchor_id, nextList);
};
const copyComment = async (item) => {
const text = item?.content || '';
if (!text) return;
try {
await navigator.clipboard.writeText(text);
ElMessage.success(t('common.copySuccess'));
} catch (error) {
ElMessage.error(t('common.copyFailed'));
}
};
const handleAction = (item, action) => {
if (action === 'copy') {
copyComment(item);
return;
}
if (action === 'edit') {
if (!canModify(item)) return;
startEdit(item);
return;
}
if (action === 'delete') {
if (!canModify(item)) return;
deleteCommentItem(item);
}
};
const formatCommentTime = (value) => {
if (!value) return '';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return value;
return date.toLocaleString();
};
const loadComments = async (loadVersionRef) => {
const requestVersion = ++loadVersionRef.value;
const requestDocId = getDocId?.();
const inlineEnabled = !!getInlineEnabled?.();
const pendingEditingDrafts = commentList.value
.filter((item) => item && !item.external_id && item.editing)
.map((item) => ({ ...item }));
if (!requestDocId || !inlineEnabled) {
commentList.value = [];
if (requestVersion === loadVersionRef.value) {
return false;
}
return true;
}
try {
const resp = await listDocumentComments({
document_external_id: requestDocId,
page: 1,
page_size: 100
});
if (requestVersion !== loadVersionRef.value || requestDocId !== getDocId?.()) {
return false;
}
const remoteComments = (resp.comments || [])
.filter((item) => item.anchor_id)
.map((item) => ({
local_id: item.external_id || item.anchor_id,
anchor_id: item.anchor_id,
external_id: item.external_id,
parent_external_id: item.parent_external_id || '',
content: item.content,
created_at: item.created_at,
creator_name: item.creator_name,
creator_user_external_id: item.creator_user_external_id,
creator_avatar: item.creator_avatar,
editing: false,
draft: '',
saving: false
}));
commentList.value = [...pendingEditingDrafts, ...remoteComments];
return true;
} catch (error) {
if (requestVersion !== loadVersionRef.value || requestDocId !== getDocId?.()) {
return false;
}
commentList.value = pendingEditingDrafts;
return true;
}
};
return {
createTempComment,
getActions,
handleReply,
handleAction,
saveEdit,
cancelEdit,
formatCommentTime,
loadComments,
deleteRemoteComment: deleteDocumentComment
};
}