Files
tougao_web/src/common/js/citeTablePreview.js

170 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 表格弹窗预览:将单元格内空 mycite 转为可见 [n],与 word.vue renderCiteLabels 一致(纯函数,无 Vue 依赖)
*/
export function formatCiteNumbers(nums) {
if (!nums || !nums.length) return '';
const sorted = [...new Set(nums)].sort((a, b) => a - b);
const result = [];
let i = 0;
while (i < sorted.length) {
let j = i;
while (j < sorted.length - 1 && sorted[j + 1] === sorted[j] + 1) j++;
if (j - i >= 2) {
result.push(`${sorted[i]}${sorted[j]}`);
} else {
for (let k = i; k <= j; k++) result.push(sorted[k]);
}
i = j + 1;
}
return result.join(', ');
}
export function sortAutociteIdsByCiteNumber(ids, citeMap) {
const map = citeMap || {};
const uniq = [...new Set(ids.map(String))];
return uniq.sort((a, b) => {
const na = map[a];
const nb = map[b];
const ha = na != null && na !== '';
const hb = nb != null && nb !== '';
if (ha && hb) return Number(na) - Number(nb);
if (ha) return -1;
if (hb) return 1;
return String(a).localeCompare(String(b));
});
}
/**
* @param {Array} refs - chanFerForm项含 p_refer_id
* @param {Array<string|number>} bodyCiteIdOrder - 正文首次出现顺序;空则按列表行序 1..n
*/
export function buildCiteMapFromRefs(refs, bodyCiteIdOrder) {
const refList = Array.isArray(refs) ? refs : [];
const refIdSet = new Set(
refList.map((r) => (r && r.p_refer_id != null ? String(r.p_refer_id) : '')).filter(Boolean)
);
let orderedIds = [];
if (Array.isArray(bodyCiteIdOrder) && bodyCiteIdOrder.length > 0) {
orderedIds = bodyCiteIdOrder.map(String);
}
if (orderedIds.length === 0) {
const map = {};
refList.forEach((row, idx) => {
const key = row && row.p_refer_id != null ? String(row.p_refer_id) : '';
if (key) map[key] = idx + 1;
});
return map;
}
const filtered = [];
orderedIds.forEach((id) => {
if (refIdSet.has(id) && !filtered.includes(id)) filtered.push(id);
});
const map = {};
filtered.forEach((id, idx) => {
map[id] = idx + 1;
});
let next = filtered.length + 1;
refList.forEach((r) => {
const key = r && r.p_refer_id != null ? String(r.p_refer_id) : '';
if (!key || map[key] != null) return;
map[key] = next++;
});
return map;
}
function escAttr(s) {
return String(s || '')
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;');
}
/**
* @param {string} html
* @param {Array} refs - chanFerForm
* @param {Object} citeMap - p_refer_id -> 显示序号
*/
export function renderCiteLabelsInHtml(html, refs, citeMap) {
if (!html || typeof html !== 'string') return html || '';
if (!Array.isArray(refs) || refs.length === 0) return html;
/** 与稿面一致:历史/表格 JSON 中可能为 <autocite> */
let h = html.replace(/<\/autocite>/gi, '</mycite>').replace(/<autocite\b/gi, '<mycite');
const refList = refs;
const refMap = refList.reduce((acc, item) => {
const key = item && item.p_refer_id != null ? String(item.p_refer_id) : '';
if (key) acc[key] = item;
return acc;
}, {});
let normalized = h.replace(/<mycite\b[^>]*\/?>[\s\S]*?(?:<\/mycite>)?/gi, (fullTag) => {
const attrMatch = fullTag.match(/\bdata-id\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i);
const dataId = (attrMatch && (attrMatch[1] || attrMatch[2] || attrMatch[3])) || '';
if (!dataId) return '';
return `<mycite data-id="${escAttr(dataId)}"></mycite>`;
});
const citeGroupRe = /(?:<mycite\s+data-id="([^"]*)"\s*><\/mycite>\s*)+/gi;
normalized = normalized.replace(citeGroupRe, (groupMatch) => {
const ids = [];
const innerRe = /<mycite\s+data-id="([^"]*)"\s*><\/mycite>/gi;
let m;
while ((m = innerRe.exec(groupMatch)) !== null) {
m[1].split(',').forEach((part) => {
const id = part.trim();
if (id) ids.push(id);
});
}
const sortedAll = sortAutociteIdsByCiteNumber(ids, citeMap);
const validIds = sortedAll.filter((id) => refMap[id]);
const sortedIds = validIds.length ? sortAutociteIdsByCiteNumber(validIds, citeMap) : [];
const map = citeMap || {};
const parts = sortedIds.map((id) => {
const ref = refMap[id];
const no = ref ? map[id] : null;
const num = no != null && no !== '' ? String(no) : null;
return { id, ref, num };
});
const numsForLabel = parts
.map((p) => p.num)
.filter((n) => n != null && n !== '')
.map(Number);
const label = numsForLabel.length > 0 ? formatCiteNumbers(numsForLabel) : '';
if (!label) {
return '';
}
const dataIdAttr = escAttr(sortedIds.join(','));
return `<mycite data-id="${dataIdAttr}">[${label}]</mycite>`;
});
return normalized.replace(/<mycite[^>]*data-id=""[^>]*>[\s\S]*?<\/mycite>/gi, '');
}
export function applyCiteLabelsToTableRows(rows, refs, citeMap) {
if (!Array.isArray(rows) || !rows.length) return rows;
if (!Array.isArray(refs) || refs.length === 0) return rows;
return rows.map((row) => {
if (!Array.isArray(row)) return row;
const nextRow = row.map((cell) => {
if (!cell || typeof cell !== 'object') return cell;
const t = cell.text;
const lower = typeof t === 'string' ? t.toLowerCase() : '';
if (!lower || (!lower.includes('mycite') && !lower.includes('autocite'))) return cell;
const next = renderCiteLabelsInHtml(t, refs, citeMap);
if (next === t) return cell;
return { ...cell, text: next };
});
// TableUtils.addRowIdToData 会给数组行对象挂 rowId渲染 oddColor 依赖它,不能在 map 后丢失
if (row.rowId != null) {
nextRow.rowId = row.rowId;
}
return nextRow;
});
}