当提交的版本与当前工作版本不同时,自动创建命名副本:
- 新增 _create_named_working_copy_for_review 方法处理送审时的版本复制
- 支持将工作版本快照复制为指定版本进行送审
- 新增 AgentAssetSpreadsheetChangeRecordRead schema
- API 端点新增 /rules/{id}/spreadsheet-versions/{version}/change-records 接口
125 lines
3.3 KiB
JavaScript
125 lines
3.3 KiB
JavaScript
function normalizeText(value) {
|
|
if (typeof value === 'string') {
|
|
return value.trim()
|
|
}
|
|
if (value === null || value === undefined) {
|
|
return ''
|
|
}
|
|
return String(value).trim()
|
|
}
|
|
|
|
function resolveOperationLabelFromSource(source) {
|
|
switch (normalizeText(source).toLowerCase()) {
|
|
case 'onlyoffice':
|
|
return '在线编辑保存'
|
|
case 'content-import':
|
|
return '导入表格'
|
|
case 'upload':
|
|
return '上传表格'
|
|
case 'restore':
|
|
return '恢复历史版本'
|
|
case 'review-submit':
|
|
return '提交审核固化'
|
|
case 'preview':
|
|
return '预览版本'
|
|
default:
|
|
return ''
|
|
}
|
|
}
|
|
|
|
export function resolveSpreadsheetOperationLabel(record) {
|
|
const explicitLabel = normalizeText(record?.operationLabel)
|
|
if (explicitLabel) {
|
|
return explicitLabel
|
|
}
|
|
|
|
const sourceLabel = resolveOperationLabelFromSource(record?.spreadsheetMeta?.source)
|
|
if (sourceLabel) {
|
|
return sourceLabel
|
|
}
|
|
|
|
const note = normalizeText(record?.note).toLowerCase()
|
|
if (note.includes('onlyoffice')) {
|
|
return '在线编辑保存'
|
|
}
|
|
if (note.includes('导入')) {
|
|
return '导入表格'
|
|
}
|
|
if (note.includes('恢复')) {
|
|
return '恢复历史版本'
|
|
}
|
|
if (note.includes('上传')) {
|
|
return '上传表格'
|
|
}
|
|
|
|
return '表格修改'
|
|
}
|
|
|
|
function normalizeChangeRecord(record) {
|
|
const version = normalizeText(record?.version)
|
|
if (!version) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
version,
|
|
operationLabel: resolveSpreadsheetOperationLabel(record),
|
|
operationActor:
|
|
normalizeText(record?.operationActor || record?.createdBy || record?.spreadsheetMeta?.updated_by) ||
|
|
'系统',
|
|
note: normalizeText(record?.note) || '用户修改了表格内容。',
|
|
time: normalizeText(record?.time || record?.createdAt || record?.spreadsheetMeta?.updated_at),
|
|
isWorking: record?.isWorking !== false,
|
|
isPendingLocalEdit: Boolean(record?.isPendingLocalEdit),
|
|
disabledReason: normalizeText(record?.disabledReason)
|
|
}
|
|
}
|
|
|
|
function toTimestamp(value) {
|
|
const normalized = normalizeText(value)
|
|
if (!normalized) {
|
|
return 0
|
|
}
|
|
const parsed = Date.parse(normalized)
|
|
return Number.isNaN(parsed) ? 0 : parsed
|
|
}
|
|
|
|
function dedupeChangeRecords(records) {
|
|
const seen = new Set()
|
|
return records.filter((item) => {
|
|
const key = [item.version, item.operationLabel, item.note].join('::')
|
|
if (seen.has(key)) {
|
|
return false
|
|
}
|
|
seen.add(key)
|
|
return true
|
|
})
|
|
}
|
|
|
|
export function buildSpreadsheetChangeRecords({
|
|
history = [],
|
|
localRecords = [],
|
|
publishedVersion = '',
|
|
limit = 5
|
|
} = {}) {
|
|
const normalizedPublishedVersion = normalizeText(publishedVersion)
|
|
const normalizedHistoryRecords = Array.isArray(history)
|
|
? history.map(normalizeChangeRecord).filter(Boolean)
|
|
: []
|
|
const normalizedLocalRecords = Array.isArray(localRecords)
|
|
? localRecords.map(normalizeChangeRecord).filter(Boolean)
|
|
: []
|
|
|
|
const unpublishedHistoryRecords = normalizedHistoryRecords.filter(
|
|
(item) => item.version !== normalizedPublishedVersion
|
|
)
|
|
const preferredHistoryRecords =
|
|
unpublishedHistoryRecords.length || !normalizedPublishedVersion
|
|
? unpublishedHistoryRecords
|
|
: normalizedHistoryRecords
|
|
|
|
return dedupeChangeRecords([...normalizedLocalRecords, ...preferredHistoryRecords])
|
|
.sort((left, right) => toTimestamp(right.time) - toTimestamp(left.time))
|
|
.slice(0, limit)
|
|
}
|