Compare commits
No commits in common. "c04ed4acb1477487b72569b00b7396bbf774711d" and "49c86d566858774b1d8e0e78f9735faa39027ae6" have entirely different histories.
c04ed4acb1
...
49c86d5668
@ -62,14 +62,6 @@ type XmInfoLike = {
|
|||||||
reviewedBy?: unknown
|
reviewedBy?: unknown
|
||||||
preparedDate?: unknown
|
preparedDate?: unknown
|
||||||
projectIndustry?: unknown
|
projectIndustry?: unknown
|
||||||
preparedCompany?: unknown
|
|
||||||
overview?: unknown
|
|
||||||
desc?: unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
type HtBaseInfoLike = {
|
|
||||||
quality?: unknown
|
|
||||||
duration?: unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ScaleRowLike {
|
interface ScaleRowLike {
|
||||||
@ -97,26 +89,12 @@ interface ZxFwRowLike {
|
|||||||
id: string
|
id: string
|
||||||
process?: unknown
|
process?: unknown
|
||||||
subtotal?: unknown
|
subtotal?: unknown
|
||||||
finalFee?: unknown
|
|
||||||
investScale?: unknown
|
investScale?: unknown
|
||||||
landScale?: unknown
|
landScale?: unknown
|
||||||
workload?: unknown
|
workload?: unknown
|
||||||
hourly?: unknown
|
hourly?: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkContentRowLike {
|
|
||||||
id?: unknown
|
|
||||||
content?: unknown
|
|
||||||
checked?: unknown
|
|
||||||
custom?: unknown
|
|
||||||
serviceGroup?: unknown
|
|
||||||
isAddTrigger?: unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WorkContentStateLike {
|
|
||||||
detailRows?: WorkContentRowLike[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ZxFwStorageLike {
|
interface ZxFwStorageLike {
|
||||||
selectedIds?: string[]
|
selectedIds?: string[]
|
||||||
selectedCodes?: string[]
|
selectedCodes?: string[]
|
||||||
@ -197,7 +175,6 @@ interface ExportScaleRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ExportMethod1Detail {
|
interface ExportMethod1Detail {
|
||||||
proNum: number
|
|
||||||
major: number
|
major: number
|
||||||
cost: number
|
cost: number
|
||||||
basicFee: number
|
basicFee: number
|
||||||
@ -214,7 +191,6 @@ interface ExportMethod1Detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ExportMethod1 {
|
interface ExportMethod1 {
|
||||||
proAmount: number
|
|
||||||
cost: number
|
cost: number
|
||||||
basicFee: number
|
basicFee: number
|
||||||
basicFee_basic: number
|
basicFee_basic: number
|
||||||
@ -224,7 +200,6 @@ interface ExportMethod1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ExportMethod2Detail {
|
interface ExportMethod2Detail {
|
||||||
proNum: number
|
|
||||||
major: number
|
major: number
|
||||||
area: number
|
area: number
|
||||||
basicFee: number
|
basicFee: number
|
||||||
@ -241,7 +216,6 @@ interface ExportMethod2Detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ExportMethod2 {
|
interface ExportMethod2 {
|
||||||
proAmount: number
|
|
||||||
area: number
|
area: number
|
||||||
basicFee: number
|
basicFee: number
|
||||||
basicFee_basic: number
|
basicFee_basic: number
|
||||||
@ -285,20 +259,13 @@ interface ExportMethod4 {
|
|||||||
interface ExportService {
|
interface ExportService {
|
||||||
id: number
|
id: number
|
||||||
fee: number
|
fee: number
|
||||||
finalFee: number
|
|
||||||
process: number
|
process: number
|
||||||
tasks: ExportTaskGroup[]
|
|
||||||
method1?: ExportMethod1
|
method1?: ExportMethod1
|
||||||
method2?: ExportMethod2
|
method2?: ExportMethod2
|
||||||
method3?: ExportMethod3
|
method3?: ExportMethod3
|
||||||
method4?: ExportMethod4
|
method4?: ExportMethod4
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExportTaskGroup {
|
|
||||||
serviceid?: number
|
|
||||||
text: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ExportServiceCoe {
|
interface ExportServiceCoe {
|
||||||
serviceid: number
|
serviceid: number
|
||||||
coe: number
|
coe: number
|
||||||
@ -317,8 +284,6 @@ interface ExportContract {
|
|||||||
addtionalFee: number
|
addtionalFee: number
|
||||||
reserveFee: number
|
reserveFee: number
|
||||||
fee: number
|
fee: number
|
||||||
quality: string
|
|
||||||
duration: string
|
|
||||||
scale: ExportScaleRow[]
|
scale: ExportScaleRow[]
|
||||||
serviceCoes: ExportServiceCoe[]
|
serviceCoes: ExportServiceCoe[]
|
||||||
majorCoes: ExportMajorCoe[]
|
majorCoes: ExportMajorCoe[]
|
||||||
@ -349,11 +314,10 @@ interface ExportMethod5 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ExportAdditionalDetail {
|
interface ExportAdditionalDetail {
|
||||||
id: number | string
|
id: number
|
||||||
code?: unknown
|
code?: unknown
|
||||||
name: string
|
name: string
|
||||||
fee: number
|
fee: number
|
||||||
tasks: ExportTaskGroup[]
|
|
||||||
m0?: ExportMethod0
|
m0?: ExportMethod0
|
||||||
m4?: ExportMethod4
|
m4?: ExportMethod4
|
||||||
m5?: ExportMethod5
|
m5?: ExportMethod5
|
||||||
@ -370,7 +334,6 @@ interface ExportReserve {
|
|||||||
code?: unknown
|
code?: unknown
|
||||||
name: string
|
name: string
|
||||||
fee: number
|
fee: number
|
||||||
tasks: ExportTaskGroup[]
|
|
||||||
m0?: ExportMethod0
|
m0?: ExportMethod0
|
||||||
m4?: ExportMethod4
|
m4?: ExportMethod4
|
||||||
m5?: ExportMethod5
|
m5?: ExportMethod5
|
||||||
@ -380,13 +343,10 @@ interface ExportReportPayload {
|
|||||||
name: string
|
name: string
|
||||||
writer: string
|
writer: string
|
||||||
reviewer: string
|
reviewer: string
|
||||||
company: string
|
|
||||||
date: string
|
date: string
|
||||||
industry: number
|
industry: number
|
||||||
fee: number
|
fee: number
|
||||||
scaleCost: number
|
scaleCost: number
|
||||||
overview: string
|
|
||||||
desc: string
|
|
||||||
scale: ExportScaleRow[]
|
scale: ExportScaleRow[]
|
||||||
serviceCoes: ExportServiceCoe[]
|
serviceCoes: ExportServiceCoe[]
|
||||||
majorCoes: ExportMajorCoe[]
|
majorCoes: ExportMajorCoe[]
|
||||||
@ -1072,83 +1032,6 @@ const mapIndustryCodeToExportIndustry = (value: unknown): number => {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseScaleScopedRowId = (rowId: unknown) => {
|
|
||||||
const raw = String(rowId || '').trim()
|
|
||||||
const scopedMatch = /^(\d+)::(.+)$/.exec(raw)
|
|
||||||
if (scopedMatch) {
|
|
||||||
return {
|
|
||||||
proNum: toSafeInteger(scopedMatch[1]) ?? 1,
|
|
||||||
majorPart: String(scopedMatch[2] || '').trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
proNum: 1,
|
|
||||||
majorPart: raw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const toScaleMajorId = (row: ScaleMethodRowLike): number | null => {
|
|
||||||
const direct = toSafeInteger((row as { majorDictId?: unknown }).majorDictId)
|
|
||||||
if (direct != null) return direct
|
|
||||||
const parsed = parseScaleScopedRowId(row.id)
|
|
||||||
return toSafeInteger(parsed.majorPart)
|
|
||||||
}
|
|
||||||
|
|
||||||
const toScaleProNum = (row: ScaleMethodRowLike): number => {
|
|
||||||
const parsed = parseScaleScopedRowId(row.id)
|
|
||||||
return parsed.proNum > 0 ? parsed.proNum : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizeTaskText = (value: unknown): string => String(value || '').trim()
|
|
||||||
|
|
||||||
const groupWorkContentTasks = (
|
|
||||||
rows: WorkContentRowLike[] | undefined,
|
|
||||||
options?: { forceUngroup?: boolean; serviceLabelToId?: Map<string, number> }
|
|
||||||
): ExportTaskGroup[] => {
|
|
||||||
const source = Array.isArray(rows) ? rows : []
|
|
||||||
const selected = source.filter(item => {
|
|
||||||
if (item && item.isAddTrigger === true) return false
|
|
||||||
const isCustom = Boolean(item?.custom)
|
|
||||||
const isChecked = Boolean(item?.checked)
|
|
||||||
return isCustom || isChecked
|
|
||||||
})
|
|
||||||
if (selected.length === 0) return []
|
|
||||||
|
|
||||||
const hasGroup = !options?.forceUngroup && selected.some(item => normalizeTaskText(item?.serviceGroup).length > 0)
|
|
||||||
if (!hasGroup) {
|
|
||||||
const text = selected
|
|
||||||
.map(item => normalizeTaskText(item?.content))
|
|
||||||
.filter(Boolean)
|
|
||||||
return text.length > 0 ? [{ text }] : []
|
|
||||||
}
|
|
||||||
|
|
||||||
const grouped = new Map<string, string[]>()
|
|
||||||
const orderedGroupKeys: string[] = []
|
|
||||||
for (const item of selected) {
|
|
||||||
const groupName = normalizeTaskText(item?.serviceGroup)
|
|
||||||
const key = groupName || '__ungrouped__'
|
|
||||||
if (!grouped.has(key)) {
|
|
||||||
grouped.set(key, [])
|
|
||||||
orderedGroupKeys.push(key)
|
|
||||||
}
|
|
||||||
const content = normalizeTaskText(item?.content)
|
|
||||||
if (!content) continue
|
|
||||||
grouped.get(key)?.push(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
const byLabel = options?.serviceLabelToId || new Map<string, number>()
|
|
||||||
return orderedGroupKeys
|
|
||||||
.map(groupName => {
|
|
||||||
const text = grouped.get(groupName) || []
|
|
||||||
if (text.length === 0) return null
|
|
||||||
const entry: ExportTaskGroup = { text }
|
|
||||||
const resolvedServiceId = byLabel.get(groupName)
|
|
||||||
if (resolvedServiceId != null) entry.serviceid = resolvedServiceId
|
|
||||||
return entry
|
|
||||||
})
|
|
||||||
.filter((item): item is ExportTaskGroup => Boolean(item))
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildProjectServiceCoes = (rows: FactorRowLike[] | undefined): ExportServiceCoe[] => {
|
const buildProjectServiceCoes = (rows: FactorRowLike[] | undefined): ExportServiceCoe[] => {
|
||||||
if (!Array.isArray(rows)) return []
|
if (!Array.isArray(rows)) return []
|
||||||
return rows
|
return rows
|
||||||
@ -1201,13 +1084,10 @@ const toExportScaleRows = (rows: ScaleRowLike[] | undefined): ExportScaleRow[] =
|
|||||||
const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | null => {
|
const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | null => {
|
||||||
if (!Array.isArray(rows)) return null
|
if (!Array.isArray(rows)) return null
|
||||||
let hasTotalValue = false
|
let hasTotalValue = false
|
||||||
const proSet = new Set<number>()
|
|
||||||
const det = rows
|
const det = rows
|
||||||
.map(row => {
|
.map(row => {
|
||||||
const major = toScaleMajorId(row)
|
const major = toSafeInteger(row.id)
|
||||||
if (major == null || row.budgetFee == null) return null
|
if (major == null || row.budgetFee == null) return null
|
||||||
const proNum = toScaleProNum(row)
|
|
||||||
proSet.add(proNum)
|
|
||||||
const cost = toFiniteNumber(row.amount)
|
const cost = toFiniteNumber(row.amount)
|
||||||
const basicFee = toFiniteNumber(row.budgetFee)
|
const basicFee = toFiniteNumber(row.budgetFee)
|
||||||
if (basicFee != null) hasTotalValue = true
|
if (basicFee != null) hasTotalValue = true
|
||||||
@ -1222,7 +1102,6 @@ const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | n
|
|||||||
isNonEmptyString(remark)
|
isNonEmptyString(remark)
|
||||||
if (!hasValue) return null
|
if (!hasValue) return null
|
||||||
return {
|
return {
|
||||||
proNum,
|
|
||||||
major,
|
major,
|
||||||
cost: cost ?? 0,
|
cost: cost ?? 0,
|
||||||
basicFee: basicFee ?? 0,
|
basicFee: basicFee ?? 0,
|
||||||
@ -1242,7 +1121,6 @@ const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | n
|
|||||||
|
|
||||||
if (det.length === 0 || !hasTotalValue) return null
|
if (det.length === 0 || !hasTotalValue) return null
|
||||||
return {
|
return {
|
||||||
proAmount: proSet.size > 0 ? proSet.size : 1,
|
|
||||||
cost: sumNumbers(det.map(item => item.cost)),
|
cost: sumNumbers(det.map(item => item.cost)),
|
||||||
basicFee: sumNumbers(det.map(item => item.basicFee)),
|
basicFee: sumNumbers(det.map(item => item.basicFee)),
|
||||||
basicFee_basic: sumNumbers(det.map(item => item.basicFee_basic)),
|
basicFee_basic: sumNumbers(det.map(item => item.basicFee_basic)),
|
||||||
@ -1255,13 +1133,10 @@ const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | n
|
|||||||
const buildMethod2 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod2 | null => {
|
const buildMethod2 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod2 | null => {
|
||||||
if (!Array.isArray(rows)) return null
|
if (!Array.isArray(rows)) return null
|
||||||
let hasTotalValue = false
|
let hasTotalValue = false
|
||||||
const proSet = new Set<number>()
|
|
||||||
const det = rows
|
const det = rows
|
||||||
.map(row => {
|
.map(row => {
|
||||||
const major = toScaleMajorId(row)
|
const major = toSafeInteger(row.id)
|
||||||
if (major == null || row.budgetFee == null) return null
|
if (major == null || row.budgetFee == null) return null
|
||||||
const proNum = toScaleProNum(row)
|
|
||||||
proSet.add(proNum)
|
|
||||||
const area = toFiniteNumber(row.landArea)
|
const area = toFiniteNumber(row.landArea)
|
||||||
const basicFee = toFiniteNumber(row.budgetFee)
|
const basicFee = toFiniteNumber(row.budgetFee)
|
||||||
if (basicFee != null) hasTotalValue = true
|
if (basicFee != null) hasTotalValue = true
|
||||||
@ -1276,7 +1151,6 @@ const buildMethod2 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod2 | n
|
|||||||
isNonEmptyString(remark)
|
isNonEmptyString(remark)
|
||||||
if (!hasValue) return null
|
if (!hasValue) return null
|
||||||
return {
|
return {
|
||||||
proNum,
|
|
||||||
major,
|
major,
|
||||||
area: area ?? 0,
|
area: area ?? 0,
|
||||||
basicFee: basicFee ?? 0,
|
basicFee: basicFee ?? 0,
|
||||||
@ -1296,7 +1170,6 @@ const buildMethod2 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod2 | n
|
|||||||
|
|
||||||
if (det.length === 0 || !hasTotalValue) return null
|
if (det.length === 0 || !hasTotalValue) return null
|
||||||
return {
|
return {
|
||||||
proAmount: proSet.size > 0 ? proSet.size : 1,
|
|
||||||
area: sumNumbers(det.map(item => item.area)),
|
area: sumNumbers(det.map(item => item.area)),
|
||||||
basicFee: sumNumbers(det.map(item => item.basicFee)),
|
basicFee: sumNumbers(det.map(item => item.basicFee)),
|
||||||
basicFee_basic: sumNumbers(det.map(item => item.basicFee_basic)),
|
basicFee_basic: sumNumbers(det.map(item => item.basicFee_basic)),
|
||||||
@ -1480,50 +1353,6 @@ const loadHtFeeMethodsByRow = async (mainStorageKey: string, rowId: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildServiceGroupLabelToIdMap = (serviceIds: string[]): Map<string, number> => {
|
|
||||||
const map = new Map<string, number>()
|
|
||||||
for (const serviceId of serviceIds) {
|
|
||||||
const item = (serviceList as Record<string, any>)[serviceId]
|
|
||||||
if (!item) continue
|
|
||||||
const id = toSafeInteger(serviceId)
|
|
||||||
if (id == null) continue
|
|
||||||
const label = `${String(item.code || '').trim()} ${String(item.name || '').trim()}`.trim()
|
|
||||||
if (!label) continue
|
|
||||||
map.set(label, id)
|
|
||||||
}
|
|
||||||
return map
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildServiceTasks = async (
|
|
||||||
contractId: string,
|
|
||||||
serviceId: string,
|
|
||||||
serviceLabelToId: Map<string, number>
|
|
||||||
): Promise<ExportTaskGroup[]> => {
|
|
||||||
const taskState = await zxFwPricingStore.loadKeyState<WorkContentStateLike>(`work-content-${contractId}-${serviceId}`)
|
|
||||||
return groupWorkContentTasks(taskState?.detailRows, { serviceLabelToId })
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildAdditionalRowTasks = async (contractId: string, rowId: string): Promise<ExportTaskGroup[]> => {
|
|
||||||
const taskStorageKey = `work-content-htExtraFee-${contractId}-additional-work-${rowId}`
|
|
||||||
const taskState = await zxFwPricingStore.loadKeyState<WorkContentStateLike>(taskStorageKey)
|
|
||||||
return groupWorkContentTasks(taskState?.detailRows, { forceUngroup: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildServiceFinalFee = (
|
|
||||||
row: ZxFwRowLike | null | undefined,
|
|
||||||
method1: ExportMethod1 | null,
|
|
||||||
method2: ExportMethod2 | null,
|
|
||||||
method3: ExportMethod3 | null,
|
|
||||||
method4: ExportMethod4 | null
|
|
||||||
) => {
|
|
||||||
const finalFee = toFiniteNumber(row?.finalFee)
|
|
||||||
if (finalFee != null) return finalFee
|
|
||||||
const subtotal = toFiniteNumber(row?.subtotal)
|
|
||||||
if (subtotal != null) return subtotal
|
|
||||||
const methodSum = sumNumbers([method1?.fee, method2?.fee, method3?.fee, method4?.fee])
|
|
||||||
return methodSum
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const buildAdditionalExport = async (contractId: string): Promise<ExportAdditional | null> => {
|
const buildAdditionalExport = async (contractId: string): Promise<ExportAdditional | null> => {
|
||||||
@ -1534,17 +1363,15 @@ const buildAdditionalExport = async (contractId: string): Promise<ExportAddition
|
|||||||
|
|
||||||
const det = (
|
const det = (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
rows.map(async row => {
|
rows.map(async (row, index) => {
|
||||||
const methodPayload = await loadHtFeeMethodsByRow(storageKey, row.id)
|
const methodPayload = await loadHtFeeMethodsByRow(storageKey, row.id)
|
||||||
if (!methodPayload) return null
|
if (!methodPayload) return null
|
||||||
const tasks = await buildAdditionalRowTasks(contractId, row.id)
|
|
||||||
const item: ExportAdditionalDetail = {
|
const item: ExportAdditionalDetail = {
|
||||||
id: row.id,
|
id: index,
|
||||||
code: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'F' }] },
|
code: { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: 'C' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: 'F' }] },
|
||||||
|
|
||||||
name: row.name,
|
name: row.name,
|
||||||
fee: methodPayload.fee,
|
fee: methodPayload.fee
|
||||||
tasks
|
|
||||||
}
|
}
|
||||||
if (methodPayload.m0) item.m0 = methodPayload.m0
|
if (methodPayload.m0) item.m0 = methodPayload.m0
|
||||||
if (methodPayload.m4) item.m4 = methodPayload.m4
|
if (methodPayload.m4) item.m4 = methodPayload.m4
|
||||||
@ -1575,8 +1402,7 @@ const buildReserveExport = async (contractId: string): Promise<ExportReserve | n
|
|||||||
if (!methodPayload) continue
|
if (!methodPayload) continue
|
||||||
const reserve: ExportReserve = {
|
const reserve: ExportReserve = {
|
||||||
name: row.name || '预备费',
|
name: row.name || '预备费',
|
||||||
fee: methodPayload.fee,
|
fee: methodPayload.fee
|
||||||
tasks: []
|
|
||||||
}
|
}
|
||||||
if (methodPayload.m0) reserve.m0 = methodPayload.m0
|
if (methodPayload.m0) reserve.m0 = methodPayload.m0
|
||||||
if (methodPayload.m4) reserve.m4 = methodPayload.m4
|
if (methodPayload.m4) reserve.m4 = methodPayload.m4
|
||||||
@ -1610,11 +1436,8 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
const projectName = isNonEmptyString(projectInfo.projectName) ? projectInfo.projectName.trim() : '造价项目'
|
const projectName = isNonEmptyString(projectInfo.projectName) ? projectInfo.projectName.trim() : '造价项目'
|
||||||
const writer = isNonEmptyString(projectInfo.preparedBy) ? projectInfo.preparedBy.trim() : ''
|
const writer = isNonEmptyString(projectInfo.preparedBy) ? projectInfo.preparedBy.trim() : ''
|
||||||
const reviewer = isNonEmptyString(projectInfo.reviewedBy) ? projectInfo.reviewedBy.trim() : ''
|
const reviewer = isNonEmptyString(projectInfo.reviewedBy) ? projectInfo.reviewedBy.trim() : ''
|
||||||
const company = isNonEmptyString(projectInfo.preparedCompany) ? projectInfo.preparedCompany.trim() : ''
|
|
||||||
const date = isNonEmptyString(projectInfo.preparedDate) ? projectInfo.preparedDate.trim() : ''
|
const date = isNonEmptyString(projectInfo.preparedDate) ? projectInfo.preparedDate.trim() : ''
|
||||||
const industry = mapIndustryCodeToExportIndustry(projectInfo.projectIndustry)
|
const industry = mapIndustryCodeToExportIndustry(projectInfo.projectIndustry)
|
||||||
const overview = isNonEmptyString(projectInfo.overview) ? projectInfo.overview.trim() : ''
|
|
||||||
const desc = isNonEmptyString(projectInfo.desc) ? projectInfo.desc.trim() : ''
|
|
||||||
|
|
||||||
const contractCards = (Array.isArray(contractCardsRaw) ? contractCardsRaw : [])
|
const contractCards = (Array.isArray(contractCardsRaw) ? contractCardsRaw : [])
|
||||||
.filter(item => item && typeof item.id === 'string')
|
.filter(item => item && typeof item.id === 'string')
|
||||||
@ -1626,12 +1449,11 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
const contract = contractCards[index]
|
const contract = contractCards[index]
|
||||||
const contractId = contract.id
|
const contractId = contract.id
|
||||||
await zxFwPricingStore.loadContract(contractId)
|
await zxFwPricingStore.loadContract(contractId)
|
||||||
const [htInfoRaw, zxFwRaw, htConsultCategoryFactorRaw, htMajorFactorRaw, htBaseInfoRaw] = await Promise.all([
|
const [htInfoRaw, zxFwRaw, htConsultCategoryFactorRaw, htMajorFactorRaw] = await Promise.all([
|
||||||
kvStore.getItem<DetailRowsStorageLike<ScaleRowLike>>(`ht-info-v3-${contractId}`),
|
kvStore.getItem<DetailRowsStorageLike<ScaleRowLike>>(`ht-info-v3-${contractId}`),
|
||||||
kvStore.getItem<ZxFwStorageLike>(`zxFW-${contractId}`),
|
kvStore.getItem<ZxFwStorageLike>(`zxFW-${contractId}`),
|
||||||
kvStore.getItem<DetailRowsStorageLike<FactorRowLike>>(`ht-consult-category-factor-v1-${contractId}`),
|
kvStore.getItem<DetailRowsStorageLike<FactorRowLike>>(`ht-consult-category-factor-v1-${contractId}`),
|
||||||
kvStore.getItem<DetailRowsStorageLike<FactorRowLike>>(`ht-major-factor-v1-${contractId}`),
|
kvStore.getItem<DetailRowsStorageLike<FactorRowLike>>(`ht-major-factor-v1-${contractId}`)
|
||||||
kvStore.getItem<HtBaseInfoLike>(`ht-base-info-${contractId}`)
|
|
||||||
])
|
])
|
||||||
|
|
||||||
const contractState = zxFwPricingStore.getContractState(contractId)
|
const contractState = zxFwPricingStore.getContractState(contractId)
|
||||||
@ -1640,7 +1462,6 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
id: String(row.id || ''),
|
id: String(row.id || ''),
|
||||||
process: row.process,
|
process: row.process,
|
||||||
subtotal: row.subtotal,
|
subtotal: row.subtotal,
|
||||||
finalFee: row.finalFee,
|
|
||||||
investScale: row.investScale,
|
investScale: row.investScale,
|
||||||
landScale: row.landScale,
|
landScale: row.landScale,
|
||||||
workload: row.workload,
|
workload: row.workload,
|
||||||
@ -1673,7 +1494,6 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
const serviceIdTexts = sortServiceIdsByDict(
|
const serviceIdTexts = sortServiceIdsByDict(
|
||||||
(selectedIds.length > 0 ? selectedIds : fallbackServiceIds).filter(hasServiceId)
|
(selectedIds.length > 0 ? selectedIds : fallbackServiceIds).filter(hasServiceId)
|
||||||
)
|
)
|
||||||
const serviceLabelToId = buildServiceGroupLabelToIdMap(serviceIdTexts)
|
|
||||||
|
|
||||||
const services = (
|
const services = (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@ -1698,15 +1518,11 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
const method3 = buildMethod3(method3Raw?.detailRows)
|
const method3 = buildMethod3(method3Raw?.detailRows)
|
||||||
const method4 = buildMethod4(method4Raw?.detailRows)
|
const method4 = buildMethod4(method4Raw?.detailRows)
|
||||||
const fee = buildServiceFee(sourceRow, method1, method2, method3, method4)
|
const fee = buildServiceFee(sourceRow, method1, method2, method3, method4)
|
||||||
const finalFee = buildServiceFinalFee(sourceRow, method1, method2, method3, method4)
|
|
||||||
const tasks = await buildServiceTasks(contractId, serviceIdText, serviceLabelToId)
|
|
||||||
const process = Number(sourceRow?.process) === 1 ? 1 : 0
|
const process = Number(sourceRow?.process) === 1 ? 1 : 0
|
||||||
const service: ExportService = {
|
const service: ExportService = {
|
||||||
id: serviceId,
|
id: serviceId,
|
||||||
process,
|
process,
|
||||||
fee,
|
fee
|
||||||
finalFee,
|
|
||||||
tasks
|
|
||||||
}
|
}
|
||||||
if (method1) service.method1 = method1
|
if (method1) service.method1 = method1
|
||||||
if (method2) service.method2 = method2
|
if (method2) service.method2 = method2
|
||||||
@ -1748,8 +1564,6 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
addtionalFee,
|
addtionalFee,
|
||||||
reserveFee,
|
reserveFee,
|
||||||
fee: contractFee,
|
fee: contractFee,
|
||||||
quality: isNonEmptyString(htBaseInfoRaw?.quality) ? htBaseInfoRaw.quality.trim() : '',
|
|
||||||
duration: isNonEmptyString(htBaseInfoRaw?.duration) ? htBaseInfoRaw.duration.trim() : '',
|
|
||||||
scale: contractScale,
|
scale: contractScale,
|
||||||
serviceCoes: contractServiceCoesRaw,
|
serviceCoes: contractServiceCoesRaw,
|
||||||
majorCoes: contractMajorCoesRaw,
|
majorCoes: contractMajorCoesRaw,
|
||||||
@ -1763,13 +1577,10 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
|||||||
name: projectName,
|
name: projectName,
|
||||||
writer,
|
writer,
|
||||||
reviewer,
|
reviewer,
|
||||||
company,
|
|
||||||
date,
|
date,
|
||||||
industry,
|
industry,
|
||||||
fee: sumNumbers(contracts.map(item => item.fee)),
|
fee: sumNumbers(contracts.map(item => item.fee)),
|
||||||
scaleCost: projectScaleCost,
|
scaleCost: projectScaleCost,
|
||||||
overview,
|
|
||||||
desc,
|
|
||||||
scale: projectScale,
|
scale: projectScale,
|
||||||
serviceCoes: projectServiceCoes,
|
serviceCoes: projectServiceCoes,
|
||||||
majorCoes: projectMajorCoes,
|
majorCoes: projectMajorCoes,
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
PinnedRowModule,
|
PinnedRowModule,
|
||||||
RowAutoHeightModule,
|
RowAutoHeightModule,
|
||||||
TextEditorModule,
|
TextEditorModule,
|
||||||
TooltipModule,ClientSideRowModelApiModule ,
|
TooltipModule,
|
||||||
UndoRedoEditModule,RenderApiModule ,ColumnApiModule ,CellSpanModule ,RowStyleModule ,RowSelectionModule
|
UndoRedoEditModule,RenderApiModule ,ColumnApiModule ,CellSpanModule ,RowStyleModule ,RowSelectionModule
|
||||||
|
|
||||||
} from 'ag-grid-community'
|
} from 'ag-grid-community'
|
||||||
@ -39,7 +39,7 @@ const AG_GRID_MODULES = [
|
|||||||
RowAutoHeightModule,ContextMenuModule,
|
RowAutoHeightModule,ContextMenuModule,
|
||||||
LargeTextEditorModule,
|
LargeTextEditorModule,
|
||||||
UndoRedoEditModule,
|
UndoRedoEditModule,
|
||||||
CellStyleModule,ClientSideRowModelApiModule ,
|
CellStyleModule,
|
||||||
PinnedRowModule,RenderApiModule ,ColumnApiModule ,
|
PinnedRowModule,RenderApiModule ,ColumnApiModule ,
|
||||||
TooltipModule,
|
TooltipModule,
|
||||||
TreeDataModule,
|
TreeDataModule,
|
||||||
|
|||||||
92
src/sql.ts
92
src/sql.ts
@ -11,34 +11,6 @@ const toFiniteNumber = (value: unknown) => {
|
|||||||
const num = Number(value)
|
const num = Number(value)
|
||||||
return Number.isFinite(num) ? num : 0
|
return Number.isFinite(num) ? num : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 兼容导出 tasks 对象结构:[{ text: [] }, { serviceid, text: [] }]
|
|
||||||
const normalizeTaskTexts = (tasks: unknown): string[] => {
|
|
||||||
if (!Array.isArray(tasks)) return [];
|
|
||||||
const result: string[] = [];
|
|
||||||
const seen = new Set<string>();
|
|
||||||
const pushText = (value: unknown) => {
|
|
||||||
const text = String(value ?? '').trim();
|
|
||||||
if (!text) return;
|
|
||||||
if (seen.has(text)) return;
|
|
||||||
seen.add(text);
|
|
||||||
result.push(text);
|
|
||||||
};
|
|
||||||
tasks.forEach(item => {
|
|
||||||
if (typeof item === 'string') {
|
|
||||||
pushText(item);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!item || typeof item !== 'object') return;
|
|
||||||
const textField = item.text;
|
|
||||||
if (Array.isArray(textField)) {
|
|
||||||
textField.forEach(pushText);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pushText(textField);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
export type WorkType = '基本工作' | '可选工作' | '日常顾问' | '专项顾问' | '附加工作' | '自定义'
|
export type WorkType = '基本工作' | '可选工作' | '日常顾问' | '专项顾问' | '附加工作' | '自定义'
|
||||||
|
|
||||||
export const TYPE_LABEL_MAP: Record<number, WorkType> = {
|
export const TYPE_LABEL_MAP: Record<number, WorkType> = {
|
||||||
@ -825,7 +797,7 @@ export async function exportFile(fileName: string, data: any | (() => Promise<an
|
|||||||
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||||
const url1 = window.URL.createObjectURL(blob);
|
const url1 = window.URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url1;
|
a.hcode = url1;
|
||||||
a.download = `${fileName}.xlsx`;
|
a.download = `${fileName}.xlsx`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url1);
|
URL.revokeObjectURL(url1);
|
||||||
@ -839,6 +811,7 @@ export async function exportFile(fileName: string, data: any | (() => Promise<an
|
|||||||
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
|
// 按模板生成最终工作簿:填充封面、目录、各分表及汇总数据。
|
||||||
async function generateTemplate(data) {
|
async function generateTemplate(data) {
|
||||||
// const downTextTmp = { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '常规' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: '下标' }] };
|
// const downTextTmp = { richText: [{ font: { charset: 134, color: { theme: 1 }, italic: true, name: '宋体', size: 10 }, text: '常规' }, { font: { charset: 134, color: { theme: 1 }, italic: true, name: 'Calibri', size: 10, vertAlign: 'subscript' }, text: '下标' }] };
|
||||||
|
console.log(data)
|
||||||
// 编制说明 → 工作内容的前后默认项
|
// 编制说明 → 工作内容的前后默认项
|
||||||
let prefixIDs = [6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
|
let prefixIDs = [6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
|
||||||
let suffixIDs = [6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
|
let suffixIDs = [6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
|
||||||
@ -2286,9 +2259,8 @@ async function generateTemplate(data) {
|
|||||||
targetRow.getCell(1).value = ` (${ciTastNum})${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
|
targetRow.getCell(1).value = ` (${ciTastNum})${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
|
||||||
ciTastNum++;
|
ciTastNum++;
|
||||||
});
|
});
|
||||||
const additionalTaskTexts = normalizeTaskTexts(ai.tasks);
|
if (ai.tasks?.length) {
|
||||||
if (additionalTaskTexts.length) {
|
ai.tasks.forEach((ati, atindex) => {
|
||||||
additionalTaskTexts.forEach((ati, atindex) => {
|
|
||||||
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1})${ati}。`, ctx);
|
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1})${ati}。`, ctx);
|
||||||
atiTextArr.forEach(ti => {
|
atiTextArr.forEach(ti => {
|
||||||
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
|
cusInsertRowFunc(descRowNum, [descSheet.getRow(descRowNum - 1)], descSheet, (targetRow) => {
|
||||||
@ -2403,25 +2375,41 @@ async function generateTemplate(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
ci.services.forEach((si, sindex) => {
|
ci.services.forEach((si, sindex) => {
|
||||||
let siTextArr = paragraphLineBreakFor1112(` (${ciTastNum})${si.process == null ? '' : (si.process == 1 ? '审核' : '编制')}${serviceList[si.id].name},具体工作内容包括:`, ctx);
|
let flag = false;
|
||||||
siTextArr.forEach(ti => {
|
|
||||||
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
|
||||||
descRowNum3++;
|
|
||||||
targetRow.getCell(1).value = ti;
|
|
||||||
ciTastNum++;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (si.tasks?.length) {
|
if (si.tasks?.length) {
|
||||||
si.tasks.forEach((sti, stindex) => {
|
si.tasks.forEach(tsi => {
|
||||||
let stiTextArr = paragraphLineBreakFor1112(` ${stindex + 1})${sti}。`, ctx);
|
if (tsi.text?.length) {
|
||||||
stiTextArr.forEach(ti => {
|
flag = true;
|
||||||
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
let sx = tsi.serviceid == null ? { id: si.id, process: si.process } : { id: tsi.serviceid, process: tsi.process };
|
||||||
descRowNum3++;
|
let tsiTextArr = paragraphLineBreakFor1112(` (${ciTastNum})${sx.process == null ? '完成' : (sx.process == 1 ? '审核' : '编制')}${serviceList[sx.id].name},具体工作内容包括:`, ctx);
|
||||||
targetRow.getCell(1).value = ti;
|
tsiTextArr.forEach(ti => {
|
||||||
|
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
||||||
|
descRowNum3++;
|
||||||
|
targetRow.getCell(1).value = ti;
|
||||||
|
ciTastNum++;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
tsi.text.forEach((sti, stindex) => {
|
||||||
|
let stiTextArr = paragraphLineBreakFor1112(` ${stindex + 1})${sti}。`, ctx);
|
||||||
|
stiTextArr.forEach(ti => {
|
||||||
|
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
||||||
|
descRowNum3++;
|
||||||
|
targetRow.getCell(1).value = ti;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!flag) {
|
||||||
|
let siTextArr = paragraphLineBreakFor1112(` (${ciTastNum})${si.process == null ? '完成' : (si.process == 1 ? '审核' : '编制')}${serviceList[si.id].name},具体工作内容包括:`, ctx);
|
||||||
|
siTextArr.forEach(ti => {
|
||||||
|
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
||||||
|
descRowNum3++;
|
||||||
|
targetRow.getCell(1).value = ti;
|
||||||
|
ciTastNum++;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
||||||
descRowNum3++;
|
descRowNum3++;
|
||||||
targetRow.getCell(1).value = ' 1)×××××。';
|
targetRow.getCell(1).value = ' 1)×××××。';
|
||||||
@ -2435,9 +2423,8 @@ async function generateTemplate(data) {
|
|||||||
targetRow.getCell(1).value = ` (${ciTastNum})${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
|
targetRow.getCell(1).value = ` (${ciTastNum})${ai.id == 1 ? '负责协调工作,具体工作内容包括:' : '其他附加工作,具体工作内容包括:'}`;
|
||||||
ciTastNum++;
|
ciTastNum++;
|
||||||
});
|
});
|
||||||
const additionalTaskTexts = normalizeTaskTexts(ai.tasks);
|
if (ai.tasks?.length) {
|
||||||
if (additionalTaskTexts.length) {
|
ai.tasks.forEach((ati, atindex) => {
|
||||||
additionalTaskTexts.forEach((ati, atindex) => {
|
|
||||||
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1})${ati}。`, ctx);
|
let atiTextArr = paragraphLineBreakFor1112(` ${atindex + 1})${ati}。`, ctx);
|
||||||
atiTextArr.forEach(ti => {
|
atiTextArr.forEach(ti => {
|
||||||
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
cusInsertRowFunc(descRowNum3, [descSheet.getRow(descRowNum3 - 1)], descSheet, (targetRow) => {
|
||||||
@ -2533,10 +2520,9 @@ async function generateTemplate(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (String(data.desc || '').trim()) {
|
if (data.desc) {
|
||||||
descRowNum++;
|
descRowNum++;
|
||||||
const otherDescText = String(data.desc || '').trim();
|
let otherDesc = paragraphLineBreakFor1112(` ${data.desc}${/。$/.test(ci.duration) ? '' : '。'}`, ctx);
|
||||||
let otherDesc = paragraphLineBreakFor1112(` ${otherDescText}${/。$/.test(otherDescText) ? '' : '。'}`, ctx);
|
|
||||||
descSheet.getRow(descRowNum).getCell(1).value = otherDesc[0];
|
descSheet.getRow(descRowNum).getCell(1).value = otherDesc[0];
|
||||||
descRowNum++;
|
descRowNum++;
|
||||||
if (otherDesc.length > 1) {
|
if (otherDesc.length > 1) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user