| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902 |
- <template>
- <div>
- <!-- 在线填报弹窗(单记录类型,可编辑/只读由 isViewMode/viewModeForDialog 控制) -->
- <survey-form-dialog
- :visible.sync="surveyFormDialogVisible"
- :survey-data="{ ...(currentTemplateRow || {}), ...surveyDetailData }"
- :form-fields="formFields"
- :is-view-mode="viewModeForDialog"
- :audited-unit-id="auditedUnitId"
- :request-type="2"
- :upload-id="
- (currentTemplateRow &&
- (currentTemplateRow.uploadId || currentTemplateRow.id)) ||
- ''
- "
- :survey-template-id="getSurveyTemplateId(currentTemplateRow)"
- :catalog-id="(currentTemplateRow && currentTemplateRow.catalogId) || ''"
- @save="
- $emit('handle-survey-form-save', {
- row: currentTemplateRow,
- formData: $event,
- })
- "
- @refresh="
- $emit('handle-survey-form-save', {
- row: currentTemplateRow,
- formData: {},
- })
- "
- />
- <!-- 固定表填报弹窗(可编辑/只读由 isViewMode/viewModeForDialog 控制) -->
- <fixed-table-dialog
- :visible.sync="fixedTableDialogVisible"
- :survey-data="{ ...currentSurveyRow, fixedHeaders }"
- :fixed-fields="fixedFields || ''"
- :fixed-fieldids="fixedFieldids || ''"
- :columns-meta="columnsMeta"
- :table-items="tableItems"
- :audit-periods="auditPeriods"
- :project-audit-periods="auditPeriod"
- :project-audit-period="auditPeriod"
- :project-id="projectId"
- :is-view-mode="viewModeForDialog"
- :request-type="2"
- :audited-unit-id="auditedUnitId"
- :upload-id="
- currentSurveyRow && currentSurveyRow.id ? currentSurveyRow.id : uploadId
- "
- :survey-template-id="
- currentSurveyRow && currentSurveyRow.surveyTemplateId
- ? currentSurveyRow.surveyTemplateId
- : surveyTemplateId
- "
- :catalog-id="catalogId"
- :task-id="taskId"
- :cross-table-info="crossTableInfo"
- @save="handleFixedTableSave"
- @refresh="handleRefresh"
- />
- <!-- 动态表填报弹窗(可编辑/只读由 isViewMode/viewModeForDialog 控制) -->
- <dynamic-table-dialog
- :key="dynamicDialogKey"
- :visible.sync="dynamicTableDialogVisible"
- :survey-data="currentSurveyRow"
- :table-data="dynamicTableData"
- :table-items="tableItems"
- :is-view-mode="viewModeForDialog"
- :request-type="2"
- :audited-unit-id="auditedUnitId"
- :upload-id="
- currentSurveyRow && (currentSurveyRow.uploadId || currentSurveyRow.id)
- ? currentSurveyRow.uploadId || currentSurveyRow.id
- : uploadId
- "
- :catalog-id="catalogId"
- :survey-template-id="
- getSurveyTemplateId(currentSurveyRow) || surveyTemplateId
- "
- @save="handleDynamicTableSave"
- @refresh="handleRefresh"
- />
- <el-button
- type="primary"
- :disabled="isViewMode"
- @click="$emit('handleAddMaterial')"
- >
- 补充材料
- </el-button>
- <el-table
- style="margin-top: 20px"
- border
- :data="dataRequirements"
- size="mini"
- :show-header="true"
- :row-class-name="getRowClassName"
- >
- <el-table-column prop="seq" label="序号" width="80" align="center">
- <template slot-scope="scope">
- <span v-if="!scope.row.isCategoryHeader">
- {{ scope.row.seq || scope.row.index }}
- </span>
- </template>
- </el-table-column>
- <el-table-column
- prop="informationName"
- label="报送资料"
- min-width="280"
- header-align="center"
- align="left"
- >
- <template slot-scope="scope">
- <div v-if="scope.row.isCategoryHeader" class="category-header-cell">
- {{ scope.row.categoryName }}
- </div>
- <span v-else>{{ scope.row.informationName || '-' }}</span>
- </template>
- </el-table-column>
- <el-table-column
- prop="formatRequired"
- label="资料类型"
- width="130"
- align="center"
- >
- <template slot-scope="scope">
- <span v-if="!scope.row.isCategoryHeader">
- <span
- v-if="
- scope.row.formatRequired !== null &&
- scope.row.formatRequired !== undefined
- "
- >
- {{
- getDictName('formatAsk', String(scope.row.formatRequired)) ||
- scope.row.formatRequired
- }}
- </span>
- <span v-else>-</span>
- </span>
- </template>
- </el-table-column>
- <el-table-column
- prop="isRequired"
- label="是否必填"
- width="110"
- align="center"
- >
- <template slot-scope="scope">
- <span v-if="!scope.row.isCategoryHeader">
- {{ scope.row.isRequired === '1' ? '是' : '否' }}
- </span>
- </template>
- </el-table-column>
- <el-table-column
- prop="isUpload"
- label="是否上传"
- width="110"
- align="center"
- >
- <template slot-scope="scope">
- <span v-if="!scope.row.isCategoryHeader">
- <span v-if="scope.row.informationName == '动态表'">
- <span
- v-if="uploadStatusMap[scope.row.id] === '已上传'"
- style="color: #67c23a"
- >
- {{ uploadStatusMap[scope.row.id] || '-' }}
- </span>
- <span
- v-else-if="uploadStatusMap[scope.row.id] === '未上传'"
- class="text-danger"
- >
- {{ uploadStatusMap[scope.row.id] }}
- </span>
- <span v-else>-</span>
- </span>
- <span v-else>
- <span
- v-if="scope.row.isUpload === 1 || scope.row.isUpload === '1'"
- style="color: #67c23a"
- >
- 已上传
- </span>
- <span v-else class="text-danger">未上传</span>
- </span>
- </span>
- </template>
- </el-table-column>
- <el-table-column
- prop="isRequired"
- label="审核状态"
- width="110"
- align="center"
- >
- <template slot-scope="scope">
- <span v-if="!scope.row.isCategoryHeader">
- <span
- v-if="
- scope.row.auditedStatus !== null &&
- scope.row.auditedStatus !== undefined
- "
- >
- {{
- getDictName('clshzt', String(scope.row.auditedStatus)) ||
- scope.row.auditedStatus
- }}
- </span>
- <span v-else>-</span>
- </span>
- </template>
- </el-table-column>
- <el-table-column prop="operation" label="操作" width="220" align="center">
- <template slot-scope="scope">
- <template v-if="!scope.row.isCategoryHeader">
- <template v-if="String(scope.row.formatRequired) !== '3'">
- <!-- 固定表:也支持在线填报(templateType=2) -->
- <template v-if="String(scope.row.templateType) === '2'">
- <el-button
- v-if="scope.row.isUpload === 1 || scope.row.isUpload === '1'"
- type="text"
- size="small"
- @click="handleViewTemplate(scope.row)"
- >
- 查看
- </el-button>
- <el-button
- type="text"
- size="small"
- :disabled="isViewMode"
- @click="handleOnlineSubmission(scope.row)"
- >
- 在线填报
- </el-button>
- </template>
- <el-button
- v-if="
- (scope.row.isUpload === 1 || scope.row.isUpload === '1') &&
- String(scope.row.templateType) !== '2'
- "
- type="text"
- size="small"
- @click="handleFileView(scope.row)"
- >
- 查看
- </el-button>
- <el-button
- v-if="
- (scope.row.isUpload === 1 || scope.row.isUpload === '1') &&
- String(scope.row.templateType) !== '2'
- "
- type="text"
- size="small"
- @click="$emit('handleFileDownload', scope.row)"
- >
- 下载
- </el-button>
- <el-button
- v-if="
- scope.row.auditedStatus !== '1' &&
- (currentNode === 'clcs' || currentNode === 'tjcl') &&
- String(scope.row.templateType) !== '2'
- "
- type="text"
- size="small"
- :disabled="isViewMode"
- @click="
- $emit(
- 'handleFileUpload',
- scope.row,
- getUploadAccept(scope.row)
- )
- "
- >
- 上传
- </el-button>
- </template>
- <template v-else>
- <!-- v-if="scope.row.isUpload === 1 || scope.row.isUpload === '1'" -->
- <el-button
- v-if="scope.row.isUpload === 1 || scope.row.isUpload === '1'"
- type="text"
- size="small"
- @click="handleViewTemplate(scope.row)"
- >
- 查看
- </el-button>
- <el-button
- v-if="scope.row.formatRequired === '3'"
- type="text"
- size="small"
- @click="handleOnlineSubmission(scope.row)"
- >
- 在线填报
- </el-button>
- <el-button
- v-if="
- scope.row.formatRequired === '3' &&
- scope.row.templateType !== '1'
- "
- type="text"
- size="small"
- @click="handleTemplateDownload(scope.row)"
- >
- 模版下载
- </el-button>
- <el-button
- v-if="
- scope.row.auditedStatus !== '1' &&
- (currentNode === 'clcs' || currentNode === 'tjcl') &&
- scope.row.formatRequired === '3' &&
- scope.row.templateType !== '1' &&
- scope.row.informationName !== '动态表' &&
- scope.row.templateType !== '3'
- "
- type="text"
- size="small"
- :disabled="isViewMode"
- @click="triggerDataUpload(scope.row)"
- >
- 数据上传
- </el-button>
- </template>
- </template>
- </template>
- </el-table-column>
- </el-table>
- <input
- ref="dataUploadInput"
- type="file"
- :accept="dataUploadAccept"
- style="display: none"
- @change="handleDataFileChange"
- />
- <!-- 单记录弹窗(查看模式) -->
- <survey-form-dialog
- :visible.sync="singleDialogVisible"
- :survey-data="{}"
- :is-view-mode="true"
- :request-type="2"
- :audited-unit-id="auditedUnitId"
- :upload-id="(currentTemplateRow && currentTemplateRow.uploadId) || ''"
- :survey-template-id="getSurveyTemplateId(currentTemplateRow)"
- :catalog-id="(currentTemplateRow && currentTemplateRow.catalogId) || ''"
- />
- <!-- 固定表弹窗(查看模式) -->
- <fixed-table-dialog
- :visible.sync="fixedDialogVisible"
- :is-view-mode="true"
- :request-type="2"
- :project-id="projectId"
- :audited-unit-id="auditedUnitId"
- :audit-periods="auditPeriods"
- :project-audit-periods="auditPeriod"
- :project-audit-period="auditPeriod"
- :upload-id="(currentTemplateRow && currentTemplateRow.uploadId) || ''"
- :survey-template-id="getSurveyTemplateId(currentTemplateRow)"
- :catalog-id="(currentTemplateRow && currentTemplateRow.catalogId) || ''"
- :cross-table-info="crossTableInfo"
- />
- <!-- 动态表弹窗(查看模式) -->
- <dynamic-table-dialog
- :visible.sync="dynamicDialogVisible"
- :is-view-mode="true"
- :request-type="2"
- :audited-unit-id="auditedUnitId"
- :upload-id="(currentTemplateRow && currentTemplateRow.uploadId) || ''"
- :survey-template-id="getSurveyTemplateId(currentTemplateRow)"
- :catalog-id="(currentTemplateRow && currentTemplateRow.catalogId) || ''"
- />
- </div>
- </template>
- <script>
- import { uploadPresetTemplate } from '@/api/auditTaskProcessing'
- import {
- getSingleRecordSurveyList,
- getSurveyDetail,
- getDynamicTableData,
- downloadTemplate,
- importData,
- getCrossTableData,
- } from '@/api/audit/survey'
- import { getListBySurveyTemplateIdAndVersion } from '@/api/costSurveyTemplateHeaders'
- import SurveyFormDialog from '@/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue'
- import FixedTableDialog from '@/views/EntDeclaration/auditTaskManagement/components/FixedTableDialog.vue'
- import DynamicTableDialog from '@/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue'
- export default {
- name: 'DataRequirementsTab',
- components: {
- SurveyFormDialog,
- FixedTableDialog,
- DynamicTableDialog,
- },
- props: {
- dataRequirements: {
- type: Array,
- default: () => [],
- },
- isViewMode: {
- type: Boolean,
- default: false,
- },
- dictData: {
- type: Object,
- default: () => ({}),
- },
- currentNode: {
- type: String,
- default: '',
- },
- auditedUnitId: {
- type: [String, Number],
- default: '',
- },
- // 任务ID(用于上传等场景)
- taskId: {
- type: [String, Number],
- default: '',
- },
- // 监审期间(与 CostSurveyTab 对齐,便于统一传递给子组件)
- auditPeriod: {
- type: [String, Array],
- default: null,
- },
- // 以下三个用于与 CostSurveyTab 一致的透传参数
- uploadId: {
- type: [String, Number],
- default: '',
- },
- surveyTemplateId: {
- type: [String, Number],
- default: '',
- },
- catalogId: {
- type: [String, Number],
- default: '',
- },
- // 立项信息ID(用于 FixedTableDialog 优先用接口 auditPeriod 渲染年份)
- projectId: {
- type: [String, Number],
- default: '',
- },
- },
- data() {
- return {
- pendingUploadRow: null,
- dataUploadAccept: '.xls,.xlsx',
- // 模板查看相关
- currentTemplateRow: null,
- currentSurveyRow: null,
- singleDialogVisible: false,
- fixedDialogVisible: false,
- dynamicDialogVisible: false,
- // 在线填报/查看共用弹窗的只读控制
- viewModeForDialog: false,
- // 在线填报(编辑)相关
- surveyFormDialogVisible: false,
- fixedTableDialogVisible: false,
- dynamicTableDialogVisible: false,
- formFields: [],
- surveyDetailData: {},
- tableItems: [],
- auditPeriods: [],
- dynamicTableData: [],
- dynamicDialogKey: 0,
- fixedDialogKey: 0,
- fixedHeaders: null,
- // 与 CostSurveyTab 对齐的固定表头派生字段
- fixedFields: '',
- fixedFieldids: '',
- columnsMeta: [],
- uploadStatusMap: {},
- // 跨表引用数据(与 CostSurveyTab 对齐:按年份分组)
- crossTableInfo: {
- isCrossTable: false,
- crossTableName: '',
- data: {},
- years: [],
- getValue: () => undefined,
- },
- }
- },
- // ...
- watch: {
- auditPeriod: {
- immediate: true,
- deep: true,
- handler(val) {
- if (!val) return
- if (Array.isArray(val)) {
- this.auditPeriods = val.map((p) => String(p))
- } else {
- const str = String(val).trim()
- if (!str) return
- if (str.includes(',')) {
- this.auditPeriods = str
- .split(',')
- .map((s) => s.trim())
- .filter(Boolean)
- } else if (str.includes('-')) {
- const parts = str.split('-')
- if (parts.length === 2) {
- const start = parseInt(parts[0].trim())
- const end = parseInt(parts[1].trim())
- const years = []
- if (!isNaN(start) && !isNaN(end) && end >= start) {
- for (let y = start; y <= end; y++) years.push(String(y))
- }
- this.auditPeriods = years
- }
- } else {
- this.auditPeriods = [str]
- }
- }
- },
- },
- // 监听dataRequirements变化,预加载所有动态表上传状态
- dataRequirements: {
- immediate: true,
- deep: true,
- handler(newVal, oldVal) {
- if (newVal && newVal.length > 0) {
- this.preloadAllDynamicTableStatus()
- }
- },
- },
- },
- methods: {
- // 异步获取上传状态并直接更新row属性
- async fetchUploadStatus(row) {
- try {
- const uploadId = row.uploadId || row.id || ''
- const auditedUnitId = this.auditedUnitId || row.auditedUnitId || ''
- const catalogId = row.catalogId || ''
- const surveyTemplateId = this.getSurveyTemplateId(row)
- const params = {
- uploadId,
- auditedUnitId,
- catalogId,
- surveyTemplateId,
- type: 2,
- }
- const res = await getDynamicTableData(params)
- // 直接更新row的uploadStatus属性
- if (res && res.code === 200) {
- const records = res.value?.records || res.value || []
- this.$set(
- this.uploadStatusMap,
- uploadId,
- records.length > 0 ? '已上传' : '未上传'
- )
- } else {
- this.uploadStatusMap[uploadId] = ''
- }
- // 触发表格更新
- this.$nextTick(() => {
- this.$forceUpdate()
- })
- } catch (error) {
- console.error('获取上传状态失败:', error)
- // 错误情况下更新为未上传状态
- row.uploadStatus = '未上传'
- // 确保表格更新
- this.$nextTick(() => {
- this.$forceUpdate()
- })
- }
- },
- // 预加载所有动态表上传状态
- async preloadAllDynamicTableStatus() {
- if (!this.dataRequirements || this.dataRequirements.length === 0) return
- const dynamicTableRows = this.dataRequirements.filter(
- (row) => !row.isCategoryHeader && row.informationName === '动态表'
- )
- // 并行请求所有动态表的上传状态,不设置初始加载状态
- const promises = dynamicTableRows.map((row) => {
- return this.fetchUploadStatus(row)
- })
- try {
- await Promise.all(promises)
- } catch (error) {
- console.error('预加载上传状态失败:', error)
- } finally {
- // 确保表格更新
- this.$nextTick(() => {
- this.$forceUpdate()
- })
- }
- },
- // 加载跨表引用数据(固定表/动态表使用,type=2=报送资料)
- async loadCrossTableInfo(row) {
- const surveyTemplateId = this.getSurveyTemplateId(row)
- const taskId = (row && (row.taskId || row.taskID)) || this.taskId || ''
- if (!surveyTemplateId || !taskId) {
- this.crossTableInfo = {
- isCrossTable: false,
- crossTableName: '',
- data: {},
- years: [],
- getValue: () => undefined,
- }
- return true
- }
- try {
- const res = await getCrossTableData({
- taskId,
- surveyTemplateId,
- type: 2,
- })
- const wrapper = res || {}
- const wrappedValue = wrapper.value || wrapper.data || wrapper
- const code =
- wrapper.code !== undefined && wrapper.code !== null
- ? wrapper.code
- : wrappedValue && wrappedValue.code
- if (!(code === 0 || code === 200)) {
- this.crossTableInfo = {
- isCrossTable: false,
- crossTableName: '',
- data: {},
- years: [],
- getValue: () => undefined,
- }
- return true
- }
- const d = wrappedValue || {}
- const dataByYearRaw = d && d.data
- const isEmptyArray =
- Array.isArray(dataByYearRaw) && dataByYearRaw.length === 0
- const dataByYear =
- !dataByYearRaw || Array.isArray(dataByYearRaw) ? {} : dataByYearRaw
- const years = Object.keys(dataByYear)
- .map((y) => String(y))
- .filter(Boolean)
- .sort()
- // 若标记为跨表但未返回任何跨表数据:提示 + 阻止打开弹窗
- if (d && d.isCrossTable && (isEmptyArray || years.length === 0)) {
- this.$message &&
- this.$message.warning &&
- this.$message.warning(
- `跨表引用数据为空,请先完善【${
- d.crossTableName || '跨表'
- }】后再试`
- )
- this.crossTableInfo = {
- isCrossTable: !!d.isCrossTable,
- crossTableName: d.crossTableName || '',
- data: {},
- years: [],
- getValue: () => undefined,
- }
- return false
- }
- this.crossTableInfo = {
- isCrossTable: !!d.isCrossTable,
- crossTableName: d.crossTableName || '',
- data: dataByYear,
- years,
- getValue: (year, key) => {
- const y = year === undefined || year === null ? '' : String(year)
- const k = key === undefined || key === null ? '' : String(key)
- if (!y || !k) return undefined
- return dataByYear && dataByYear[y] ? dataByYear[y][k] : undefined
- },
- }
- return true
- } catch (e) {
- console.error('获取跨表引用数据失败:', e)
- this.crossTableInfo = {
- isCrossTable: false,
- crossTableName: '',
- data: {},
- years: [],
- getValue: () => undefined,
- }
- return true
- }
- },
- // 在线填报入口:与 CostSurveyTab 一致
- async handleOnlineSubmission(row) {
- if (!row) return
- this.currentTemplateRow = row
- this.currentSurveyRow = row
- this.surveyDetailData = {}
- // 在线填报时使用页面传入的 isViewMode,不强制只读
- this.viewModeForDialog = false
- const t = String(row.templateType || row.templatetype || '').trim()
- // 1=单记录,2=固定表,3=动态表
- if (t === '1') {
- // 只要有 uploadId/id 就尝试回显数据
- if (row.uploadId || row.id) {
- try {
- const params = {
- uploadId: row.uploadId || row.id,
- auditedUnitId: this.auditedUnitId,
- type: 2,
- }
- const res = await getSurveyDetail(params)
- if (res && res.code === 200 && res.value) {
- console.log(res, 'getUploadData')
- const detailData = {}
- if (Array.isArray(res.value)) {
- res.value.forEach((item) => {
- if (item.rowid && item.rvalue !== undefined) {
- detailData[item.rowid] = item.rvalue
- }
- })
- } else if (res.value && typeof res.value === 'object') {
- Object.assign(detailData, res.value)
- }
- this.surveyDetailData = detailData
- }
- } catch (err) {
- console.error('获取单记录详情失败', err)
- }
- }
- await this.initFormFields()
- } else if (t === '2') {
- const ok = await this.loadCrossTableInfo(row)
- if (!ok) return
- await this.initFixedTableData()
- } else if (t === '3') {
- this.resetDynamicDialogState()
- await this.initDynamicTableData()
- }
- },
- // 处理固定表保存(与 CostSurveyTab 对齐)
- handleFixedTableSave(tableData) {
- this.$emit('handle-fixed-table-save', {
- row: this.currentSurveyRow || this.currentTemplateRow,
- tableData,
- })
- },
- // 处理刷新(与 CostSurveyTab 对齐)
- handleRefresh() {
- this.$emit('handle-survey-form-save', {
- row: this.currentSurveyRow || this.currentTemplateRow,
- formData: {},
- })
- },
- // 处理动态表保存(与 CostSurveyTab 对齐)
- handleDynamicTableSave(tableData) {
- this.$emit('handle-dynamic-table-save', {
- row: this.currentSurveyRow || this.currentTemplateRow,
- tableData,
- })
- this.handleRefresh()
- },
- // 预览:与 UploadComponent.vue 的 handlePreview 一致
- handleFileView(row) {
- console.log(row, '这一行数据')
- try {
- const filePath =
- row?.filePath ||
- row?.filepath ||
- row?.fileUrl ||
- row?.url ||
- row?.path ||
- ''
- if (!filePath) {
- this.$message &&
- this.$message.warning &&
- this.$message.warning('未找到可预览的文件路径')
- return
- }
- const encodedUrl = encodeURIComponent(
- Base64.encode((window.context && window.context.form) + filePath)
- )
- window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
- // 兼容保留:通知父组件
- this.$emit('handleFileView', row)
- } catch (e) {
- console.error('文件预览失败: ', e)
- this.$message &&
- this.$message.error &&
- this.$message.error('文件预览失败')
- }
- },
- // 模版查看:与 submitData.vue 的 handleViewTemplate 保持一致
- async handleViewTemplate(row) {
- this.currentTemplateRow = row || null
- this.currentSurveyRow = row || null
- const t = String(
- (row && (row.templateType || row.templatetype)) || ''
- ).trim()
- // 点击“查看”时,复用在线填报的弹窗和数据加载逻辑,但强制只读
- this.viewModeForDialog = true
- if (t === '1' || t === '2' || t === '3') {
- if (!row) return
- this.currentTemplateRow = row
- this.surveyDetailData = {}
- // 在线填报时使用页面传入的 isViewMode,不强制只读
- this.viewModeForDialog = true
- const t = String(row.templateType || row.templatetype || '').trim()
- // 1=单记录,2=固定表,3=动态表
- if (t === '1') {
- // 只要有 uploadId/id 就尝试回显数据
- if (row.uploadId || row.id) {
- try {
- const params = {
- uploadId: row.uploadId || row.id,
- auditedUnitId: this.auditedUnitId,
- type: 2,
- }
- const res = await getSurveyDetail(params)
- if (res && res.code === 200 && res.value) {
- console.log(res, 'getUploadData')
- const detailData = {}
- if (Array.isArray(res.value)) {
- res.value.forEach((item) => {
- if (item.rowid && item.rvalue !== undefined) {
- detailData[item.rowid] = item.rvalue
- }
- })
- } else if (res.value && typeof res.value === 'object') {
- Object.assign(detailData, res.value)
- }
- this.surveyDetailData = detailData
- }
- } catch (err) {
- console.error('获取单记录详情失败', err)
- }
- }
- await this.initFormFields()
- } else if (t === '2') {
- const ok = await this.loadCrossTableInfo(row)
- if (!ok) return
- await this.initFixedTableData()
- } else if (t === '3') {
- this.resetDynamicDialogState()
- await this.initDynamicTableData()
- }
- } else {
- this.$message &&
- this.$message.warning &&
- this.$message.warning('未知的模板类型,无法打开预置模板')
- }
- },
- // 根据资料类型返回上传accept白名单
- getUploadAccept(row) {
- const fmt = row && row.formatRequired
- const fmtStr = fmt != null ? String(fmt).toLowerCase() : ''
- if (
- fmtStr === '1' ||
- fmtStr.includes('doc') ||
- fmtStr.includes('word') ||
- fmtStr.includes('pdf') ||
- fmtStr.includes('文档')
- ) {
- return '.pdf,.doc,.docx'
- }
- if (
- fmtStr === '2' ||
- fmtStr.includes('excel') ||
- fmtStr.includes('xls') ||
- fmtStr.includes('xlsx') ||
- fmtStr.includes('表格')
- ) {
- return '.xls,.xlsx'
- }
- return '.pdf,.doc,.docx,.xls,.xlsx'
- },
- getDataUploadAccept(row) {
- const fmt = row && row.formatRequired
- const fmtStr = fmt != null ? String(fmt).toLowerCase() : ''
- if (
- fmtStr === '3' ||
- fmtStr.includes('模版') ||
- fmtStr.includes('模板')
- ) {
- return '.xls,.xlsx'
- }
- return '.xls,.xlsx'
- },
- getRowClassName(data) {
- if (data.row.isCategoryHeader) {
- return 'category-header-row'
- }
- return ''
- },
- getDictName(dictType, dictKey) {
- const list = (this.dictData && this.dictData[dictType]) || []
- if (!Array.isArray(list) || dictKey === undefined || dictKey === null) {
- return ''
- }
- const item = list.find(
- (it) =>
- String(it.key) === String(dictKey) ||
- String(it.value) === String(dictKey)
- )
- return item ? item.name : ''
- },
- getSurveyTemplateId(row) {
- return (
- row?.surveyTemplateId ||
- row?.templateId ||
- row?.surveyTemplateID ||
- row?.templateID ||
- ''
- )
- },
- getMaterialId(row) {
- return row?.materialId || row?.id || row?.materialID || ''
- },
- resetDataUploadState() {
- const input = this.$refs.dataUploadInput
- if (input) {
- input.value = ''
- }
- this.pendingUploadRow = null
- },
- triggerDataUpload(row) {
- console.log(row)
- if (!row || this.isViewMode) {
- return
- }
- const surveyTemplateId = this.getSurveyTemplateId(row)
- if (!surveyTemplateId) {
- this.$message.warning('缺少模板信息,无法上传数据')
- return
- }
- this.pendingUploadRow = row
- this.dataUploadAccept = this.getDataUploadAccept(row)
- this.$nextTick(() => {
- const input = this.$refs.dataUploadInput
- if (input) {
- input.value = ''
- input.click()
- }
- })
- },
- async handleDataFileChange(event) {
- const files = event?.target?.files
- if (!this.pendingUploadRow || !files || !files.length) {
- this.resetDataUploadState()
- return
- }
- const file = files[0]
- if (!file) {
- this.$message.warning('请选择需要上传的文件')
- this.resetDataUploadState()
- return
- }
- const surveyTemplateId = this.getSurveyTemplateId(this.pendingUploadRow)
- const materialId = this.getMaterialId(this.pendingUploadRow)
- if (!surveyTemplateId) {
- this.$message.warning('缺少模板信息,无法上传数据')
- this.resetDataUploadState()
- return
- }
- if (!materialId) {
- this.$message.warning('缺少资料标识,无法上传数据')
- this.resetDataUploadState()
- return
- }
- const formData = new FormData()
- formData.append('file', file)
- formData.append('surveyTemplateId', surveyTemplateId)
- formData.append('materialId', materialId)
- // const auditedUnitId =this.pendingUploadRow.auditedUnitId
- const taskId = this.pendingUploadRow.taskId || this.taskId
- // formData.append('auditedUnitId', auditedUnitId)
- formData.append('taskId', taskId)
- formData.append('type', '2')
- const loading = this.$loading({
- lock: true,
- text: '数据上传中...',
- spinner: 'el-icon-loading',
- background: 'rgba(0, 0, 0, 0.7)',
- })
- try {
- const response = await importData(formData)
- loading.close()
- const success =
- response &&
- (response.code === 200 ||
- response.success === true ||
- response.status === 200)
- if (success) {
- this.$message.success('数据上传成功')
- this.$emit('data-upload-success', {
- row: this.pendingUploadRow,
- response,
- })
- } else {
- const message =
- response?.message ||
- response?.msg ||
- response?.data?.message ||
- '数据上传失败,请稍后重试'
- this.$message.error(message)
- }
- } catch (error) {
- loading.close()
- console.error('数据上传失败:', error)
- // this.$message.error(error.message || '数据上传失败,请稍后重试')
- } finally {
- this.resetDataUploadState()
- }
- },
- // 处理模板下载
- async handleTemplateDownload(row) {
- console.log(row)
- let loading
- try {
- // 显示加载提示
- loading = this.$loading({
- lock: true,
- text: '模板下载中...',
- spinner: 'el-icon-loading',
- background: 'rgba(0, 0, 0, 0.7)',
- })
- // 构建请求参数
- const params = { type: 2 }
- const surveyTemplateId = this.getSurveyTemplateId(row)
- if (surveyTemplateId) {
- params.surveyTemplateId = surveyTemplateId
- }
- // 追加 taskId(来自行或页面 props)
- const taskId = row && (row.taskId || row.taskID)
- if (taskId || this.taskId) {
- params.taskId = taskId || this.taskId
- }
- const response = await downloadTemplate(params)
- // 下载接口可能返回两类数据:
- // 1) 正常:Blob(xlsx)
- // 2) 异常:JSON({code:500,state:false,message:'...'}),但由于 responseType=blob,前端拿到的可能仍是 Blob
- const getJsonFromBlobIfPossible = async (blob) => {
- if (!(blob instanceof Blob)) return null
- try {
- const text = await blob.text()
- if (!text) return null
- return JSON.parse(text)
- } catch (e) {
- return null
- }
- }
- let maybeJson = null
- if (
- response &&
- response.data &&
- typeof response.data === 'object' &&
- !(response.data instanceof Blob)
- ) {
- maybeJson = response.data
- } else if (
- response &&
- typeof response === 'object' &&
- !(response instanceof Blob) &&
- !(response.data instanceof Blob)
- ) {
- maybeJson = response
- } else if (response && response.data instanceof Blob) {
- maybeJson = await getJsonFromBlobIfPossible(response.data)
- } else if (response instanceof Blob) {
- maybeJson = await getJsonFromBlobIfPossible(response)
- }
- console.log('下载模板接口返回数据:', maybeJson)
- if (
- maybeJson &&
- (maybeJson.state === false ||
- (maybeJson.code !== undefined &&
- maybeJson.code !== null &&
- ![0, 200].includes(Number(maybeJson.code))))
- ) {
- const msg =
- maybeJson.message ||
- maybeJson.msg ||
- '导出失败:该表存在跨表引用且部分年份数据缺失,请先完善后再下载'
- this.$message && this.$message.warning && this.$message.warning(msg)
- return
- }
- // 处理响应数据
- // response 可能是 { data, headers } 格式,也可能是直接的 Blob
- const blobData = (response && response.data) || response
- const blob =
- blobData instanceof Blob ? blobData : new Blob([blobData])
- // 文件名:优先从响应头获取
- let fileName = ''
- const headers = (response && response.headers) || {}
- const contentDisposition =
- headers['content-disposition'] || headers['Content-Disposition']
- if (contentDisposition) {
- const fileNameMatch = contentDisposition.match(
- /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
- )
- if (fileNameMatch && fileNameMatch[1]) {
- try {
- fileName = decodeURIComponent(
- fileNameMatch[1].replace(/['"]/g, '')
- )
- } catch (e) {
- fileName = fileNameMatch[1].replace(/['"]/g, '')
- }
- }
- }
- if (!fileName) {
- const defaultName = row?.informationName || row?.name || '模板文件'
- fileName = `${defaultName}_模板.xlsx`
- }
- if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
- fileName += '.xlsx'
- }
- const url = window.URL.createObjectURL(blob)
- const link = document.createElement('a')
- link.style.display = 'none'
- link.href = url
- link.download = fileName
- document.body.appendChild(link)
- link.click()
- document.body.removeChild(link)
- window.URL.revokeObjectURL(url)
- this.$message &&
- this.$message.success &&
- this.$message.success('开始下载文件')
- } catch (error) {
- // 兼容:axios 抛错时,错误信息可能在 error.response.data(同样可能是 Blob)
- try {
- const errRes = error && error.response
- const errData = errRes && errRes.data
- let errJson = null
- if (
- errData &&
- typeof errData === 'object' &&
- !(errData instanceof Blob)
- ) {
- errJson = errData
- } else if (errData instanceof Blob) {
- try {
- const text = await errData.text()
- errJson = text ? JSON.parse(text) : null
- } catch (_) {
- errJson = null
- }
- }
- if (errJson && (errJson.message || errJson.msg)) {
- this.$message &&
- this.$message.warning &&
- this.$message.warning(errJson.message || errJson.msg)
- return
- }
- } catch (_) {
- // ignore
- }
- console.error('模板下载失败:', error)
- this.$message &&
- this.$message.error &&
- this.$message.error(error.message || '模板下载失败,请稍后重试')
- } finally {
- if (loading && loading.close) loading.close()
- }
- },
- // 以下为在线填报所需方法,与 CostSurveyTab 对齐
- async initDynamicTableData() {
- try {
- const uploadId =
- (this.currentTemplateRow &&
- (this.currentTemplateRow.uploadId ||
- this.currentTemplateRow.id)) ||
- ''
- const auditedUnitId =
- this.auditedUnitId ||
- (this.currentTemplateRow &&
- this.currentTemplateRow.auditedUnitId) ||
- ''
- const catalogId =
- (this.currentTemplateRow && this.currentTemplateRow.catalogId) || ''
- const surveyTemplateId = this.getSurveyTemplateId(
- this.currentTemplateRow
- )
- const params = {
- uploadId,
- auditedUnitId,
- catalogId,
- surveyTemplateId,
- type: 2,
- }
- const res = await getDynamicTableData(params)
- if (res && res.code === 200) {
- const records = res.value?.records || res.value || []
- this.dynamicTableData = Array.isArray(records) ? records : []
- } else {
- this.dynamicTableData =
- this.currentTemplateRow?.dynamicTableData || []
- }
- if (
- this.currentTemplateRow &&
- this.currentTemplateRow.tableItems &&
- this.currentTemplateRow.tableItems.length > 0
- ) {
- this.tableItems = this.currentTemplateRow.tableItems
- } else {
- this.tableItems = this.getMockTableItems()
- }
- this.dynamicTableDialogVisible = true
- } catch (error) {
- console.error('获取动态表数据失败', error)
- this.dynamicTableData =
- this.currentTemplateRow?.dynamicTableData || []
- this.tableItems =
- this.currentTemplateRow?.tableItems || this.getMockTableItems()
- this.dynamicTableDialogVisible = true
- }
- },
- async initFormFields() {
- if (
- this.currentTemplateRow &&
- this.getSurveyTemplateId(this.currentTemplateRow)
- ) {
- try {
- const params = {
- surveyTemplateId: this.getSurveyTemplateId(
- this.currentTemplateRow
- ),
- type: 2,
- }
- const res = await getListBySurveyFdTemplateIdAndVersion(params)
- if (res && res.code === 200) {
- let mapped = []
- if (Array.isArray(res.value)) {
- mapped = res.value
- .map((item, index) =>
- this.mapApiFieldToFormField(item, index)
- )
- .filter(Boolean)
- } else if (res.value && typeof res.value === 'object') {
- const { fixedFields, fixedFieldids } = res.value
- if (fixedFields && fixedFieldids) {
- const labels = fixedFields.split(',').map((i) => i.trim())
- const ids = fixedFieldids.split(',').map((i) => i.trim())
- mapped = labels.map((label, index) => ({
- prop: ids[index] || `field_${index}`,
- label,
- type: 'input',
- colSpan: 12,
- placeholder: `请输入${label}`,
- rules: [],
- defaultValue: '',
- disabled: false,
- clearable: true,
- multiple: false,
- required: false,
- }))
- }
- }
- this.formFields =
- mapped.length > 0 ? mapped : this.getMockFormFields()
- } else {
- this.formFields = this.getMockFormFields()
- }
- this.surveyFormDialogVisible = true
- } catch (err) {
- console.error('获取单记录表单字段配置失败', err)
- this.formFields = this.getMockFormFields()
- this.surveyFormDialogVisible = true
- }
- } else {
- this.formFields = this.getMockFormFields()
- this.surveyFormDialogVisible = true
- }
- },
- async initFixedTableData() {
- if (
- this.currentTemplateRow &&
- this.getSurveyTemplateId(this.currentTemplateRow)
- ) {
- try {
- const params = {
- surveyTemplateId: this.getSurveyTemplateId(
- this.currentTemplateRow
- ),
- type: 2,
- }
- const res = await getSingleRecordSurveyList(params)
- if (res && res.code === 200 && res.value) {
- // 将接口返回的数据转换为固定表配置格式
- // 固定表使用 itemlist,不使用 fixedFields 和 fixedFieldids
- const { itemlist } = res.value
- console.log('itemlist', itemlist)
- // 如果有 itemlist,使用 itemlist 作为表格项配置
- if (itemlist && Array.isArray(itemlist) && itemlist.length > 0) {
- this.tableItems = itemlist.map((item, index) => ({
- id: item.id || item.itemId || '',
- rowid: item.rowid || item.id || item.itemId || '', // rowid 用于父子关系
- seq: item.序号, // 序号就是序号
- itemName: item.项目 || '', // 项目就是项目
- unit: item.unit || '', // 单位是 unit
- isCategory: item.isCategory || false,
- categorySeq: item.categorySeq || '',
- categoryId: item.categoryId || '',
- parentid:
- item.parentid !== undefined
- ? item.parentid
- : item.parentId !== undefined
- ? item.parentId
- : '-1', // 父项ID,默认为 '-1'(父项)
- validateRules: item.validateRules || {},
- linkageRules: item.linkageRules || {},
- children: item.children || [],
- ...item, // 保留其他字段
- }))
- // 若该接口同时提供 fixedFields/fixedFieldids,则同步到弹窗表头
- if (res.value.fixedFields && res.value.fixedFieldids) {
- this.fixedFields = res.value.fixedFields
- console.log(this.fixedFields, 'biaogeshuju')
- this.fixedFieldids = res.value.fixedFieldids
- }
- } else {
- // 如果没有 itemlist,使用假数据
- this.tableItems = this.getMockTableItems()
- }
- } else {
- this.tableItems = this.getMockTableItems()
- }
- } catch (err) {
- console.error('获取固定表配置失败', err)
- this.tableItems = this.getMockTableItems()
- }
- } else if (
- this.currentTemplateRow &&
- this.currentTemplateRow.tableItems
- ) {
- this.tableItems = this.currentTemplateRow.tableItems
- } else {
- this.tableItems = this.getMockTableItems()
- }
- // 监审期间:优先使用 props.auditPeriod,其次使用行上的 auditPeriod,否则默认最近三年
- if (this.auditPeriod) {
- if (Array.isArray(this.auditPeriod)) {
- this.auditPeriods = this.auditPeriod.map((p) => String(p))
- } else {
- this.auditPeriods = this.parseAuditPeriod(this.auditPeriod)
- }
- } else if (
- this.currentTemplateRow &&
- this.currentTemplateRow.auditPeriod
- ) {
- this.auditPeriods = this.parseAuditPeriod(
- this.currentTemplateRow.auditPeriod
- )
- } else {
- const currentYear = new Date().getFullYear()
- this.auditPeriods = [
- String(currentYear - 2),
- String(currentYear - 1),
- String(currentYear),
- ]
- }
- try {
- const headerRes = await getListBySurveyTemplateIdAndVersion({
- surveyTemplateId: this.getSurveyTemplateId(this.currentTemplateRow),
- type: 2,
- })
- if (headerRes && headerRes.code === 200) {
- const hdrVal = headerRes.value
- // 统一规范:columnsMeta + fixedFields + fixedFieldids
- let columnsMeta = []
- let fixedFieldsStr = this.fixedFields || ''
- let fixedFieldidsStr = this.fixedFieldids || ''
- if (Array.isArray(hdrVal)) {
- columnsMeta = hdrVal
- } else if (hdrVal && typeof hdrVal === 'object') {
- const {
- fixedFields,
- fixedFieldids,
- columnsMeta: metas,
- headers,
- items,
- } = hdrVal
- fixedFieldsStr = fixedFieldsStr || fixedFields || ''
- fixedFieldidsStr = fixedFieldidsStr || fixedFieldids || ''
- columnsMeta = Array.isArray(metas)
- ? metas
- : Array.isArray(headers)
- ? headers
- : Array.isArray(items)
- ? items
- : []
- }
- // 如未提供 fixedFields/fixedFieldids,则从 columnsMeta 推导
- if (
- (!fixedFieldsStr || !fixedFieldidsStr) &&
- Array.isArray(columnsMeta) &&
- columnsMeta.length
- ) {
- const labels = columnsMeta
- .map((m) => (m && (m.label || m.fieldName || m.name)) || '')
- .map((s) => String(s || '').trim())
- .filter(Boolean)
- const ids = columnsMeta
- .map(
- (m) =>
- (m && (m.fieldId || m.fieldName || m.prop || m.code)) || ''
- )
- .map((s) => String(s || '').trim())
- .filter(Boolean)
- if (labels.length) fixedFieldsStr = labels.join(',')
- if (ids.length) fixedFieldidsStr = ids.join(',')
- }
- // 回写到实例;优先保留服务端原始 fixedHeaders,以与成本调查表保持一致
- this.columnsMeta = columnsMeta
- this.fixedFields = fixedFieldsStr
- this.fixedFieldids = fixedFieldidsStr
- if (hdrVal) {
- this.fixedHeaders = hdrVal
- } else if (
- (Array.isArray(this.columnsMeta) && this.columnsMeta.length) ||
- (this.fixedFields && this.fixedFields.length) ||
- (this.fixedFieldids && this.fixedFieldids.length)
- ) {
- this.fixedHeaders = {
- fixedFields: this.fixedFields,
- fixedFieldids: this.fixedFieldids,
- columnsMeta: this.columnsMeta,
- }
- } else {
- this.fixedHeaders = null
- }
- } else {
- this.fixedHeaders = null
- this.fixedFields = ''
- this.fixedFieldids = ''
- this.columnsMeta = []
- }
- } catch (e) {
- this.fixedHeaders = null
- this.fixedFields = ''
- this.fixedFieldids = ''
- this.columnsMeta = []
- }
- this.fixedDialogKey++
- this.fixedTableDialogVisible = true
- },
- extractLengthFromFormat(format) {
- if (!format) return undefined
- const str = String(format).trim()
- if (!str) return undefined
- const match = str.match(/\d+/)
- if (match && match[0]) {
- const len = Number(match[0])
- return Number.isNaN(len) ? undefined : len
- }
- return undefined
- },
- buildFieldRules(meta) {
- const {
- type,
- label,
- required,
- totalLength,
- decimalLength,
- formatLength,
- format,
- isAuditPeriod,
- } = meta || {}
- const rules = []
- const trigger = type === 'select' ? 'change' : 'blur'
- if (required) {
- rules.push({
- required: true,
- message: `${type === 'select' ? '请选择' : '请输入'}${label}`,
- trigger,
- })
- }
- const inputMaxLength = formatLength || totalLength
- if (type === 'input' && inputMaxLength) {
- rules.push({
- validator: (_, value, callback) => {
- if (value === undefined || value === null || value === '')
- return callback()
- const str = String(value)
- if (str.length > inputMaxLength)
- callback(
- new Error(`${label}长度不能超过${inputMaxLength}个字符`)
- )
- else callback()
- },
- trigger: 'blur',
- })
- }
- const numberTotal = totalLength || formatLength
- if (type === 'number') {
- rules.push({
- validator: (_, value, callback) => {
- if (value === undefined || value === null || value === '')
- return callback()
- if (Number.isNaN(Number(value)))
- return callback(new Error(`${label}必须为数字`))
- const pure = String(value).replace('-', '')
- if (numberTotal && pure.replace('.', '').length > numberTotal)
- return callback(
- new Error(`${label}总位数不能超过${numberTotal}`)
- )
- if (decimalLength !== undefined && decimalLength !== null) {
- const decimals = pure.split('.')[1] || ''
- if (decimals.length > decimalLength)
- return callback(
- new Error(`${label}小数位不能超过${decimalLength}位`)
- )
- }
- callback()
- },
- trigger: 'blur',
- })
- }
- if (type === 'datetime' || type === 'date') {
- if (format) {
- rules.push({
- validator: (_, value, callback) => callback(),
- trigger: 'change',
- })
- }
- }
- if (type === 'year' || isAuditPeriod) {
- rules.push({
- validator: (_, value, callback) => {
- if (value === undefined || value === null || value === '')
- return callback()
- const pattern = /^\d{4}$/
- if (!pattern.test(String(value)))
- callback(new Error(`${label}必须是四位年份`))
- else callback()
- },
- trigger: 'change',
- })
- }
- return rules
- },
- mapApiFieldToFormField(item, index = 0) {
- if (!item) return null
- const getVal = (keys, fallback) => {
- for (const key of keys) {
- if (
- key &&
- item[key] !== undefined &&
- item[key] !== null &&
- item[key] !== ''
- )
- return item[key]
- }
- return fallback
- }
- const toBool = (value) => {
- if (value === undefined || value === null) return false
- if (typeof value === 'boolean') return value
- if (typeof value === 'number') return value === 1
- const str = String(value).trim().toLowerCase()
- return ['1', 'true', 'y', 'yes', '是'].includes(str)
- }
- const toNumber = (value) => {
- if (value === undefined || value === null || value === '')
- return undefined
- const num = Number(value)
- return Number.isNaN(num) ? undefined : num
- }
- const prop =
- getVal(
- [
- 'fieldName',
- 'field_name',
- 'columnName',
- 'column_name',
- 'fieldCode',
- ],
- undefined
- ) || `field_${index}`
- const label =
- getVal(
- [
- 'columnComment',
- 'column_comment',
- 'fieldCname',
- 'field_cname',
- 'fieldLabel',
- 'field_label',
- ],
- prop
- ) || prop
- const columnType =
- (getVal(
- ['columnType', 'column_type', 'fieldType', 'field_type'],
- ''
- ) || '') + ''
- const columnTypeLower = columnType.toLowerCase()
- const totalLength = toNumber(
- getVal(
- ['fieldTypeLen', 'field_typelen', 'length', 'fieldLength'],
- undefined
- )
- )
- const decimalLength = toNumber(
- getVal(
- ['fieldTypeNointLen', 'field_typenointlen', 'scale'],
- undefined
- )
- )
- const isAuditPeriod = toBool(
- getVal(['isAuditPeriod', 'is_audit_period'], false)
- )
- const dictCode =
- getVal(
- [
- 'dictCode',
- 'dict_code',
- 'dictId',
- 'dictid',
- 'dictType',
- 'dict_type',
- ],
- ''
- ) || ''
- const optionsRaw = getVal(['options'], [])
- let options = []
- if (Array.isArray(optionsRaw)) options = optionsRaw
- else if (typeof optionsRaw === 'string' && optionsRaw.trim() !== '') {
- options = optionsRaw
- .split(',')
- .map((value) => ({ label: value.trim(), value: value.trim() }))
- }
- let type = getVal(['componentType', 'type'], '')
- if (!type) {
- if (dictCode || options.length > 0) type = 'select'
- else if (
- columnTypeLower.includes('datetime') ||
- columnTypeLower.includes('timestamp') ||
- columnTypeLower.includes('date time')
- )
- type = 'datetime'
- else if (columnTypeLower.includes('date')) type = 'date'
- else if (columnTypeLower.includes('year')) type = 'year'
- else if (
- columnTypeLower.includes('int') ||
- columnTypeLower.includes('number') ||
- columnTypeLower.includes('decimal') ||
- columnTypeLower.includes('float') ||
- columnTypeLower.includes('double')
- )
- type = 'number'
- else type = 'input'
- }
- const required = toBool(
- getVal(['isRequired', 'is_required', 'required'], false)
- )
- const multiple = toBool(
- getVal(['isMultiple', 'is_multiple', 'multiple'], false)
- )
- const colSpan =
- toNumber(
- getVal(['colSpan', 'colspan', 'columnSpan', 'column_span'], 12)
- ) || 12
- const placeholder =
- getVal(
- ['placeholder', 'columnComment', 'column_comment'],
- undefined
- ) || (type === 'select' ? `请选择${label}` : `请输入${label}`)
- const defaultValue = getVal(
- ['defaultValue', 'default_value', 'defaultVal', 'default_val'],
- undefined
- )
- const precision = toNumber(
- getVal(
- ['fieldTypeNointLen', 'field_typenointlen', 'precision'],
- undefined
- )
- )
- const min = toNumber(getVal(['min'], undefined))
- const max = toNumber(getVal(['max'], undefined))
- const format = getVal(['format'], undefined)
- const valueFormat =
- getVal(['valueFormat', 'value_format'], undefined) ||
- (type === 'datetime'
- ? 'yyyy-MM-dd HH:mm:ss'
- : type === 'date'
- ? 'yyyy-MM-dd'
- : type === 'year'
- ? 'yyyy'
- : undefined)
- const formatLength = this.extractLengthFromFormat(format)
- const rules = this.buildFieldRules({
- type,
- label,
- required,
- totalLength,
- decimalLength,
- formatLength,
- format,
- isAuditPeriod,
- })
- return {
- prop,
- label,
- type,
- colSpan,
- placeholder,
- dictCode,
- dictType: dictCode,
- options,
- required,
- defaultValue,
- multiple,
- precision,
- min,
- max,
- format,
- valueFormat,
- totalLength,
- decimalLength,
- formatLength,
- rules,
- }
- },
- getMockFormFields() {
- // return [
- // {
- // prop: 'institutionName',
- // label: '机构名称',
- // type: 'input',
- // colSpan: 12,
- // defaultValue: '幼儿园基本情况',
- // placeholder: '请输入机构名称',
- // required: true,
- // },
- // {
- // prop: 'institutionNature',
- // label: '机构性质',
- // type: 'select',
- // colSpan: 12,
- // dictType: 'institutionNature',
- // defaultValue: '公办',
- // placeholder: '请选择机构性质',
- // required: true,
- // clearable: true,
- // },
- // {
- // prop: 'institutionLevel',
- // label: '机构评定等级',
- // type: 'select',
- // colSpan: 12,
- // dictType: 'institutionLevel',
- // defaultValue: '省一级',
- // placeholder: '请选择机构评定等级',
- // required: true,
- // clearable: true,
- // },
- // {
- // prop: 'educationMode',
- // label: '机构办学方式',
- // type: 'select',
- // colSpan: 12,
- // dictType: 'educationMode',
- // defaultValue: '全日制',
- // placeholder: '请选择机构办学方式',
- // required: true,
- // clearable: true,
- // },
- // {
- // prop: 'institutionAddress',
- // label: '机构地址',
- // type: 'input',
- // colSpan: 12,
- // placeholder: '请输入机构地址',
- // required: true,
- // },
- // {
- // prop: 'formFiller',
- // label: '机构填表人',
- // type: 'input',
- // colSpan: 12,
- // placeholder: '请输入机构填表人',
- // required: true,
- // },
- // {
- // prop: 'financialManager',
- // label: '机构财务负责人',
- // type: 'input',
- // colSpan: 12,
- // placeholder: '请输入机构财务负责人',
- // required: true,
- // },
- // {
- // prop: 'contactPhone',
- // label: '机构联系电话',
- // type: 'input',
- // colSpan: 12,
- // placeholder: '请输入机构联系电话',
- // required: true,
- // rules: [
- // {
- // required: true,
- // message: '请输入机构联系电话',
- // trigger: 'blur',
- // },
- // {
- // pattern: /^1[3-9]\d{9}$/,
- // message: '请输入正确的手机号码',
- // trigger: 'blur',
- // },
- // ],
- // },
- // ]
- },
- getMockTableItems() {
- // return [
- // {
- // id: '1',
- // itemName: '班级数',
- // unit: '个',
- // isCategory: false,
- // seq: 1,
- // validateRules: { required: true, type: 'number', min: 0 },
- // },
- // {
- // id: '2',
- // itemName: '幼儿学生人数',
- // unit: '人',
- // isCategory: false,
- // seq: 2,
- // validateRules: { required: true, type: 'number', min: 0 },
- // },
- // ]
- },
- resetDynamicDialogState() {
- this.dynamicTableDialogVisible = false
- this.dynamicTableData = []
- this.tableItems = []
- this.dynamicDialogKey = Date.now()
- },
- },
- }
- </script>
- <style scoped>
- .text-danger {
- color: #d9001b;
- }
- /* 类别头行样式 */
- .category-header-row {
- background-color: #f5f7fa !important;
- }
- .category-header-row td {
- background-color: #f5f7fa !important;
- padding: 12px 16px !important;
- }
- .category-header-cell {
- font-weight: 700;
- color: #303133;
- padding-left: 16px;
- }
- </style>
|