fix(ct): своя строка «Дополнительной информации» по ссылке — без HTML-обёртки SharePoint
Значение своей строки хранится в comment, а это в «Критерии» ОМТС многострочное поле с форматированием: SharePoint отдаёт его как <div class="ExternalClass…">да</div>, и по ссылке показывалась разметка. При загрузке теперь остаётся чистый текст (plainTextFromSp).
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { buildCriteriaRecords, isPaymentTypeOption, restoreCriteria } from './criteria';
|
import { buildCriteriaRecords, isPaymentTypeOption, plainTextFromSp, restoreCriteria } from './criteria';
|
||||||
import { Supplier } from '../types/domain';
|
import { Supplier } from '../types/domain';
|
||||||
|
|
||||||
const ARLAN_KZT: Supplier = { id: '263_277', spId: 263, kpFileSpId: 277, name: 'ТОО «Арлан Офис Снаб»', hasOffer: true };
|
const ARLAN_KZT: Supplier = { id: '263_277', spId: 263, kpFileSpId: 277, name: 'ТОО «Арлан Офис Снаб»', hasOffer: true };
|
||||||
@@ -96,3 +96,19 @@ describe('isPaymentTypeOption', () => {
|
|||||||
expect(isPaymentTypeOption('40% предоплата, 60% по аккредитиву')).toBe(false);
|
expect(isPaymentTypeOption('40% предоплата, 60% по аккредитиву')).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('plainTextFromSp', () => {
|
||||||
|
// comment в SP «Критерии» — многострочное поле с форматированием: SharePoint заворачивает текст в HTML,
|
||||||
|
// и по ссылке своя строка показывалась как «<div class="ExternalClass…">да</div>».
|
||||||
|
it('убирает обёртку ExternalClass и теги', () => {
|
||||||
|
expect(plainTextFromSp('<div class="ExternalClass11A142948BDD4FEB93E8B98BB14AE465">да</div>')).toBe('да');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('переносы строк сохраняет, HTML-сущности раскодирует', () => {
|
||||||
|
expect(plainTextFromSp('<div>12 мес<br>от "поставки" & монтажа</div>')).toBe('12 мес\nот "поставки" & монтажа');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('обычный текст не трогает', () => {
|
||||||
|
expect(plainTextFromSp('12 мес')).toBe('12 мес');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -36,6 +36,26 @@ const EMPTY_ENTRY: CriteriaEntry = { paymentType: '', deliveryType: '', deadline
|
|||||||
const hasAnyValue = (e: CriteriaEntry): boolean =>
|
const hasAnyValue = (e: CriteriaEntry): boolean =>
|
||||||
[e.paymentType, e.deliveryType, e.deadline, e.sertificates].some(v => (v ?? '').trim() !== '');
|
[e.paymentType, e.deliveryType, e.deadline, e.sertificates].some(v => (v ?? '').trim() !== '');
|
||||||
|
|
||||||
|
const HTML_ENTITIES: Record<string, string> = {
|
||||||
|
' ': ' ',
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'"': '"',
|
||||||
|
''': "'",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Текст из многострочного поля SP с форматированием (comment в «Критерии»): SharePoint хранит его как HTML
|
||||||
|
// в обёртке <div class="ExternalClass…">. Оставляем чистый текст, переносы строк — как есть.
|
||||||
|
export function plainTextFromSp(value: string): string {
|
||||||
|
if (!value.includes('<')) return value;
|
||||||
|
return value
|
||||||
|
.replace(/<br\s*\/?>/gi, '\n')
|
||||||
|
.replace(/<[^>]+>/g, '')
|
||||||
|
.replace(/&(nbsp|amp|lt|gt|quot|#39);/g, entity => HTML_ENTITIES[entity] ?? entity)
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
export function isPaymentTypeOption(value: string): boolean {
|
export function isPaymentTypeOption(value: string): boolean {
|
||||||
return PAYMENT_TYPE_OPTIONS.includes(value.trim());
|
return PAYMENT_TYPE_OPTIONS.includes(value.trim());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
keepLatestOfferRecords,
|
keepLatestOfferRecords,
|
||||||
parseOfferItemIndex,
|
parseOfferItemIndex,
|
||||||
} from "../../../shared/offers/offerRecords";
|
} from "../../../shared/offers/offerRecords";
|
||||||
import { CriteriaRecord } from "../components/utils/criteria";
|
import { CriteriaRecord, plainTextFromSp } from "../components/utils/criteria";
|
||||||
import {
|
import {
|
||||||
NoOfferSupplierEntry,
|
NoOfferSupplierEntry,
|
||||||
NoOfferSupplierRecord,
|
NoOfferSupplierRecord,
|
||||||
@@ -680,7 +680,8 @@ export class CtService {
|
|||||||
return ((data.value ?? []) as Array<Record<string, unknown>>).map((item): CriteriaRecord => {
|
return ((data.value ?? []) as Array<Record<string, unknown>>).map((item): CriteriaRecord => {
|
||||||
const base = { id: Number(item.Id), supplierSpId: Number(item.supplierId) };
|
const base = { id: Number(item.Id), supplierSpId: Number(item.supplierId) };
|
||||||
const label = String(item.criteriaLabel ?? "").trim();
|
const label = String(item.criteriaLabel ?? "").trim();
|
||||||
if (label) return { ...base, criteriaLabel: label, value: String(item.comment ?? "") };
|
// comment — многострочное поле с форматированием: SharePoint отдаёт его в HTML-обёртке.
|
||||||
|
if (label) return { ...base, criteriaLabel: label, value: plainTextFromSp(String(item.comment ?? "")) };
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
paymentType: String(item.paymentType ?? ""),
|
paymentType: String(item.paymentType ?? ""),
|
||||||
|
|||||||
Reference in New Issue
Block a user