import { DataModel, transformArrayDataModel, transformDataModel, type KeyValue } from '@imengyu/js-request-transform'; import { AppServerRequestModule } from '../RequestModules'; import { transformSomeToArray } from '../Utils'; import ApiCofig from '@/common/config/ApiCofig'; import { appendGetUrlParams } from '@imengyu/imengyu-utils'; import { useAuthStore } from '@/stores/auth'; /** * 自查评估 / 传承协议相关接口(ShowDoc) * @see https://www.showdoc.com.cn/minnanCE/11559060626966335 列表 * @see https://www.showdoc.com.cn/minnanCE/11559060626887140 传承协议编辑 * @see https://www.showdoc.com.cn/minnanCE/11559060626966336 评估表编辑/新增 * @see https://www.showdoc.com.cn/minnanCE/11559060626966337 详情 */ /** 计分点项(getCheckItems) */ export class CheckItemInfo extends DataModel { constructor() { super(CheckItemInfo, '自查计分项目'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, pid: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'number' }, points: { clientSide: 'number', serverSide: 'number' }, isTitle: { clientSide: 'boolean', serverSide: 'number' }, isMulitCheck: { clientSide: 'boolean', serverSide: 'number' }, }; } id = 0 as number; pid = 0 as number; name = '' as string; level = 0 as number; points = 0 as number; isTitle = false; isMulitCheck = false; /** 1=单选,2=多选,3=次数 */ checkType = 0 as number; children: CheckItemInfo[] = []; } /** 自查评估表列表行 */ export class SelfAssessmentListRow extends DataModel { constructor() { super(SelfAssessmentListRow, '自查评估表列表项'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, userId: { clientSide: 'number', serverSide: 'number' }, year: { clientSide: 'number', serverSide: 'number' }, weigh: { clientSide: 'number', serverSide: 'number' }, deductPoints: { clientSide: 'number', serverSide: 'number' }, points: { clientSide: 'number', serverSide: 'number' }, self: { clientSide: 'number', serverSide: 'number' }, ichUnit: { clientSide: 'number', serverSide: 'number' }, unitPoints: { clientSide: 'number', serverSide: 'number' }, county: { clientSide: 'number', serverSide: 'number' }, countyPoints: { clientSide: 'number', serverSide: 'number' }, district: { clientSide: 'number', serverSide: 'number' }, districtPoints: { clientSide: 'number', serverSide: 'number' }, province: { clientSide: 'number', serverSide: 'number' }, provincePoints: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'string' }, }; this._convertKeyType = (key) => { if (key.endsWith('Text') || key.endsWith('_text')) { return { clientSide: 'string', serverSide: 'undefined' }; } return undefined; }; } id = 0 as number; userId = 0 as number; year = 0 as number; inheritor = '' as string|null; unit = '' as string|null; ichName = '' as string|null; mobile = '' as string|null; idCard = '' as string|null; level = null as number|string|null; address = '' as string|null; weigh = 0 as number; deductPoints = 0 as number; points = 0 as number; self = null as number|null; ichUnit = null as number|null; unitPoints = 0 as number; county = null as number|null; countyPoints = 0 as number; district = null as number|null; districtPoints = 0 as number; province = null as number|null; provincePoints = 0 as number; createtime = '' as string; updatetime = '' as string; selfText = '' as string; } /** 传承协议列表行 */ export class AgreementListRow extends DataModel { constructor() { super(AgreementListRow, '传承协议列表项'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, userId: { clientSide: 'number', serverSide: 'number' }, year: { clientSide: 'number', serverSide: 'number' }, apprentice: { clientSide: 'number', serverSide: 'number' }, activity: { clientSide: 'number', serverSide: 'number' }, course: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'number' }, }; } id = 0 as number; userId = 0 as number; level = null as number|null; year = 0 as number; partyA = '' as string|null; partyB = '' as string|null; apprentice = 0 as number; activity = 0 as number; course = 0 as number; mobile = '' as string|null; partyAMobile = '' as string|null; idCard = '' as string|null; health = '' as string|null; ich = '' as string|null; partyASign = '' as string|null; partyBSign = '' as string|null; createtime = '' as string; updatetime = '' as string; deletetime = '' as string|null; } /** 传承人基础信息(ich/check/basic) */ export class InheritorCheckBasicInfo extends DataModel { constructor() { super(InheritorCheckBasicInfo, '传承人自查基础信息'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { userId: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'number' }, batch: { clientSide: 'number', serverSide: 'number' }, }; this._convertKeyType = (key) => { if (key.endsWith('Text') || key.endsWith('_text')) { return { clientSide: 'string', serverSide: 'undefined' }; } return undefined; }; } userId = 0 as number; name = '' as string; region = '' as string; gender = '' as string; education = '' as string|null; ichName = '' as string; unit = '' as string; level = 0 as number; idCard = '' as string; address = '' as string; batch = 0 as number; mobile = '' as string; genderText = '' as string; educationText = '' as string; levelText = '' as string; regionText = '' as string; /** 已填写的传承协议ID */ agreementId = 0 as number; /** 已填写的自查表ID */ checkId = 0 as number; } /** 详情中已选计分项 */ export class SelfAssessmentCheckItemAnswer extends DataModel { constructor() { super(SelfAssessmentCheckItemAnswer, '自查计分选项'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, points: { clientSide: 'number', serverSide: 'number' }, count: { clientSide: 'number', serverSide: 'number' }, }; this._afterSolveServer = (data) => { if (data.itemId) data.id = data.itemId; } } id = 0 as number; points = 0 as number; count = 0 as number; } /** 自查评估表详情 */ export class SelfAssessmentDetail extends DataModel { constructor() { super(SelfAssessmentDetail, '自查评估表详情'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, userId: { clientSide: 'number', serverSide: 'number' }, year: { clientSide: 'number', serverSide: 'number' }, weigh: { clientSide: 'number', serverSide: 'number' }, deductPoints: { clientSide: 'number', serverSide: 'number' }, points: { clientSide: 'number', serverSide: 'number' }, self: { clientSide: 'number', serverSide: 'number' }, ichUnit: { clientSide: 'number', serverSide: 'number' }, unitPoints: { clientSide: 'number', serverSide: 'number' }, county: { clientSide: 'number', serverSide: 'number' }, countyPoints: { clientSide: 'number', serverSide: 'number' }, district: { clientSide: 'number', serverSide: 'number' }, districtPoints: { clientSide: 'number', serverSide: 'number' }, province: { clientSide: 'number', serverSide: 'number' }, provincePoints: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'string' }, content: { customToClientFn: (value) => { try { return JSON.parse(value as string); } catch { return {}; } }, customToServerFn: (value) => { return value; }, }, awardTime: { clientSide: 'dayjs', clientSideDateFormat: 'YYYY-MM-DD', serverSide: 'string', serverSideDateFormat: 'YYYY-MM-DD', }, checkItems: { customToClientFn: (value) => { return transformArrayDataModel(SelfAssessmentCheckItemAnswer, transformSomeToArray(value), 'data'); }, customToServerFn: (value) => { return (value as SelfAssessmentCheckItemAnswer[]) .filter(item => item.count > 0) .map((item) => { return { id: item.id, count: item.count, }; }); }, }, }; this._blackList.toServer = [ 'createtime', 'updatetime', 'deletetime', ] this._convertKeyType = (key) => { if (key.endsWith('Text') || key.endsWith('_text')) { return { clientSide: 'string', serverSide: 'undefined' }; } return undefined; }; this._beforeSolveClient = (data) => { if (data.id == 0) delete data.id; return data; } } id = 0 as number; userId = 0 as number; year = 0 as number; inheritor = '' as string|null; unit = '' as string|null; ichName = '' as string|null; mobile = '' as string|null; idCard = '' as string|null; level = null as number|string|null; address = '' as string|null; content : Record|null = null; weigh = 0 as number; awardTime = new Date(); deductContent = '' as string|null; deductPoints = 0 as number; points = 0 as number; self = null as number|null; sign = '' as string|null; ichUnit = null as number|null; unitPoints = 0 as number; county = null as number|null; countyPoints = 0 as number; district = null as number|null; districtPoints = 0 as number; province = null as number|null; provincePoints = 0 as number; createtime = '' as string; updatetime = '' as string; deletetime = '' as string|null; selfText = '' as string; checkItems : SelfAssessmentCheckItemAnswer[] = []; } /** 传承协议详情 */ export class AgreementDetail extends DataModel { constructor() { super(AgreementDetail, '传承协议详情'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, userId: { clientSide: 'number', serverSide: 'number' }, year: { clientSide: 'number', serverSide: 'number' }, apprentice: { clientSide: 'number', serverSide: 'number' }, activity: { clientSide: 'number', serverSide: 'number' }, course: { clientSide: 'number', serverSide: 'number' }, level: { clientSide: 'number', serverSide: 'number' }, updatetime: { clientSide: 'date', serverSide: 'undefined' }, }; this._nameMapperClient = { partyA: 'party_a', partyB: 'party_b', partyASign: 'party_a_sign', partyBSign: 'party_b_sign', partyAMobile: 'party_a_mobile', } this._blackList.toServer = [ 'createtime', 'updatetime', 'deletetime', ] this._beforeSolveClient = (data) => { if (data.id == 0) delete data.id; return data; } } id = 0 as number; userId = 0 as number; level = null as number|null; year = 0 as number; partyA = '' as string|null; partyB = '' as string|null; apprentice = 0 as number; activity = 0 as number; course = 0 as number; mobile = '' as string|null; partyAMobile = '' as string|null; idCard = '' as string|null; health = '' as string|null; ich = '' as string|null; partyASign = '' as string|null; partyBSign = '' as string|null; updatetime = new Date(); } /** 证明材料附件类型(saveAnnex `type`) */ export const CheckAnnexType = { Image: 1, Video: 2, Audio: 3, Document: 4, Other: 5, ExternalLink: 6, } as const; export function getCheckAnnexType(mimetype: string) { if (mimetype.startsWith('image/')) return CheckAnnexType.Image; if (mimetype.startsWith('video/')) return CheckAnnexType.Video; if (mimetype.startsWith('audio/')) return CheckAnnexType.Audio; if (mimetype.startsWith('application/pdf')) return CheckAnnexType.Document; return CheckAnnexType.Other; } export type CheckAnnexTypeValue = (typeof CheckAnnexType)[keyof typeof CheckAnnexType]; /** 证明材料修改与新增请求体(POST /ich/check/saveAnnex) */ export interface SaveCheckAnnexPayload { id?: number; name: string; formId: number; url: string; type: CheckAnnexTypeValue | number; desc?: string; mimetype?: string; attachId?: number; fileSize?: number; } /** 证明材料列表项(getAnnexList) */ export class CheckAnnexListItem extends DataModel { constructor() { super(CheckAnnexListItem, '证明材料列表项'); this.setNameMapperCase('Camel', 'Snake'); this._convertTable = { id: { clientSide: 'number', serverSide: 'number' }, formId: { clientSide: 'number', serverSide: 'number' }, type: { clientSide: 'number', serverSide: 'number' }, attachId: { clientSide: 'number', serverSide: 'number' }, fileSize: { clientSide: 'number', serverSide: 'number' }, }; } id = 0 as number; name = '' as string; formId = 0 as number; url = '' as string; type = 0 as number; desc = '' as string|null; mimetype = '' as string|null; attachId = null as number|null; fileSize = null as number|null; createtime = '' as string|null; updatetime = '' as string|null; } export type IchCheckPaginated = { total: number; perPage: number; currentPage: number; lastPage: number; data: T[]; }; function normalizePaginated(rowClass: new () => T, raw: KeyValue): IchCheckPaginated { return { total: Number(raw.total ?? 0), perPage: Number(raw.per_page ?? 0), currentPage: Number(raw.current_page ?? 0), lastPage: Number(raw.last_page ?? 0), data: transformArrayDataModel(rowClass, transformSomeToArray(raw.data), 'data'), }; } function buildPdfUrl(baseUrl: string, path: string, id: number) { const auth = useAuthStore(); let url = `${baseUrl}${path}?id=${encodeURIComponent(String(id))}`; url = appendGetUrlParams(url, 'main_body_id', ApiCofig.mainBodyId); url = appendGetUrlParams(url, 'token', auth.token); return url; } async function downloadPdfBlob(path: string, id: number, baseUrl: string, defaultFilename: string) { const url = buildPdfUrl(baseUrl, path, id); const auth = useAuthStore(); const res = await fetch(url, { method: 'GET', headers: { token: auth.token, __token__: auth.token, }, }); if (!res.ok) throw new Error('下载失败,状态码:' + res.status); const blob = await res.blob(); const objectUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = objectUrl; a.download = defaultFilename; a.rel = 'noopener'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(objectUrl); } export class AssessmentContentApi extends AppServerRequestModule { constructor() { super(); } async getCheckItems(level: number) { const res = await this.post('/ich/check/getCheckItems', { level }, '自查计分项目'); const list = transformSomeToArray(res.data) as KeyValue[]; const items = transformArrayDataModel(CheckItemInfo, list, 'data') as CheckItemInfo[]; const map = new Map(); for (const item of items) map.set(item.id, item); const top = items.filter((item) => item.pid === 0); for (const item of items) item.children = items.filter((i) => i.pid === item.id); return { top, map, }; } async getSelfAssessmentList(data: { userId?: number; level?: number; year?: number; keywords?: string; page?: number; pageSize?: number; }) { const res = await this.post('/ich/check/getList', { user_id: data.userId, level: data.level, year: data.year, keywords: data.keywords, page: data.page, pageSize: data.pageSize, }, '评估表列表'); return normalizePaginated(SelfAssessmentListRow, res.data as KeyValue); } async getAgreementList(data: { userId?: number; level?: number; year?: number; keywords?: string; page?: number; pageSize?: number; }) { const res = await this.post('/ich/check/getAgreementList', { user_id: data.userId, level: data.level, year: data.year, keywords: data.keywords, page: data.page, pageSize: data.pageSize, }, '传承协议列表'); return normalizePaginated(AgreementListRow, res.data as KeyValue); } async saveAgreement(dataModel: AgreementDetail) { return this.post('/ich/check/saveAgreement', dataModel.toServerSide(), '传承协议保存'); } async saveSelfAssessment(dataModel: SelfAssessmentDetail) { return this.post('/ich/check/save', dataModel.toServerSide(), '自查评估表保存'); } async downloadSelfAssessmentPdf(id: number) { await downloadPdfBlob('/pdf/create', id, this.config.baseUrl, `self-assessment-${id}.pdf`); } async downloadAgreementPdf(id: number) { await downloadPdfBlob('/pdf/nationalContract', id, this.config.baseUrl, `agreement-${id}.pdf`); } async saveAnnex(payload: SaveCheckAnnexPayload) { return this.post('/ich/check/saveAnnex', { id: payload.id, name: payload.name, form_id: payload.formId, url: payload.url, type: payload.type, desc: payload.desc, mimetype: payload.mimetype, attach_id: payload.attachId, filesize: payload.fileSize, }, '证明材料保存'); } async getAnnexList(formId: number) { const res = await this.post('/ich/check/getAnnexList', { form_id: formId, }, '证明材料列表'); return normalizePaginated(CheckAnnexListItem, res.data as KeyValue); } async getInheritorBasic(userId?: number) { const res = await this.post('/ich/check/basic', { user_id: userId, }, '传承人自查基础信息'); return transformDataModel(InheritorCheckBasicInfo, res.data as KeyValue); } async getSelfAssessmentDetail(id: number, userId?: number) { const res = await this.post('/ich/check/detail', { id, user_id: userId }, '评估表详情'); return transformDataModel(SelfAssessmentDetail, res.data as KeyValue); } async getAgreementDetail(id: number, userId?: number) { const res = await this.post('/ich/check/agreementDetail', { id, user_id: userId }, '传承协议详情'); return transformDataModel(AgreementDetail, res.data as KeyValue); } } export default new AssessmentContentApi();