infoMaintain.vue 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891
  1. <template>
  2. <div>
  3. <div class="top-wrapper">
  4. <el-button plain type="primary" icon="el-icon-back" @click="handleBack">
  5. 返回
  6. </el-button>
  7. <div class="title ml20">{{ surveyTemplateName }}内容维护</div>
  8. </div>
  9. <!-- 搜索面板 -->
  10. <div class="search-panel mt20">
  11. <el-form :inline="true" :model="searchForm" label-width="80px">
  12. <el-form-item label="状态:">
  13. <el-select
  14. v-model="searchForm.status"
  15. placeholder="请选择状态"
  16. style="width: 180px"
  17. >
  18. <el-option label="全部" value=""></el-option>
  19. <el-option label="草稿" value="-1"></el-option>
  20. <el-option label="现行版本" value="0"></el-option>
  21. <el-option label="历史版本" value="1"></el-option>
  22. </el-select>
  23. </el-form-item>
  24. <el-form-item>
  25. <el-button type="primary" icon="el-icon-search" @click="handleSearch">
  26. 查询
  27. </el-button>
  28. <el-button
  29. plain
  30. type="primary"
  31. icon="el-icon-refresh"
  32. @click="handleReset"
  33. >
  34. 重置
  35. </el-button>
  36. </el-form-item>
  37. </el-form>
  38. </div>
  39. <!-- 操作栏 -->
  40. <div class="operation-bar">
  41. <el-button
  42. plain
  43. type="success"
  44. icon="el-icon-circle-plus"
  45. @click="handleAdd"
  46. >
  47. 添加
  48. </el-button>
  49. <el-button
  50. plain
  51. type="danger"
  52. icon="el-icon-delete"
  53. :disabled="selectedRows.length === 0"
  54. @click="handleBatchDelete"
  55. >
  56. 批量删除
  57. </el-button>
  58. </div>
  59. <!-- 表格 -->
  60. <div class="table-container">
  61. <CostAuditTable
  62. ref="costAuditTable"
  63. :table-data="tableData"
  64. :columns="tableColumns"
  65. :show-selection="true"
  66. :show-index="true"
  67. :show-pagination="true"
  68. :pagination="pagination"
  69. :loading="loading"
  70. @selection-change="handleSelectionChange"
  71. @pagination-change="handlePaginationChange"
  72. >
  73. <!-- 创建时间自定义单元格 -->
  74. <template #createTime="{ row }">
  75. <div>{{ row.createTime ? row.createTime.split(' ')[0] : '-' }}</div>
  76. <div>{{ row.createTime ? row.createTime.split(' ')[1] : '-' }}</div>
  77. </template>
  78. <!-- 操作列 -->
  79. <template #action="{ row }">
  80. <el-button type="text" size="small" @click="handleViewDetail(row)">
  81. 详情
  82. </el-button>
  83. <el-button
  84. v-if="row.status === '-1'"
  85. type="text"
  86. size="small"
  87. @click="handleEdit(row)"
  88. >
  89. 修改
  90. </el-button>
  91. <el-button
  92. v-if="row.status != '0'"
  93. class="delete-btn"
  94. type="text"
  95. size="small"
  96. @click="handleDelete(row)"
  97. >
  98. 删除
  99. </el-button>
  100. <el-button
  101. v-if="row.status === '-1'"
  102. type="text"
  103. size="small"
  104. @click="handleEditContent(row)"
  105. >
  106. 内容维护
  107. </el-button>
  108. <el-button
  109. v-if="row.status === '-1'"
  110. type="text"
  111. size="small"
  112. @click="handleStatus(row)"
  113. >
  114. 启用
  115. </el-button>
  116. <el-button
  117. v-if="row.status === '0'"
  118. type="text"
  119. size="small"
  120. @click="handleStatus(row)"
  121. >
  122. 停用
  123. </el-button>
  124. </template>
  125. </CostAuditTable>
  126. </div>
  127. <!-- 详情弹窗 -->
  128. <el-dialog title="详情" :visible.sync="detailDialogVisible" width="800px">
  129. <el-form :model="detailForm" label-width="120px" class="detail-form">
  130. <el-form-item label="ID:">{{ detailForm.id }}</el-form-item>
  131. <el-form-item label="版本号:">{{ detailForm.versionNo }}</el-form-item>
  132. <el-form-item label="状态:">
  133. {{ forStatus(detailForm.status) }}
  134. </el-form-item>
  135. <el-form-item label="创建人:">{{ detailForm.createBy }}</el-form-item>
  136. <el-form-item label="创建时间:">
  137. {{ detailForm.createTime }}
  138. </el-form-item>
  139. <el-form-item label="备注:">{{ detailForm.remarks }}</el-form-item>
  140. </el-form>
  141. <div slot="footer">
  142. <el-button @click="detailDialogVisible = false">关闭</el-button>
  143. </div>
  144. </el-dialog>
  145. <!-- 添加/修改弹窗 -->
  146. <el-dialog
  147. :title="dialogTitle"
  148. :visible.sync="dialogVisible"
  149. width="600px"
  150. :close-on-click-modal="false"
  151. >
  152. <el-form
  153. ref="dataForm"
  154. :model="dataForm"
  155. :rules="dataFormRules"
  156. label-width="120px"
  157. class="data-form"
  158. >
  159. <el-form-item label="创建人" prop="createBy">
  160. <el-input
  161. v-model="dataForm.createBy"
  162. placeholder="请输入创建人"
  163. ></el-input>
  164. </el-form-item>
  165. <el-form-item label="创建时间" prop="createTime">
  166. <el-date-picker
  167. v-model="dataForm.createTime"
  168. type="datetime"
  169. placeholder="选择日期时间"
  170. style="width: 100%"
  171. ></el-date-picker>
  172. </el-form-item>
  173. <el-form-item label="备注">
  174. <el-input
  175. v-model="dataForm.remarks"
  176. type="textarea"
  177. placeholder="请输入备注"
  178. rows="3"
  179. ></el-input>
  180. </el-form-item>
  181. </el-form>
  182. <div slot="footer" class="dialog-footer">
  183. <el-button @click="dialogVisible = false">取消</el-button>
  184. <el-button type="primary" @click="submitForm">确定</el-button>
  185. </div>
  186. </el-dialog>
  187. <!-- 内容修改弹窗 -->
  188. <el-dialog
  189. title="内容维护"
  190. :visible.sync="contentEditDialogVisible"
  191. width="75%"
  192. class="content-edit-dialog"
  193. :close-on-click-modal="false"
  194. >
  195. <div class="content-edit-container">
  196. <div class="table-header-info">
  197. <div class="table-name">
  198. 调查表名称:{{ contentEditForm.tableName }}
  199. </div>
  200. <div class="table-style">
  201. 表单样式:
  202. <el-radio-group
  203. v-model="contentEditForm.templateType"
  204. @change="handleFormStyleChange"
  205. >
  206. <el-radio v-if="contentEditForm.templateType === '1'" label="1">
  207. 单记录
  208. </el-radio>
  209. <el-radio v-if="contentEditForm.templateType === '2'" label="2">
  210. 固定表
  211. </el-radio>
  212. <el-radio v-if="contentEditForm.templateType === '3'" label="3">
  213. 动态表
  214. </el-radio>
  215. </el-radio-group>
  216. </div>
  217. <div v-if="viewDetail" class="detail-info-container">
  218. <div class="detail-item">
  219. <span class="detail-label">版本号:</span>
  220. <span class="detail-value">{{ detailForm.versionNo }}</span>
  221. </div>
  222. <div class="detail-item">
  223. <span class="detail-label">状态:</span>
  224. <span class="detail-value">
  225. {{ forStatus(detailForm.status) }}
  226. </span>
  227. </div>
  228. <div class="detail-item">
  229. <span class="detail-label">创建人:</span>
  230. <span class="detail-value">{{ detailForm.createBy }}</span>
  231. </div>
  232. <div class="detail-item">
  233. <span class="detail-label">创建时间:</span>
  234. <span class="detail-value">{{ detailForm.createTime }}</span>
  235. </div>
  236. <div class="detail-item">
  237. <span class="detail-label">备注:</span>
  238. <span class="detail-value">{{ detailForm.remarks }}</span>
  239. </div>
  240. </div>
  241. </div>
  242. <!-- 单记录列表 -->
  243. <div v-if="contentEditForm.templateType === '1'">
  244. <div class="button-group">
  245. <el-button
  246. v-if="!viewDetail"
  247. type="primary"
  248. @click="handleAddTableHeader('单记录')"
  249. >
  250. 添加项目
  251. </el-button>
  252. <el-button
  253. v-if="!viewDetail"
  254. type="primary"
  255. @click="handleSaveContent('单记录')"
  256. >
  257. 保存
  258. </el-button>
  259. </div>
  260. <div class="table-edit-container">
  261. <el-table
  262. :data="contentEditForm.tableHeaders"
  263. border
  264. style="width: 100%"
  265. >
  266. <el-table-column label="序号" width="80" align="center">
  267. <template slot-scope="scope">
  268. <span>{{ scope.$index + 1 }}</span>
  269. </template>
  270. </el-table-column>
  271. <el-table-column
  272. prop="fieldName"
  273. label="字段名称"
  274. min-width="150"
  275. >
  276. <template slot-scope="scope">
  277. <el-input
  278. v-model="scope.row.fieldName"
  279. placeholder="请输入字段名称"
  280. size="small"
  281. :disabled="viewDetail"
  282. ></el-input>
  283. </template>
  284. </el-table-column>
  285. <el-table-column prop="fieldType" label="字段类型" width="220">
  286. <template slot-scope="scope">
  287. <el-select
  288. v-model="scope.row.fieldType"
  289. placeholder="请选择字段类型"
  290. size="small"
  291. :disabled="viewDetail"
  292. @change="handleFieldTypeChange(scope.row)"
  293. >
  294. <el-option label="字符串" value="string"></el-option>
  295. <el-option label="整数" value="integer"></el-option>
  296. <el-option label="小数" value="double"></el-option>
  297. <el-option label="日期" value="datetime"></el-option>
  298. <el-option label="布尔值" value="boolean"></el-option>
  299. </el-select>
  300. </template>
  301. </el-table-column>
  302. <el-table-column prop="format" label="格式" width="220">
  303. <template slot-scope="scope">
  304. <!-- 字符串类型格式 -->
  305. <div
  306. v-if="scope.row.fieldType === 'string'"
  307. class="format-input"
  308. >
  309. <span class="format-prefix">长度</span>
  310. <el-input
  311. v-model="scope.row.format"
  312. placeholder="请输入长度"
  313. size="small"
  314. style="width: calc(100% - 80px)"
  315. :disabled="viewDetail"
  316. ></el-input>
  317. </div>
  318. <!-- 整数类型格式 -->
  319. <div
  320. v-else-if="scope.row.fieldType === 'integer'"
  321. class="format-input"
  322. >
  323. <span class="format-prefix">整数</span>
  324. <el-input
  325. v-model="scope.row.fieldTypelen"
  326. placeholder="整数位数"
  327. size="small"
  328. style="width: 80px; margin: 0 5px"
  329. :disabled="viewDetail"
  330. ></el-input>
  331. </div>
  332. <!-- 小数类型格式 -->
  333. <div
  334. v-else-if="scope.row.fieldType === 'double'"
  335. class="format-input"
  336. >
  337. <span class="format-prefix">小数</span>
  338. <el-input
  339. v-model="scope.row.fieldTypenointlen"
  340. placeholder="小数位数"
  341. size="small"
  342. style="width: 80px; margin-left: 5px"
  343. :disabled="viewDetail"
  344. ></el-input>
  345. </div>
  346. <!-- 日期类型格式 -->
  347. <div
  348. v-else-if="scope.row.fieldType === 'datetime'"
  349. class="format-input"
  350. >
  351. <el-select
  352. v-model="scope.row.format"
  353. placeholder="请选择日期格式"
  354. size="small"
  355. style="width: 100%"
  356. :disabled="viewDetail"
  357. >
  358. <el-option
  359. label="yyyy-MM-dd HH:mm:ss"
  360. value="yyyy-MM-dd HH:mm:ss"
  361. ></el-option>
  362. <el-option
  363. label="yyyy-MM-dd"
  364. value="yyyy-MM-dd"
  365. ></el-option>
  366. </el-select>
  367. </div>
  368. <!-- 布尔类型格式 -->
  369. <div v-else-if="scope.row.fieldType === 'boolean'">
  370. <el-select
  371. v-model="scope.row.format"
  372. placeholder="请选择布尔值格式"
  373. size="small"
  374. style="width: 100%"
  375. :disabled="viewDetail"
  376. >
  377. <el-option label="是" value="true"></el-option>
  378. <el-option label="否" value="false"></el-option>
  379. </el-select>
  380. </div>
  381. <!-- 默认情况 -->
  382. <el-input
  383. v-else
  384. v-model="scope.row.format"
  385. :placeholder="getFormatPlaceholder(scope.row.fieldType)"
  386. size="small"
  387. :disabled="viewDetail"
  388. ></el-input>
  389. </template>
  390. </el-table-column>
  391. <el-table-column prop="isRequired" label="是否必填" width="120">
  392. <template slot-scope="scope">
  393. <el-select
  394. v-model="scope.row.isRequired"
  395. size="small"
  396. :disabled="scope.row.isDisabled || viewDetail"
  397. >
  398. <el-option label="是" value="true"></el-option>
  399. <el-option label="否" value="false"></el-option>
  400. </el-select>
  401. </template>
  402. </el-table-column>
  403. <el-table-column prop="showVisible" label="是否显示" width="120">
  404. <template slot-scope="scope">
  405. <el-select
  406. v-model="scope.row.showVisible"
  407. size="small"
  408. :disabled="scope.row.isDisabled || viewDetail"
  409. >
  410. <el-option label="是" value="1"></el-option>
  411. <el-option label="否" value="0"></el-option>
  412. </el-select>
  413. </template>
  414. </el-table-column>
  415. <el-table-column prop="isDict" label="绑定字典" min-width="150">
  416. <template slot-scope="scope">
  417. <div class="bind-dict-column">
  418. <el-select
  419. v-model="scope.row.isDict"
  420. size="small"
  421. style="width: 80px"
  422. :disabled="scope.row.isDisabled || viewDetail"
  423. @change="handleBindDictChange(scope.row)"
  424. >
  425. <el-option label="是" value="true"></el-option>
  426. <el-option label="否" value="false"></el-option>
  427. </el-select>
  428. <el-select
  429. v-if="scope.row.isDict === 'true'"
  430. v-model="scope.row.dictid"
  431. placeholder="请选择字典"
  432. class="dict-select"
  433. size="small"
  434. style="width: 120px; margin-top: 5px"
  435. :disabled="scope.row.isDisabled || viewDetail"
  436. >
  437. <el-option
  438. v-for="(item, index) in dictTypeList"
  439. :key="index"
  440. :label="item.name"
  441. :value="String(item.id)"
  442. ></el-option>
  443. </el-select>
  444. </div>
  445. </template>
  446. </el-table-column>
  447. <el-table-column label="操作" width="150" fixed="right">
  448. <template slot-scope="scope">
  449. <div class="table-actions">
  450. <el-button
  451. type="text"
  452. size="mini"
  453. :disabled="viewDetail"
  454. @click="
  455. handleDeleteHeader(scope.$index, '单记录', scope.row)
  456. "
  457. >
  458. 删除
  459. </el-button>
  460. <el-button
  461. v-if="scope.$index !== 0"
  462. type="text"
  463. size="mini"
  464. :disabled="viewDetail"
  465. @click="handleMoveUp(scope.$index)"
  466. >
  467. 上升
  468. </el-button>
  469. <el-button
  470. v-if="
  471. scope.$index !== contentEditForm.tableHeaders.length - 1
  472. "
  473. type="text"
  474. size="mini"
  475. :disabled="viewDetail"
  476. @click="handleMoveDown(scope.$index)"
  477. >
  478. 下降
  479. </el-button>
  480. </div>
  481. </template>
  482. </el-table-column>
  483. </el-table>
  484. </div>
  485. </div>
  486. <!-- 固定表时显示 -->
  487. <div v-if="contentEditForm.templateType === '2'">
  488. <div class="button-group">
  489. <el-button
  490. v-if="!viewDetail"
  491. type="primary"
  492. @click="handleAddTableHeader('固定表表头')"
  493. >
  494. 添加表头
  495. </el-button>
  496. <el-button
  497. v-if="!viewDetail"
  498. type="primary"
  499. @click="handleSaveContent('固定表表头')"
  500. >
  501. 下一步
  502. </el-button>
  503. </div>
  504. <div class="table-edit-container">
  505. <el-table
  506. :data="contentEditForm.fixedTable.tableHeaders"
  507. border
  508. style="width: 100%"
  509. >
  510. <el-table-column label="序号" width="80" align="center">
  511. <template slot-scope="scope">
  512. <span>{{ scope.$index + 1 }}</span>
  513. </template>
  514. </el-table-column>
  515. <el-table-column
  516. prop="fieldName"
  517. label="字段名称"
  518. min-width="150"
  519. >
  520. <template slot-scope="scope">
  521. <el-input
  522. v-model="scope.row.fieldName"
  523. placeholder="请输入字段名称"
  524. size="small"
  525. :disabled="scope.row.isDisabled || viewDetail"
  526. ></el-input>
  527. </template>
  528. </el-table-column>
  529. <el-table-column prop="fieldType" label="字段类型" width="120">
  530. <template slot-scope="scope">
  531. <el-select
  532. v-model="scope.row.fieldType"
  533. placeholder="请选择字段类型"
  534. size="small"
  535. :disabled="scope.row.isDisabled || viewDetail"
  536. @change="handleFieldTypeChange(scope.row)"
  537. >
  538. <el-option label="字符串" value="string"></el-option>
  539. <el-option label="整数" value="integer"></el-option>
  540. <el-option label="小数" value="double"></el-option>
  541. <el-option label="日期" value="datetime"></el-option>
  542. <el-option label="布尔值" value="boolean"></el-option>
  543. </el-select>
  544. </template>
  545. </el-table-column>
  546. <el-table-column prop="format" label="格式" width="220">
  547. <template slot-scope="scope">
  548. <!-- 字符串类型格式 -->
  549. <div
  550. v-if="scope.row.fieldType === 'string'"
  551. class="format-input"
  552. >
  553. <span class="format-prefix">长度</span>
  554. <el-input
  555. v-model="scope.row.format"
  556. placeholder="请输入长度"
  557. size="small"
  558. style="width: calc(100% - 80px)"
  559. :disabled="scope.row.isDisabled || viewDetail"
  560. ></el-input>
  561. </div>
  562. <!-- 整数类型格式 -->
  563. <div
  564. v-else-if="scope.row.fieldType === 'integer'"
  565. class="format-input"
  566. >
  567. <span class="format-prefix">整数</span>
  568. <el-input
  569. v-model="scope.row.fieldTypelen"
  570. placeholder="整数位数"
  571. size="small"
  572. style="width: 80px; margin: 0 5px"
  573. :disabled="scope.row.isDisabled || viewDetail"
  574. ></el-input>
  575. </div>
  576. <!-- 小数类型格式 -->
  577. <div
  578. v-else-if="scope.row.fieldType === 'double'"
  579. class="format-input"
  580. >
  581. <span class="format-prefix">小数</span>
  582. <el-input
  583. v-model="scope.row.fieldTypenointlen"
  584. placeholder="小数位数"
  585. size="small"
  586. style="width: 80px; margin-left: 5px"
  587. :disabled="scope.row.isDisabled || viewDetail"
  588. ></el-input>
  589. </div>
  590. <!-- 日期类型格式 -->
  591. <div
  592. v-else-if="scope.row.fieldType === 'datetime'"
  593. class="format-input"
  594. >
  595. <el-select
  596. v-model="scope.row.format"
  597. placeholder="请选择日期格式"
  598. size="small"
  599. style="width: 100%"
  600. :disabled="scope.row.isDisabled"
  601. >
  602. <el-option
  603. label="yyyy-MM-dd HH:mm:ss"
  604. value="yyyy-MM-dd HH:mm:ss"
  605. ></el-option>
  606. <el-option
  607. label="yyyy-MM-dd"
  608. value="yyyy-MM-dd"
  609. ></el-option>
  610. </el-select>
  611. </div>
  612. <!-- 布尔类型格式 -->
  613. <div v-else-if="scope.row.fieldType === 'boolean'">
  614. <el-select
  615. v-model="scope.row.format"
  616. placeholder="请选择布尔值格式"
  617. size="small"
  618. style="width: 100%"
  619. :disabled="scope.row.isDisabled || viewDetail"
  620. >
  621. <el-option label="是" value="true"></el-option>
  622. <el-option label="否" value="false"></el-option>
  623. </el-select>
  624. </div>
  625. <!-- 默认情况 -->
  626. <el-input
  627. v-else
  628. v-model="scope.row.format"
  629. :placeholder="getFormatPlaceholder(scope.row.fieldType)"
  630. size="small"
  631. :disabled="scope.row.isDisabled || viewDetail"
  632. ></el-input>
  633. </template>
  634. </el-table-column>
  635. <el-table-column prop="isRequired" label="是否必填" width="120">
  636. <template slot-scope="scope">
  637. <el-select
  638. v-model="scope.row.isRequired"
  639. size="small"
  640. :disabled="scope.row.isDisabled || viewDetail"
  641. >
  642. <el-option label="是" value="true"></el-option>
  643. <el-option label="否" value="false"></el-option>
  644. </el-select>
  645. </template>
  646. </el-table-column>
  647. <el-table-column prop="showVisible" label="是否显示" width="120">
  648. <template slot-scope="scope">
  649. <el-select
  650. v-model="scope.row.showVisible"
  651. size="small"
  652. :disabled="scope.row.isDisabled || viewDetail"
  653. >
  654. <el-option label="是" value="1"></el-option>
  655. <el-option label="否" value="0"></el-option>
  656. </el-select>
  657. </template>
  658. </el-table-column>
  659. <el-table-column
  660. prop="isAuditPeriod"
  661. label="是否绑定监审期间"
  662. width="140"
  663. >
  664. <template slot-scope="scope">
  665. <el-select
  666. v-model="scope.row.isAuditPeriod"
  667. size="small"
  668. :disabled="scope.row.isDisabled || viewDetail"
  669. >
  670. <el-option label="是" value="true"></el-option>
  671. <el-option label="否" value="false"></el-option>
  672. </el-select>
  673. </template>
  674. </el-table-column>
  675. <el-table-column prop="isDict" label="绑定字典" min-width="150">
  676. <template slot-scope="scope">
  677. <div class="bind-dict-column">
  678. <el-select
  679. v-model="scope.row.isDict"
  680. size="small"
  681. style="width: 80px"
  682. :disabled="scope.row.isDisabled || viewDetail"
  683. @change="handleBindDictChange(scope.row)"
  684. >
  685. <el-option label="是" value="true"></el-option>
  686. <el-option label="否" value="false"></el-option>
  687. </el-select>
  688. <el-select
  689. v-if="scope.row.isDict === 'true'"
  690. v-model="scope.row.dictid"
  691. placeholder="请选择字典"
  692. class="dict-select"
  693. size="small"
  694. style="width: 120px; margin-top: 5px"
  695. :disabled="scope.row.isDisabled || viewDetail"
  696. >
  697. <el-option
  698. v-for="(item, index) in dictTypeList"
  699. :key="index"
  700. :label="item.name"
  701. :value="String(item.id)"
  702. ></el-option>
  703. </el-select>
  704. </div>
  705. </template>
  706. </el-table-column>
  707. <el-table-column label="操作" width="150" fixed="right">
  708. <template slot-scope="scope">
  709. <div class="table-actions">
  710. <el-button
  711. type="text"
  712. size="mini"
  713. :disabled="scope.row.isDisabled || viewDetail"
  714. @click="
  715. handleDeleteHeader(
  716. scope.$index,
  717. '固定表表头',
  718. scope.row
  719. )
  720. "
  721. >
  722. 删除
  723. </el-button>
  724. <el-button
  725. v-if="scope.$index !== 0"
  726. type="text"
  727. size="mini"
  728. :disabled="scope.row.isDisabled || viewDetail"
  729. @click="handleMoveUp(scope.$index)"
  730. >
  731. 上升
  732. </el-button>
  733. <el-button
  734. v-if="
  735. scope.$index !== contentEditForm.tableHeaders.length - 1
  736. "
  737. type="text"
  738. size="mini"
  739. :disabled="scope.row.isDisabled || viewDetail"
  740. @click="handleMoveDown(scope.$index)"
  741. >
  742. 下降
  743. </el-button>
  744. </div>
  745. </template>
  746. </el-table-column>
  747. </el-table>
  748. </div>
  749. <div>
  750. <div class="button-group">
  751. <el-button
  752. v-if="!viewDetail"
  753. type="primary"
  754. @click="handleAddTableHeader('固定表项目')"
  755. >
  756. 添加项目
  757. </el-button>
  758. <el-button
  759. v-if="!viewDetail"
  760. type="primary"
  761. @click="handleSaveContent('固定表项目')"
  762. >
  763. 保存
  764. </el-button>
  765. </div>
  766. <div class="table-edit-container">
  767. <el-table
  768. :data="contentEditForm.fixedTable.fixedTables"
  769. border
  770. style="width: 100%"
  771. @selection-change="handleSelectionChange"
  772. >
  773. <el-table-column label="序号" width="100" align="center">
  774. <template slot-scope="scope">
  775. <el-input
  776. :value="
  777. scope.row.fixedValues
  778. ? scope.row.fixedValues['序号']
  779. : ''
  780. "
  781. size="small"
  782. placeholder="数字或中文"
  783. :disabled="viewDetail"
  784. @input="handleFixedValueChange(scope.row, '序号', $event)"
  785. ></el-input>
  786. </template>
  787. </el-table-column>
  788. <el-table-column
  789. label="父子节点关系"
  790. align="center"
  791. width="120"
  792. >
  793. <template slot-scope="scope">
  794. <el-tag
  795. v-if="
  796. scope.row.isChild ||
  797. scope.row.isSubItem ||
  798. (scope.row.parentid &&
  799. scope.row.parentid != -1 &&
  800. scope.row.parentid != '-1')
  801. "
  802. type="success"
  803. size="small"
  804. >
  805. 子项
  806. </el-tag>
  807. <el-tag
  808. v-else-if="
  809. scope.row.parentid === -1 ||
  810. scope.row.parentid === '-1' ||
  811. !scope.row.parentid
  812. "
  813. type="primary"
  814. size="small"
  815. >
  816. 父项
  817. </el-tag>
  818. <el-tag v-else type="info" size="small">无</el-tag>
  819. </template>
  820. </el-table-column>
  821. <el-table-column
  822. v-for="(item, index) in contentEditForm.fixedTable
  823. .fixedTableHeaders"
  824. :key="index"
  825. :label="item.rkey"
  826. align="center"
  827. >
  828. <template slot-scope="scope">
  829. <el-input
  830. :value="
  831. scope.row.fixedValues
  832. ? scope.row.fixedValues[item.rkey]
  833. : ''
  834. "
  835. size="small"
  836. :disabled="viewDetail"
  837. @input="
  838. handleFixedValueChange(scope.row, item.rkey, $event)
  839. "
  840. ></el-input>
  841. </template>
  842. </el-table-column>
  843. <el-table-column label="指标编号" width="100" align="center">
  844. <template slot-scope="scope">
  845. <el-input
  846. :value="scope.row.cellCode"
  847. size="small"
  848. :disabled="viewDetail"
  849. @input="(val) => $set(scope.row, 'cellCode', val)"
  850. ></el-input>
  851. </template>
  852. </el-table-column>
  853. <el-table-column label="计算公式" width="100" align="center">
  854. <template slot-scope="scope">
  855. <el-input
  856. v-model="scope.row.calculationFormula"
  857. size="small"
  858. readonly
  859. :disabled="viewDetail"
  860. @click.native="
  861. openCalculationFormulaDialogVisible(
  862. scope.row,
  863. scope.$index
  864. )
  865. "
  866. ></el-input>
  867. </template>
  868. </el-table-column>
  869. <el-table-column label="单位" width="100" align="center">
  870. <template slot-scope="scope">
  871. <el-input
  872. :value="scope.row.unit"
  873. size="small"
  874. :disabled="viewDetail"
  875. @input="(val) => $set(scope.row, 'unit', val)"
  876. ></el-input>
  877. </template>
  878. </el-table-column>
  879. <el-table-column label="操作" align="center" fixed="right">
  880. <template slot-scope="scope">
  881. <div class="table-actions">
  882. <el-button
  883. v-if="!scope.row.isChild"
  884. type="text"
  885. size="mini"
  886. :disabled="viewDetail"
  887. @click="
  888. handleAddChildItem(
  889. scope.$index,
  890. '固定表项目',
  891. scope.row
  892. )
  893. "
  894. >
  895. 添加子项
  896. </el-button>
  897. <el-button
  898. type="text"
  899. size="mini"
  900. :disabled="viewDetail"
  901. @click="
  902. handleDeleteHeader(
  903. scope.$index,
  904. '固定表项目',
  905. scope.row
  906. )
  907. "
  908. >
  909. 删除
  910. </el-button>
  911. <el-button
  912. v-if="scope.$index !== 0"
  913. type="text"
  914. size="mini"
  915. :disabled="viewDetail"
  916. @click="handleMoveUp(scope.$index, '固定表')"
  917. >
  918. 上升
  919. </el-button>
  920. <el-button
  921. v-if="
  922. scope.$index !==
  923. contentEditForm.tableHeaders.length - 1
  924. "
  925. type="text"
  926. size="mini"
  927. :disabled="viewDetail"
  928. @click="handleMoveDown(scope.$index, '固定表')"
  929. >
  930. 下降
  931. </el-button>
  932. </div>
  933. </template>
  934. </el-table-column>
  935. </el-table>
  936. </div>
  937. </div>
  938. </div>
  939. <!-- 动态表时显示 -->
  940. <div v-if="contentEditForm.templateType === '3'">
  941. <div class="button-group">
  942. <el-button
  943. v-if="!viewDetail"
  944. type="primary"
  945. @click="handleAddTableHeader('动态表表头')"
  946. >
  947. 添加表头
  948. </el-button>
  949. <el-button
  950. v-if="!viewDetail"
  951. type="primary"
  952. @click="handleSaveContent('动态表表头')"
  953. >
  954. 下一步
  955. </el-button>
  956. </div>
  957. <div class="table-edit-container">
  958. <el-table
  959. :data="contentEditForm.dynamicTable.tableHeaders"
  960. border
  961. style="width: 100%"
  962. >
  963. <el-table-column label="序号" width="80" align="center">
  964. <template slot-scope="scope">
  965. <span>{{ scope.$index + 1 }}</span>
  966. </template>
  967. </el-table-column>
  968. <el-table-column
  969. prop="fieldName"
  970. label="字段名称"
  971. min-width="150"
  972. >
  973. <template slot-scope="scope">
  974. <el-input
  975. v-model="scope.row.fieldName"
  976. placeholder="请输入字段名称"
  977. size="small"
  978. :disabled="scope.row.isDisabled || viewDetail"
  979. ></el-input>
  980. </template>
  981. </el-table-column>
  982. <el-table-column prop="fieldType" label="字段类型" width="120">
  983. <template slot-scope="scope">
  984. <el-select
  985. v-model="scope.row.fieldType"
  986. placeholder="请选择字段类型"
  987. size="small"
  988. :disabled="scope.row.isDisabled || viewDetail"
  989. @change="handleFieldTypeChange(scope.row)"
  990. >
  991. <el-option label="字符串" value="string"></el-option>
  992. <el-option label="整数" value="integer"></el-option>
  993. <el-option label="小数" value="double"></el-option>
  994. <el-option label="日期" value="datetime"></el-option>
  995. <el-option label="布尔值" value="boolean"></el-option>
  996. </el-select>
  997. </template>
  998. </el-table-column>
  999. <el-table-column prop="format" label="格式" width="220">
  1000. <template slot-scope="scope">
  1001. <!-- 字符串类型格式 -->
  1002. <div
  1003. v-if="scope.row.fieldType === 'string'"
  1004. class="format-input"
  1005. >
  1006. <span class="format-prefix">长度</span>
  1007. <el-input
  1008. v-model="scope.row.format"
  1009. placeholder="请输入长度"
  1010. size="small"
  1011. style="width: calc(100% - 80px)"
  1012. :disabled="scope.row.isDisabled || viewDetail"
  1013. ></el-input>
  1014. </div>
  1015. <!-- 整数类型格式 -->
  1016. <div
  1017. v-else-if="scope.row.fieldType === 'integer'"
  1018. class="format-input"
  1019. >
  1020. <span class="format-prefix">整数</span>
  1021. <el-input
  1022. v-model="scope.row.fieldTypelen"
  1023. placeholder="整数位数"
  1024. size="small"
  1025. style="width: 80px; margin: 0 5px"
  1026. :disabled="scope.row.isDisabled || viewDetail"
  1027. ></el-input>
  1028. </div>
  1029. <!-- 小数类型格式 -->
  1030. <div
  1031. v-else-if="scope.row.fieldType === 'double'"
  1032. class="format-input"
  1033. >
  1034. <span class="format-prefix">小数</span>
  1035. <el-input
  1036. v-model="scope.row.fieldTypenointlen"
  1037. placeholder="小数位数"
  1038. size="small"
  1039. style="width: 80px; margin-left: 5px"
  1040. :disabled="scope.row.isDisabled || viewDetail"
  1041. ></el-input>
  1042. </div>
  1043. <!-- 日期类型格式 -->
  1044. <div
  1045. v-else-if="scope.row.fieldType === 'datetime'"
  1046. class="format-input"
  1047. >
  1048. <el-select
  1049. v-model="scope.row.format"
  1050. placeholder="请选择日期格式"
  1051. size="small"
  1052. style="width: 100%"
  1053. :disabled="scope.row.isDisabled || viewDetail"
  1054. >
  1055. <el-option
  1056. label="yyyy-MM-dd HH:mm:ss"
  1057. value="yyyy-MM-dd HH:mm:ss"
  1058. ></el-option>
  1059. <el-option
  1060. label="yyyy-MM-dd"
  1061. value="yyyy-MM-dd"
  1062. ></el-option>
  1063. </el-select>
  1064. </div>
  1065. <!-- 布尔类型格式 -->
  1066. <div v-else-if="scope.row.fieldType === 'boolean'">
  1067. <el-select
  1068. v-model="scope.row.format"
  1069. placeholder="请选择布尔值格式"
  1070. size="small"
  1071. style="width: 100%"
  1072. :disabled="scope.row.isDisabled || viewDetail"
  1073. >
  1074. <el-option label="是" value="true"></el-option>
  1075. <el-option label="否" value="false"></el-option>
  1076. </el-select>
  1077. </div>
  1078. <!-- 默认情况 -->
  1079. <el-input
  1080. v-else
  1081. v-model="scope.row.format"
  1082. :placeholder="getFormatPlaceholder(scope.row.fieldType)"
  1083. size="small"
  1084. :disabled="scope.row.isDisabled || viewDetail"
  1085. ></el-input>
  1086. </template>
  1087. </el-table-column>
  1088. <el-table-column prop="isRequired" label="是否必填" width="120">
  1089. <template slot-scope="scope">
  1090. <el-select
  1091. v-model="scope.row.isRequired"
  1092. size="small"
  1093. :disabled="scope.row.isDisabled || viewDetail"
  1094. >
  1095. <el-option label="是" value="true"></el-option>
  1096. <el-option label="否" value="false"></el-option>
  1097. </el-select>
  1098. </template>
  1099. </el-table-column>
  1100. <el-table-column prop="showVisible" label="是否显示" width="120">
  1101. <template slot-scope="scope">
  1102. <el-select
  1103. v-model="scope.row.showVisible"
  1104. size="small"
  1105. :disabled="scope.row.isDisabled || viewDetail"
  1106. >
  1107. <el-option label="是" value="1"></el-option>
  1108. <el-option label="否" value="0"></el-option>
  1109. </el-select>
  1110. </template>
  1111. </el-table-column>
  1112. <el-table-column prop="isDict" label="绑定字典" min-width="150">
  1113. <template slot-scope="scope">
  1114. <div class="bind-dict-column">
  1115. <el-select
  1116. v-model="scope.row.isDict"
  1117. size="small"
  1118. style="width: 80px"
  1119. :disabled="scope.row.isDisabled || viewDetail"
  1120. @change="handleBindDictChange(scope.row)"
  1121. >
  1122. <el-option label="是" value="true"></el-option>
  1123. <el-option label="否" value="false"></el-option>
  1124. </el-select>
  1125. <el-select
  1126. v-if="scope.row.isDict === 'true'"
  1127. v-model="scope.row.dictid"
  1128. placeholder="请选择字典"
  1129. class="dict-select"
  1130. size="small"
  1131. style="width: 120px; margin-top: 5px"
  1132. :disabled="scope.row.isDisabled || viewDetail"
  1133. >
  1134. <el-option
  1135. v-for="(item, index) in dictTypeList"
  1136. :key="index"
  1137. :label="item.name"
  1138. :value="String(item.id)"
  1139. ></el-option>
  1140. </el-select>
  1141. </div>
  1142. </template>
  1143. </el-table-column>
  1144. <el-table-column label="操作" width="150" fixed="right">
  1145. <template slot-scope="scope">
  1146. <div class="table-actions">
  1147. <el-button
  1148. type="text"
  1149. size="mini"
  1150. :disabled="scope.row.isDisabled || viewDetail"
  1151. @click="
  1152. handleDeleteHeader(
  1153. scope.$index,
  1154. '动态表表头',
  1155. scope.row
  1156. )
  1157. "
  1158. >
  1159. 删除
  1160. </el-button>
  1161. <el-button
  1162. v-if="scope.$index !== 0"
  1163. type="text"
  1164. size="mini"
  1165. :disabled="scope.row.isDisabled || viewDetail"
  1166. @click="handleMoveUp(scope.$index)"
  1167. >
  1168. 上升
  1169. </el-button>
  1170. <el-button
  1171. v-if="
  1172. scope.$index !== contentEditForm.tableHeaders.length - 1
  1173. "
  1174. type="text"
  1175. size="mini"
  1176. :disabled="scope.row.isDisabled || viewDetail"
  1177. @click="handleMoveDown(scope.$index)"
  1178. >
  1179. 下降
  1180. </el-button>
  1181. </div>
  1182. </template>
  1183. </el-table-column>
  1184. </el-table>
  1185. </div>
  1186. <div>
  1187. <div class="button-group">
  1188. <el-button
  1189. v-if="!viewDetail"
  1190. type="primary"
  1191. @click="handleAddTableHeader('动态表项目')"
  1192. >
  1193. 添加项目
  1194. </el-button>
  1195. <el-button
  1196. v-if="!viewDetail"
  1197. type="primary"
  1198. @click="handleSaveContent('动态表项目')"
  1199. >
  1200. 保存
  1201. </el-button>
  1202. </div>
  1203. <div class="table-edit-container">
  1204. <el-table
  1205. :data="contentEditForm.dynamicTable.dynamicTables"
  1206. border
  1207. style="width: 100%"
  1208. @selection-change="handleSelectionChange"
  1209. >
  1210. <el-table-column label="序号" width="100" align="center">
  1211. <template slot-scope="scope">
  1212. <el-input
  1213. :value="
  1214. scope.row.dynamicValues
  1215. ? scope.row.dynamicValues['序号']
  1216. : ''
  1217. "
  1218. size="small"
  1219. placeholder="数字或中文"
  1220. :disabled="viewDetail"
  1221. @input="
  1222. handleDynamicValueChange(scope.row, '序号', $event)
  1223. "
  1224. ></el-input>
  1225. </template>
  1226. </el-table-column>
  1227. <el-table-column
  1228. label="父子节点关系"
  1229. align="center"
  1230. width="120"
  1231. >
  1232. <template slot-scope="scope">
  1233. <el-tag
  1234. v-if="
  1235. scope.row.isChild ||
  1236. scope.row.isSubItem ||
  1237. (scope.row.parentid &&
  1238. scope.row.parentid != -1 &&
  1239. scope.row.parentid != '-1')
  1240. "
  1241. type="success"
  1242. size="small"
  1243. >
  1244. 子项
  1245. </el-tag>
  1246. <el-tag
  1247. v-else-if="
  1248. scope.row.parentid === -1 ||
  1249. scope.row.parentid === '-1' ||
  1250. !scope.row.parentid
  1251. "
  1252. type="primary"
  1253. size="small"
  1254. >
  1255. 父项
  1256. </el-tag>
  1257. <el-tag v-else type="info" size="small">无</el-tag>
  1258. </template>
  1259. </el-table-column>
  1260. <el-table-column
  1261. v-for="(item, index) in contentEditForm.dynamicTable
  1262. .dynamicTableHeaders"
  1263. :key="index"
  1264. :label="item.rkey"
  1265. align="center"
  1266. >
  1267. <template slot-scope="scope">
  1268. <el-input
  1269. :value="
  1270. scope.row.dynamicValues
  1271. ? scope.row.dynamicValues[item.rkey]
  1272. : ''
  1273. "
  1274. size="small"
  1275. :disabled="viewDetail"
  1276. @input="
  1277. handleDynamicValueChange(scope.row, item.rkey, $event)
  1278. "
  1279. ></el-input>
  1280. </template>
  1281. </el-table-column>
  1282. <el-table-column label="操作" align="center" fixed="right">
  1283. <template slot-scope="scope">
  1284. <div class="table-actions">
  1285. <el-button
  1286. v-if="!scope.row.isChild"
  1287. type="text"
  1288. size="mini"
  1289. :disabled="viewDetail"
  1290. @click="
  1291. handleAddChildItem(
  1292. scope.$index,
  1293. '动态表项目',
  1294. scope.row
  1295. )
  1296. "
  1297. >
  1298. 添加子项
  1299. </el-button>
  1300. <el-button
  1301. type="text"
  1302. size="mini"
  1303. :disabled="viewDetail"
  1304. @click="
  1305. handleDeleteHeader(
  1306. scope.$index,
  1307. '动态表项目',
  1308. scope.row
  1309. )
  1310. "
  1311. >
  1312. 删除
  1313. </el-button>
  1314. <el-button
  1315. v-if="scope.$index !== 0"
  1316. type="text"
  1317. size="mini"
  1318. :disabled="viewDetail"
  1319. @click="handleMoveUp(scope.$index, '动态表')"
  1320. >
  1321. 上升
  1322. </el-button>
  1323. <el-button
  1324. v-if="
  1325. scope.$index !==
  1326. contentEditForm.tableHeaders.length - 1
  1327. "
  1328. type="text"
  1329. size="mini"
  1330. :disabled="viewDetail"
  1331. @click="handleMoveDown(scope.$index, '动态表')"
  1332. >
  1333. 下降
  1334. </el-button>
  1335. </div>
  1336. </template>
  1337. </el-table-column>
  1338. </el-table>
  1339. </div>
  1340. </div>
  1341. </div>
  1342. </div>
  1343. </el-dialog>
  1344. <el-dialog
  1345. title="计算公式"
  1346. :visible.sync="calculationFormulaDialogVisible"
  1347. width="30%"
  1348. :before-close="handleDialogClose"
  1349. >
  1350. <!-- 单选按钮组:切换“当前指标项”/“其他模板指标项” -->
  1351. <el-radio-group
  1352. v-model="radioType"
  1353. class="mb20"
  1354. @change="handleRadioChange"
  1355. >
  1356. <el-radio label="current">当前指标项</el-radio>
  1357. <el-radio label="other">其他模板指标项</el-radio>
  1358. </el-radio-group>
  1359. <!-- 「当前指标项」内容区域 -->
  1360. <div v-if="radioType === 'current'" class="current-panel">
  1361. <el-input
  1362. v-model="formulaText"
  1363. type="textarea"
  1364. rows="4"
  1365. placeholder="请输入公式(如 C1+C2+C3)"
  1366. />
  1367. </div>
  1368. <!-- 「其他模板指标项」内容区域 -->
  1369. <div v-else class="other-panel">
  1370. <span>版本号:</span>
  1371. <el-select
  1372. v-model="selectedTemplateId"
  1373. placeholder="请选择版本号"
  1374. @change="handleTemplateChange"
  1375. >
  1376. <el-option
  1377. v-for="(item, index) in templateList"
  1378. :key="index"
  1379. :label="item.versionNo"
  1380. :value="item.pkVal"
  1381. ></el-option>
  1382. </el-select>
  1383. <!-- 指标表格 -->
  1384. <el-table
  1385. ref="indicatorTable"
  1386. :data="indicatorTableData"
  1387. border
  1388. style="width: 100%; margin-top: 10px"
  1389. @row-click="handleRowClick"
  1390. >
  1391. <el-table-column label="选择" width="60">
  1392. <template #default="scope">
  1393. <el-checkbox
  1394. v-model="scope.row.checked"
  1395. @change="handleCheckboxChange(scope.row)"
  1396. @click.stop
  1397. ></el-checkbox>
  1398. </template>
  1399. </el-table-column>
  1400. <el-table-column
  1401. label="指标编号"
  1402. prop="cellCode"
  1403. align="center"
  1404. ></el-table-column>
  1405. <!--循环表头 -->
  1406. <el-table-column
  1407. v-for="(item, index) in indicatorTableHeaders"
  1408. :key="index"
  1409. :label="item.rkey"
  1410. align="center"
  1411. show-overflow-tooltip
  1412. >
  1413. <template slot-scope="scope">
  1414. {{
  1415. scope.row.fixedValues ? scope.row.fixedValues[item.rkey] : ''
  1416. }}
  1417. </template>
  1418. </el-table-column>
  1419. </el-table>
  1420. <el-input
  1421. v-model="formulaText"
  1422. type="textarea"
  1423. rows="4"
  1424. placeholder="请输入公式(如 C1+C2+C3)"
  1425. @input="handleFormulaTextChange"
  1426. />
  1427. </div>
  1428. <!-- 弹窗底部按钮 -->
  1429. <template #footer>
  1430. <span class="dialog-footer">
  1431. <el-button type="primary" @click="handleConfirm">确定</el-button>
  1432. <el-button @click="calculationFormulaDialogVisible = false">
  1433. 取消
  1434. </el-button>
  1435. </span>
  1436. </template>
  1437. </el-dialog>
  1438. </div>
  1439. </template>
  1440. <script>
  1441. // 导入API模块
  1442. import {
  1443. getCostFormList,
  1444. addCostForm,
  1445. editCostForm,
  1446. deleteCostForm,
  1447. getDataStorageTableOptions,
  1448. } from '@/api/costFormManage'
  1449. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  1450. import { getDictTypList } from '@/api/dictionaryManage.js'
  1451. import {
  1452. listByTemplateIdAndVersion,
  1453. getCellCodesByTemplateId,
  1454. } from '@/api/costSurveyTemplateItems'
  1455. import {
  1456. addSurveyTemplateVersion,
  1457. delSurveyTemplateVersionById,
  1458. putSurveyTemplatePublishVersion,
  1459. getCostSurveyTemplateVersionsByTemplateId,
  1460. batchDeleteCostForm,
  1461. } from '@/api/costSurveyTemplateVersion'
  1462. import { getListFixedEnabled } from '@/api/costSurveyTemplate'
  1463. import { listByCurrentTemplateId } from '@/api/catalogManage.js'
  1464. import {
  1465. getListBySurveyTemplateId,
  1466. getListBySurveyTemplateIdAndVersion,
  1467. getBatchSaveOrUpdate,
  1468. } from '@/api/costSurveyTemplateHeaders'
  1469. import { commonMixin } from '@/mixins/useDict'
  1470. import { mapState } from 'vuex'
  1471. export default {
  1472. name: 'InfoMaintain',
  1473. components: {
  1474. CostAuditTable,
  1475. },
  1476. mixins: [commonMixin],
  1477. data() {
  1478. return {
  1479. surveyTemplateName: '',
  1480. loading: false,
  1481. searchForm: {
  1482. status: '',
  1483. },
  1484. tableData: [],
  1485. currentRow: null,
  1486. selectedRows: [],
  1487. pagination: {
  1488. currentPage: 1,
  1489. pageSize: 50,
  1490. total: 0, // 初始化为0
  1491. },
  1492. dialogVisible: false,
  1493. detailDialogVisible: false,
  1494. viewDetail: false,
  1495. contentEditDialogVisible: false,
  1496. calculationFormulaDialogVisible: false,
  1497. currentEditingRow: null,
  1498. currentEditingRowIndex: -1,
  1499. radioType: 'current',
  1500. formulaText: 'C1+C2+C3',
  1501. templateName: '',
  1502. templateList: [],
  1503. indicatorTableData: [],
  1504. indicatorTableHeaders: [],
  1505. selectedIndicatorCodes: [],
  1506. selectedIndicatorsPerTemplate: {},
  1507. dialogTitle: '',
  1508. dataForm: {
  1509. id: null,
  1510. version: '',
  1511. status: '',
  1512. createBy: '',
  1513. createTime: '',
  1514. remark: '',
  1515. },
  1516. detailForm: {
  1517. id: null,
  1518. version: '',
  1519. status: '',
  1520. createBy: '',
  1521. createTime: '',
  1522. remark: '',
  1523. },
  1524. contentEditForm: {
  1525. tableName: '',
  1526. templateType: '1',
  1527. versionId: '',
  1528. // 单记录列表
  1529. tableHeaders: [],
  1530. // 固定表列表
  1531. fixedTable: {
  1532. tableHeaders: [],
  1533. fixedTables: [],
  1534. fixedTablesTitle: [],
  1535. fixedTableHeaders: [],
  1536. },
  1537. // 动态表列表
  1538. dynamicTable: {
  1539. tableHeaders: [],
  1540. dynamicTables: [],
  1541. dynamicTablesTitle: [],
  1542. dynamicTableHeaders: [],
  1543. },
  1544. isDynamicTables: false,
  1545. isFixedTables: false,
  1546. },
  1547. tableKey: 0, // 用于强制刷新表格
  1548. dataFormRules: {
  1549. status: [
  1550. { required: true, message: '请选择状态', trigger: 'change' },
  1551. ],
  1552. createBy: [
  1553. { required: true, message: '请输入创建人', trigger: 'blur' },
  1554. ],
  1555. createTime: [
  1556. { required: true, message: '请选择创建时间', trigger: 'change' },
  1557. ],
  1558. },
  1559. id: '', // 从路由获取的ID
  1560. dataStorageTableOptions: [], // 数据存储库表选项
  1561. surveyTemplateId: '', // 成本调查表ID
  1562. versionId: '',
  1563. dictTypeList: [],
  1564. }
  1565. },
  1566. computed: {
  1567. ...mapState('user', ['userInfo', 'username']),
  1568. formatter: (status) => {
  1569. return status === '-1' ? '草稿' : status === '0' ? '现行' : '历史'
  1570. },
  1571. tableColumns() {
  1572. return [
  1573. {
  1574. prop: 'versionNo',
  1575. label: '版本号',
  1576. align: 'center',
  1577. showOverflowTooltip: true,
  1578. },
  1579. {
  1580. prop: 'status',
  1581. label: '状态',
  1582. align: 'center',
  1583. formatter: (row) => {
  1584. return row.status == '-1'
  1585. ? '草稿'
  1586. : row.status == '0'
  1587. ? '现行'
  1588. : '历史'
  1589. },
  1590. },
  1591. {
  1592. prop: 'createBy',
  1593. label: '创建人',
  1594. align: 'center',
  1595. },
  1596. {
  1597. prop: 'createTime',
  1598. label: '创建时间',
  1599. showOverflowTooltip: true,
  1600. slotName: 'createTime',
  1601. },
  1602. {
  1603. prop: 'remarks',
  1604. label: '备注',
  1605. align: 'center',
  1606. showOverflowTooltip: true,
  1607. },
  1608. {
  1609. prop: 'action',
  1610. width: '270',
  1611. label: '操作',
  1612. align: 'center',
  1613. fixed: 'right',
  1614. slotName: 'action',
  1615. },
  1616. ]
  1617. },
  1618. },
  1619. watch: {
  1620. indicatorTableData: {
  1621. handler(newVal) {
  1622. if (this.radioType === 'other' && this.selectedTemplateId) {
  1623. this.$set(
  1624. this.selectedIndicatorsPerTemplate,
  1625. this.selectedTemplateId,
  1626. newVal.filter((item) => item.checked)
  1627. )
  1628. }
  1629. this.updateSelectedIndicatorCodes()
  1630. },
  1631. deep: true,
  1632. },
  1633. selectedIndicatorCodes: {
  1634. handler(newVal) {
  1635. if (this.radioType === 'other') {
  1636. const allSelectedTemplateIds = [
  1637. ...new Set([
  1638. this.selectedTemplateId,
  1639. ...Object.keys(this.selectedIndicatorsPerTemplate).filter(
  1640. (id) =>
  1641. id !== this.selectedTemplateId &&
  1642. this.selectedIndicatorsPerTemplate[id].some(
  1643. (item) => item.checked
  1644. )
  1645. ),
  1646. ]),
  1647. ].filter((id) => id)
  1648. const isSingleTemplate = allSelectedTemplateIds.length === 1
  1649. if (isSingleTemplate && allSelectedTemplateIds[0]) {
  1650. const selectedTemplate = this.templateList.find(
  1651. (item) => item.pkVal === allSelectedTemplateIds[0]
  1652. )
  1653. const templateNameYw = selectedTemplate
  1654. ? selectedTemplate.surveyTemplateNameYw ||
  1655. selectedTemplate.surveyTemplateName ||
  1656. ''
  1657. : ''
  1658. let selectedItems = []
  1659. if (allSelectedTemplateIds[0] === this.selectedTemplateId) {
  1660. selectedItems = newVal
  1661. } else {
  1662. selectedItems = this.selectedIndicatorsPerTemplate[
  1663. allSelectedTemplateIds[0]
  1664. ]
  1665. .filter((item) => item.checked)
  1666. .map(
  1667. (item) => `${templateNameYw}.${item.code || item.cellCode}`
  1668. )
  1669. }
  1670. if (selectedItems.length > 0) {
  1671. this.formulaText = selectedItems.join('+')
  1672. this.isAutoGeneratedFormula = true
  1673. } else if (this.isAutoGeneratedFormula) {
  1674. this.formulaText = ''
  1675. }
  1676. } else {
  1677. let allSelectedCodes = []
  1678. if (newVal.length > 0 && this.selectedTemplateId) {
  1679. allSelectedCodes = [...newVal]
  1680. }
  1681. Object.keys(this.selectedIndicatorsPerTemplate).forEach(
  1682. (templateId) => {
  1683. if (templateId !== this.selectedTemplateId) {
  1684. const items = this.selectedIndicatorsPerTemplate[templateId]
  1685. const selectedTemplate = this.templateList.find(
  1686. (item) => item.pkVal === templateId
  1687. )
  1688. const templateName = selectedTemplate
  1689. ? selectedTemplate.surveyTemplateNameYw ||
  1690. selectedTemplate.surveyTemplateName ||
  1691. ''
  1692. : ''
  1693. items
  1694. .filter((item) => item.checked)
  1695. .forEach((item) => {
  1696. allSelectedCodes.push(
  1697. `${templateName}.${item.code || item.cellCode}`
  1698. )
  1699. })
  1700. }
  1701. }
  1702. )
  1703. if (allSelectedCodes.length > 0) {
  1704. this.formulaText = allSelectedCodes.join('+')
  1705. this.isAutoGeneratedFormula = true
  1706. } else if (this.isAutoGeneratedFormula) {
  1707. this.formulaText = ''
  1708. }
  1709. }
  1710. } else if (newVal.length > 0 && this.radioType === 'current') {
  1711. if (
  1712. !this.formulaText ||
  1713. this.formulaText === 'C1+C2+C3' ||
  1714. this.isAutoGeneratedFormula
  1715. ) {
  1716. this.formulaText = newVal.join('+')
  1717. this.isAutoGeneratedFormula = true
  1718. }
  1719. } else if (newVal.length === 0 && this.radioType === 'current') {
  1720. if (this.isAutoGeneratedFormula) {
  1721. this.formulaText = ''
  1722. }
  1723. }
  1724. },
  1725. deep: true,
  1726. },
  1727. },
  1728. mounted() {
  1729. this.isAutoGeneratedFormula = false
  1730. },
  1731. methods: {
  1732. async loadDictTypeList() {
  1733. try {
  1734. const res = await getDictTypList()
  1735. this.dictTypeList = res || []
  1736. } catch (error) {
  1737. console.error('加载字典类型失败:', error)
  1738. }
  1739. },
  1740. getTemplateRow(row) {
  1741. this.currentRow = row
  1742. this.surveyTemplateId = row.surveyTemplateId
  1743. this.templateType = row.templateType
  1744. this.contentEditForm.tableName = row.surveyTemplateName
  1745. this.surveyTemplateName = row.surveyTemplateName
  1746. this.contentEditForm.templateType = row.templateType
  1747. this.handleSearch()
  1748. this.loadDictTypeList()
  1749. },
  1750. handleBack() {
  1751. this.$emit('back', 'list')
  1752. },
  1753. // 查询
  1754. handleSearch() {
  1755. this.loading = true
  1756. const params = {
  1757. surveyTemplateId: this.surveyTemplateId,
  1758. status: this.searchForm.status,
  1759. // pageNum: this.pagination.currentPage,
  1760. // pageSize: this.pagination.pageSize,
  1761. }
  1762. // 根据成本调查表ID获取所有版本数据
  1763. getCostSurveyTemplateVersionsByTemplateId(params)
  1764. .then((response) => {
  1765. this.tableData = response.value || []
  1766. this.pagination.total = response.total || 0
  1767. this.loading = false
  1768. })
  1769. .catch((error) => {
  1770. console.error('查询失败:', error)
  1771. this.loading = false
  1772. })
  1773. },
  1774. // 重置
  1775. handleReset() {
  1776. this.searchForm = {
  1777. status: '',
  1778. }
  1779. this.pagination.currentPage = 1
  1780. this.handleSearch()
  1781. },
  1782. handleRowClick(row, column, event) {
  1783. // 只有点击非 checkbox 列才触发
  1784. if (column && column.property !== 'checked') {
  1785. // 如果没有 cellCode,则不允许选中
  1786. if (!row.cellCode) {
  1787. // this.$message.warning('该数据没有指标编号,无法选择')
  1788. return
  1789. }
  1790. // 切换选中状态
  1791. this.toggleRowSelection(row)
  1792. }
  1793. },
  1794. toggleRowSelection(row) {
  1795. // 切换选中状态
  1796. this.$set(row, 'checked', !row.checked)
  1797. // 格式化代码并存储在行数据中
  1798. if (row.checked) {
  1799. this.formatRowCode(row)
  1800. }
  1801. // 触发选中状态更新
  1802. this.$forceUpdate()
  1803. },
  1804. handleCheckboxChange(row) {
  1805. // 如果没有 cellCode,则不允许选中
  1806. if (!row.cellCode) {
  1807. this.$message.warning('该数据没有指标编号,无法选择')
  1808. this.$set(row, 'checked', false)
  1809. return
  1810. }
  1811. this.$set(row, 'checked', !row.checked)
  1812. if (row.checked) {
  1813. this.formatRowCode(row)
  1814. }
  1815. this.updateSelectedIndicatorCodes()
  1816. this.$forceUpdate()
  1817. },
  1818. updateSelectedIndicatorCodes() {
  1819. // 获取当前选中的行
  1820. const selectedRows = this.indicatorTableData.filter(
  1821. (item) => item.checked
  1822. )
  1823. // 更新选中的指标代码列表
  1824. this.selectedIndicatorCodes = selectedRows.map((item) => {
  1825. // 获取选中的模板信息
  1826. const selectedTemplate = this.templateList.find(
  1827. (template) => template.pkVal === this.selectedTemplateId
  1828. )
  1829. // 获取模板的 surveyTemplateNameYw
  1830. const templateName = selectedTemplate
  1831. ? selectedTemplate.surveyTemplateNameYw ||
  1832. selectedTemplate.surveyTemplateName ||
  1833. ''
  1834. : ''
  1835. return templateName
  1836. ? `${templateName}.${item.code || item.cellCode || ''}`
  1837. : item.code || item.cellCode || ''
  1838. })
  1839. },
  1840. formatRowCode(row) {
  1841. const selectedTemplate = this.templateList.find(
  1842. (item) => item.pkVal === this.selectedTemplateId
  1843. )
  1844. const surveyTemplateNameYw = selectedTemplate
  1845. ? selectedTemplate.surveyTemplateNameYw ||
  1846. selectedTemplate.surveyTemplateName ||
  1847. ''
  1848. : ''
  1849. const formattedCode = surveyTemplateNameYw
  1850. ? `${surveyTemplateNameYw}.${row.code || row.cellCode || ''}`
  1851. : row.code || row.cellCode || ''
  1852. this.$set(row, 'formattedCode', formattedCode)
  1853. const templateCode = surveyTemplateNameYw
  1854. ? `${surveyTemplateNameYw}_${row.code || row.cellCode || ''}`
  1855. : row.code || row.cellCode || ''
  1856. this.$set(
  1857. row,
  1858. 'jsonStr',
  1859. JSON.stringify([
  1860. {
  1861. [templateCode]: this.selectedTemplateId,
  1862. },
  1863. ])
  1864. )
  1865. },
  1866. openCalculationFormulaDialogVisible(row, index) {
  1867. this.currentEditingRow = row
  1868. this.currentEditingRowIndex = index
  1869. this.calculationFormulaDialogVisible = true
  1870. this.formulaText = row.calculationFormula || ''
  1871. this.selectedTemplateId = '' // 重置选中的模板
  1872. this.indicatorTableData = [] // 清空指标数据
  1873. this.getListFixedEnabled()
  1874. },
  1875. getListFixedEnabled() {
  1876. // 修改为调用状态为现行的数据
  1877. const params = {
  1878. surveyTemplateId: this.surveyTemplateId,
  1879. status: '0',
  1880. // pageNum: this.pagination.currentPage,
  1881. // pageSize: this.pagination.pageSize,
  1882. }
  1883. // 根据成本调查表ID获取所有版本数据
  1884. getCostSurveyTemplateVersionsByTemplateId(params)
  1885. .then((response) => {
  1886. this.templateList = response.value || []
  1887. })
  1888. .catch((error) => {
  1889. console.error('查询失败:', error)
  1890. })
  1891. // getListFixedEnabled().then((res) => {
  1892. // this.templateList = res.value
  1893. // })
  1894. },
  1895. // 处理模板选择变化
  1896. handleTemplateChange(templateId) {
  1897. if (templateId) {
  1898. // 根据选中的模板ID查找对应的surveyTemplateId
  1899. const selectedTemplate = this.templateList.find(
  1900. (item) => item.pkVal === templateId
  1901. )
  1902. if (selectedTemplate && selectedTemplate.surveyTemplateId) {
  1903. // this.getCellCodesByTemplateId(selectedTemplate.surveyTemplateId)
  1904. listByCurrentTemplateId({
  1905. surveyTemplateId: selectedTemplate.surveyTemplateId,
  1906. }).then((responseData) => {
  1907. //解析并显示数据
  1908. if (responseData.value && responseData.value.itemlist) {
  1909. const itemList = responseData.value.itemlist
  1910. let fixedTablesTitle = this.stringToObjects(
  1911. responseData.value.fixedFields || ''
  1912. )
  1913. this.indicatorTableHeaders = fixedTablesTitle
  1914. // 遍历itemList,为每个项目创建一行数据
  1915. itemList.forEach((item, index) => {
  1916. const newRow = {
  1917. ...item,
  1918. checked: false,
  1919. cellCode: item.cellCode || '',
  1920. fixedValues: {},
  1921. }
  1922. // 初始化fixedValues并填充实际值
  1923. fixedTablesTitle.forEach((title) => {
  1924. newRow.fixedValues[title.rkey] = item[title.rkey] || ''
  1925. })
  1926. this.indicatorTableData.push(newRow)
  1927. })
  1928. }
  1929. })
  1930. } else {
  1931. this.indicatorTableData = []
  1932. }
  1933. } else {
  1934. this.indicatorTableData = []
  1935. }
  1936. // 恢复该模板之前选中的指标项
  1937. this.$nextTick(() => {
  1938. if (this.selectedIndicatorsPerTemplate[templateId]) {
  1939. this.indicatorTableData.forEach((item) => {
  1940. const isSelected = this.selectedIndicatorsPerTemplate[
  1941. templateId
  1942. ].some((selectedItem) => selectedItem.code === item.code)
  1943. this.$set(item, 'checked', isSelected)
  1944. if (isSelected) {
  1945. this.formatRowCode(item)
  1946. }
  1947. })
  1948. }
  1949. // 更新选中的指标代码列表
  1950. this.updateSelectedIndicatorCodes()
  1951. })
  1952. },
  1953. handleDialogClose(done) {
  1954. this.selectedIndicatorsPerTemplate = {}
  1955. done()
  1956. },
  1957. handleRadioChange(value) {
  1958. this.formulaText = ''
  1959. },
  1960. handleConfirm() {
  1961. const result = {
  1962. type: this.radioType,
  1963. formula: this.formulaText,
  1964. selectedTemplate: this.selectedTemplateId,
  1965. selectedItems: this.indicatorTableData.filter((item) => item.checked),
  1966. }
  1967. const validation = this.validateFormula(this.formulaText)
  1968. if (!validation.valid) {
  1969. this.$message.error(validation.errorMsg)
  1970. return
  1971. }
  1972. let _data = []
  1973. if (this.radioType == 'current') {
  1974. _data = this.contentEditForm.fixedTable.fixedTables
  1975. .filter((item) => item.cellCode)
  1976. .map((item) => item.cellCode)
  1977. } else if (this.radioType == 'other') {
  1978. _data = this.indicatorTableData
  1979. .filter((item) => item.cellCode)
  1980. .map((item) => item.cellCode)
  1981. }
  1982. if (!this.validateFormula(this.formulaText, _data).valid) {
  1983. this.$message.error(
  1984. this.validateFormula(this.formulaText, _data).errorMsg
  1985. )
  1986. return
  1987. }
  1988. // 生成 jsonstr 字段
  1989. const jsonStrArray = this.indicatorTableData
  1990. .filter((item) => item.checked)
  1991. .map((item) => {
  1992. if (item.jsonStr) {
  1993. try {
  1994. return JSON.parse(item.jsonStr)[0]
  1995. } catch (e) {
  1996. console.error('解析 jsonStr 失败:', e)
  1997. return {}
  1998. }
  1999. }
  2000. return {}
  2001. })
  2002. .filter((item) => Object.keys(item).length > 0)
  2003. const jsonstr = JSON.stringify(jsonStrArray)
  2004. // 更新当前编辑行的计算公式值
  2005. if (this.currentEditingRow) {
  2006. this.$set(
  2007. this.currentEditingRow,
  2008. 'calculationFormula',
  2009. this.formulaText
  2010. )
  2011. this.$set(this.currentEditingRow, 'jsonstr', jsonstr)
  2012. }
  2013. console.log('点击了确定,获取到的数据:', {
  2014. ...result,
  2015. jsonstr: jsonstr,
  2016. })
  2017. // 清空当前操作的状态
  2018. this.calculationFormulaDialogVisible = false
  2019. this.currentEditingRow = null
  2020. this.currentEditingRowIndex = -1
  2021. this.isAutoGeneratedFormula = false
  2022. this.selectedTemplateId = ''
  2023. this.indicatorTableData = []
  2024. this.selectedIndicatorsPerTemplate = {} // 清空模板选中记录
  2025. },
  2026. // 获取单元格代码
  2027. getCellCodesByTemplateId(surveyTemplateId) {
  2028. getCellCodesByTemplateId(surveyTemplateId)
  2029. .then((res) => {
  2030. // 将返回的数据转换为表格需要的格式
  2031. if (res.value && Array.isArray(res.value)) {
  2032. this.indicatorTableData = res.value.map((item) => ({
  2033. ...item,
  2034. checked: false,
  2035. code: item.cellCode || '',
  2036. name: item.rvalue || '',
  2037. formattedCode: '', // 添加格式化代码字段
  2038. }))
  2039. } else {
  2040. this.indicatorTableData = []
  2041. }
  2042. })
  2043. .catch((error) => {
  2044. console.error('获取指标数据失败:', error)
  2045. this.$message.error('获取指标数据失败')
  2046. this.indicatorTableData = []
  2047. })
  2048. },
  2049. handleFormulaTextChange(value) {
  2050. // 当用户手动修改公式文本时,标记为非自动生成
  2051. this.isAutoGeneratedFormula = false
  2052. },
  2053. handleAdd() {
  2054. this.dialogTitle = '添加'
  2055. // 获取当前时间
  2056. const now = new Date()
  2057. // 格式化时间为YYYY-MM-DD HH:mm:ss
  2058. const formattedDate = `${now.getFullYear()}-${String(
  2059. now.getMonth() + 1
  2060. ).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(
  2061. now.getHours()
  2062. ).padStart(2, '0')}:${String(now.getMinutes()).padStart(
  2063. 2,
  2064. '0'
  2065. )}:${String(now.getSeconds()).padStart(2, '0')}`
  2066. this.dataForm = {
  2067. id: null,
  2068. version: '',
  2069. status: '',
  2070. createBy: this.username,
  2071. createTime: formattedDate,
  2072. remarks: '',
  2073. }
  2074. this.dialogVisible = true
  2075. },
  2076. // 修改
  2077. handleEdit(row) {
  2078. this.dialogTitle = '修改'
  2079. this.dataForm = { ...row }
  2080. this.dialogVisible = true
  2081. },
  2082. //状态格式化
  2083. forStatus(status) {
  2084. return status === '-1' ? '草稿' : status === '0' ? '现行' : '历史'
  2085. },
  2086. // 查看详情
  2087. handleViewDetail(row) {
  2088. this.viewDetail = true
  2089. this.detailForm = { ...row }
  2090. // this.detailDialogVisible = true
  2091. this.handleEditContent(row, this.viewDetail)
  2092. },
  2093. // 添加子项方法
  2094. handleAddChildItem(index, type, parentRow) {
  2095. if (!parentRow.rowid) {
  2096. this.$set(parentRow, 'rowid', this.generateUUID())
  2097. }
  2098. switch (type) {
  2099. case '固定表项目':
  2100. let childOrderNum =
  2101. this.contentEditForm.fixedTable.fixedTables.length + 1
  2102. const fixedNewRow = {
  2103. orderText: childOrderNum,
  2104. orderNum: childOrderNum,
  2105. cellCode: '',
  2106. calculationFormula: '',
  2107. unit: '',
  2108. tabtype: this.templateType,
  2109. surveyTemplateId: this.surveyTemplateId,
  2110. versionId: this.versionId,
  2111. fixedValues: { ...parentRow.fixedValues },
  2112. parentid: parentRow.rowid,
  2113. isChild: true,
  2114. isSubItem: true,
  2115. rowid: this.generateUUID(),
  2116. }
  2117. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  2118. (title) => {
  2119. if (!(title.rkey in fixedNewRow.fixedValues)) {
  2120. fixedNewRow.fixedValues[title.rkey] = ''
  2121. }
  2122. }
  2123. )
  2124. this.contentEditForm.fixedTable.fixedTables.splice(
  2125. index + 1,
  2126. 0,
  2127. fixedNewRow
  2128. )
  2129. break
  2130. case '动态表项目':
  2131. let dynamicChildOrderNum =
  2132. this.contentEditForm.dynamicTable.dynamicTables.length + 1
  2133. const dynamicNewRow = {
  2134. orderText: dynamicChildOrderNum,
  2135. orderNum: dynamicChildOrderNum,
  2136. tabtype: this.templateType,
  2137. surveyTemplateId: this.surveyTemplateId,
  2138. versionId: this.versionId,
  2139. dynamicValues: { ...parentRow.dynamicValues },
  2140. parentid: parentRow.rowid,
  2141. isChild: true,
  2142. isSubItem: true,
  2143. rowid: Date.now() + Math.random() + 1,
  2144. }
  2145. this.contentEditForm.dynamicTable.dynamicTablesTitle.forEach(
  2146. (title) => {
  2147. if (!(title.rkey in dynamicNewRow.dynamicValues)) {
  2148. dynamicNewRow.dynamicValues[title.rkey] = ''
  2149. }
  2150. }
  2151. )
  2152. this.contentEditForm.dynamicTable.dynamicTables.splice(
  2153. index + 1,
  2154. 0,
  2155. dynamicNewRow
  2156. )
  2157. break
  2158. }
  2159. this.$nextTick(() => {
  2160. const tableBody = document.querySelector('.el-table__body-wrapper')
  2161. if (tableBody) {
  2162. tableBody.scrollTop = tableBody.scrollHeight
  2163. }
  2164. })
  2165. },
  2166. handleFormStyleChange() {},
  2167. getListBySurveyTemplateIdAndVersion(surveyTemplateId, versionId) {
  2168. return getListBySurveyTemplateIdAndVersion({
  2169. surveyTemplateId: surveyTemplateId,
  2170. versionId: versionId,
  2171. })
  2172. .then((res) => {
  2173. // 确保表头数据包含所有必要的字段,包括 id
  2174. this.contentEditForm.tableHeaders =
  2175. res.value.map((item) => ({
  2176. ...item,
  2177. fieldKey: item.fieldEname
  2178. ? item.fieldEname.toLowerCase()
  2179. : `field_${Date.now()}_${Math.random()
  2180. .toString(36)
  2181. .substr(2, 9)}`,
  2182. })) || []
  2183. // 检查并添加序号字段(固定表和动态表需要)
  2184. if (['2', '3'].includes(this.contentEditForm.templateType)) {
  2185. const hasSerialNumber = this.contentEditForm.tableHeaders.some(
  2186. (item) => item.fieldName === '序号'
  2187. )
  2188. if (!hasSerialNumber) {
  2189. this.contentEditForm.tableHeaders.unshift({
  2190. fieldName: '序号',
  2191. fieldType: 'string',
  2192. format: '255',
  2193. fieldTypelen: '',
  2194. fieldTypenointlen: '',
  2195. isRequired: 'false',
  2196. showVisible: '1',
  2197. isAuditPeriod: 'false',
  2198. tabtype: this.templateType,
  2199. surveyTemplateId: this.surveyTemplateId,
  2200. versionId: this.versionId,
  2201. isDisabled: true,
  2202. orderNum: 1,
  2203. })
  2204. } else {
  2205. // 如果已存在序号字段,确保其不可编辑
  2206. const serialNumberIndex =
  2207. this.contentEditForm.tableHeaders.findIndex(
  2208. (item) => item.fieldName === '序号'
  2209. )
  2210. if (serialNumberIndex !== -1) {
  2211. this.contentEditForm.tableHeaders[
  2212. serialNumberIndex
  2213. ].isDisabled = true
  2214. }
  2215. }
  2216. }
  2217. this.contentEditForm.dynamicTable.tableHeaders =
  2218. this.contentEditForm.tableHeaders
  2219. this.contentEditForm.fixedTable.tableHeaders =
  2220. this.contentEditForm.tableHeaders
  2221. // 确保加载后的表头按正确顺序显示
  2222. this.updateTableHeadersOrderNumbers()
  2223. // 同时获取表头标题信息
  2224. listByTemplateIdAndVersion(surveyTemplateId, versionId)
  2225. .then((response) => {
  2226. if (response.code === 200) {
  2227. if (this.contentEditForm.templateType === '2') {
  2228. this.contentEditForm.fixedTable.fixedTablesTitle =
  2229. this.stringToObjects(response.value.fixedFields || '')
  2230. } else if (this.contentEditForm.templateType === '3') {
  2231. this.contentEditForm.dynamicTable.dynamicTablesTitle =
  2232. this.stringToObjects(response.value.fixedFields || '')
  2233. }
  2234. }
  2235. return response
  2236. })
  2237. .catch((error) => {
  2238. console.error('获取表头标题信息失败:', error)
  2239. throw error
  2240. })
  2241. })
  2242. .catch((error) => {
  2243. console.error('查询失败:', error)
  2244. this.loading = false
  2245. throw error
  2246. })
  2247. },
  2248. initFixedTableRow(row) {
  2249. if (row.cellCode === undefined) {
  2250. this.$set(row, 'cellCode', '')
  2251. }
  2252. if (row.calculationFormula === undefined) {
  2253. this.$set(row, 'calculationFormula', '')
  2254. }
  2255. if (row.unit === undefined) {
  2256. this.$set(row, 'unit', '')
  2257. }
  2258. if (!row.fixedValues) {
  2259. this.$set(row, 'fixedValues', {})
  2260. }
  2261. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  2262. (title, index) => {
  2263. if (!(title.rkey in row.fixedValues)) {
  2264. this.$set(row.fixedValues, title.rkey, '')
  2265. }
  2266. }
  2267. )
  2268. return row
  2269. },
  2270. initDynamicTableRow(row) {
  2271. // 为当前行创建一个与 dynamicTablesTitle 对应的值对象
  2272. if (!row.dynamicValues) {
  2273. this.$set(row, 'dynamicValues', {})
  2274. }
  2275. // 确保每个动态列在当前行都有对应的值
  2276. this.contentEditForm.dynamicTable.dynamicTablesTitle.forEach(
  2277. (title) => {
  2278. if (!(title.rkey in row.dynamicValues)) {
  2279. this.$set(row.dynamicValues, title.rkey, '')
  2280. }
  2281. }
  2282. )
  2283. return row
  2284. },
  2285. /**
  2286. * 处理固定表项目字段值变化
  2287. */
  2288. handleFixedValueChange(row, rkey, value) {
  2289. if (!row.fixedValues) {
  2290. this.$set(row, 'fixedValues', {})
  2291. }
  2292. this.$set(row.fixedValues, rkey, value)
  2293. },
  2294. // 获取或设置序号字段
  2295. getOrSetOrder(row, value) {
  2296. // 如果提供了value参数,则设置值
  2297. if (value !== undefined) {
  2298. // 使用this.$set确保响应式更新
  2299. if (row['序号'] === undefined) {
  2300. this.$set(row, '序号', value)
  2301. } else {
  2302. row['序号'] = value
  2303. }
  2304. }
  2305. // 如果没有提供value参数,则获取值
  2306. return row['序号'] !== undefined && row['序号'] !== null
  2307. ? row['序号']
  2308. : row.orderNum || ''
  2309. },
  2310. /**
  2311. * 处理动态表项目字段值变化
  2312. */
  2313. handleDynamicValueChange(row, rkey, value) {
  2314. if (!row.dynamicValues) {
  2315. this.$set(row, 'dynamicValues', {})
  2316. }
  2317. this.$set(row.dynamicValues, rkey, value)
  2318. },
  2319. // 内容维护
  2320. handleEditContent(row, viewDetail) {
  2321. this.viewDetail = viewDetail || false
  2322. this.versionId = row.id
  2323. // 显示加载状态
  2324. this.loading = true
  2325. // 获取所有需要的数据
  2326. this.getListBySurveyTemplateIdAndVersion(row.surveyTemplateId, row.id)
  2327. .then(() => {
  2328. // 获取项目数据用于回显
  2329. return listByTemplateIdAndVersion(row.surveyTemplateId, row.id)
  2330. })
  2331. .then((res) => {
  2332. if (res.code === 200) {
  2333. // 根据模板类型解析并显示数据
  2334. if (this.contentEditForm.templateType === '2') {
  2335. // 解析并显示固定表项目数据
  2336. setTimeout(() => {
  2337. this.parseAndDisplayFixedTableData(res)
  2338. }, 1000)
  2339. } else if (this.contentEditForm.templateType === '3') {
  2340. // 解析并显示动态表项目数据
  2341. setTimeout(() => {
  2342. this.parseAndDisplayDynamicTableData(res)
  2343. }, 1000)
  2344. }
  2345. }
  2346. this.loading = false
  2347. this.contentEditDialogVisible = true
  2348. })
  2349. .catch((error) => {
  2350. console.error('获取数据失败:', error)
  2351. this.$message.error('获取数据失败')
  2352. this.contentEditDialogVisible = true
  2353. this.loading = false
  2354. })
  2355. },
  2356. // 字段类型变化处理
  2357. handleFieldTypeChange(row) {
  2358. // 重置格式相关字段
  2359. row.format = ''
  2360. row.integerDigits = ''
  2361. row.decimalDigits = ''
  2362. },
  2363. // 添加表头
  2364. handleAddTableHeader(type) {
  2365. switch (type) {
  2366. case '单记录':
  2367. this.contentEditForm.tableHeaders.push({
  2368. fieldName: '',
  2369. fieldType: 'string',
  2370. format: '255',
  2371. fieldTypelen: '',
  2372. fieldTypenointlen: '',
  2373. isRequired: 'false',
  2374. showVisible: '1',
  2375. isDict: 'false',
  2376. dictid: '',
  2377. dictValue: '',
  2378. tabtype: this.templateType,
  2379. surveyTemplateId: this.surveyTemplateId,
  2380. versionId: this.versionId,
  2381. })
  2382. break
  2383. case '固定表表头':
  2384. this.contentEditForm.fixedTable.tableHeaders.push({
  2385. fieldName: '',
  2386. fieldType: 'string',
  2387. format: '255',
  2388. fieldTypelen: '',
  2389. fieldTypenointlen: '',
  2390. isRequired: 'false',
  2391. showVisible: '1',
  2392. isAuditPeriod: 'false',
  2393. tabtype: this.templateType,
  2394. surveyTemplateId: this.surveyTemplateId,
  2395. versionId: this.versionId,
  2396. orderNum: this.contentEditForm.fixedTable.tableHeaders.length + 1,
  2397. })
  2398. // 确保添加后顺序正确
  2399. this.updateTableHeadersOrderNumbers()
  2400. break
  2401. case '固定表项目':
  2402. let maxFixedOrderNum = 0
  2403. if (this.contentEditForm.fixedTable.fixedTables.length > 0) {
  2404. maxFixedOrderNum = Math.max(
  2405. ...this.contentEditForm.fixedTable.fixedTables.map(
  2406. (item) => item.orderNum || 0
  2407. )
  2408. )
  2409. }
  2410. const newRow = {
  2411. orderText: maxFixedOrderNum + 1,
  2412. orderNum: maxFixedOrderNum + 1,
  2413. cellCode: '',
  2414. calculationFormula: '',
  2415. unit: '',
  2416. tabtype: this.templateType,
  2417. surveyTemplateId: this.surveyTemplateId,
  2418. versionId: this.versionId,
  2419. fixedValues: {},
  2420. parentid: -1,
  2421. rowid: this.generateUUID(),
  2422. }
  2423. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  2424. (title) => {
  2425. newRow.fixedValues[title.rkey] = ''
  2426. }
  2427. )
  2428. this.contentEditForm.fixedTable.fixedTables.push(newRow)
  2429. break
  2430. case '动态表表头':
  2431. this.contentEditForm.dynamicTable.tableHeaders.push({
  2432. fieldName: '',
  2433. fieldType: 'string',
  2434. format: '255',
  2435. fieldTypelen: '',
  2436. fieldTypenointlen: '',
  2437. isRequired: 'false',
  2438. showVisible: '1',
  2439. tabtype: this.templateType,
  2440. surveyTemplateId: this.surveyTemplateId,
  2441. versionId: this.versionId,
  2442. orderNum:
  2443. this.contentEditForm.dynamicTable.tableHeaders.length + 1,
  2444. })
  2445. break
  2446. case '动态表项目':
  2447. let maxDynamicOrderNum = 0
  2448. if (this.contentEditForm.dynamicTable.dynamicTables.length > 0) {
  2449. maxDynamicOrderNum = Math.max(
  2450. ...this.contentEditForm.dynamicTable.dynamicTables.map(
  2451. (item) => item.orderNum || 0
  2452. )
  2453. )
  2454. }
  2455. const dynamicRow = {
  2456. orderText: maxDynamicOrderNum + 1,
  2457. orderNum: maxDynamicOrderNum + 1,
  2458. tabtype: this.templateType,
  2459. surveyTemplateId: this.surveyTemplateId,
  2460. versionId: this.versionId,
  2461. dynamicValues: {},
  2462. parentid: -1,
  2463. rowid: this.generateUUID(),
  2464. }
  2465. this.contentEditForm.dynamicTable.dynamicTablesTitle.forEach(
  2466. (title) => {
  2467. dynamicRow.dynamicValues[title.rkey] = ''
  2468. }
  2469. )
  2470. this.contentEditForm.dynamicTable.dynamicTables.push(dynamicRow)
  2471. break
  2472. default:
  2473. break
  2474. }
  2475. this.$nextTick(() => {
  2476. const tableBody = document.querySelector('.el-table__body-wrapper')
  2477. if (tableBody) {
  2478. tableBody.scrollTop = tableBody.scrollHeight
  2479. }
  2480. })
  2481. },
  2482. // 删除表头
  2483. handleDeleteHeader(index, type, row) {
  2484. // 提取重复的删除逻辑为内部函数
  2485. const handleDelete = () => {
  2486. const data = {
  2487. deleteheadersList: [row],
  2488. }
  2489. getBatchSaveOrUpdate(data)
  2490. .then((res) => {
  2491. if (res.code === 200) {
  2492. this.$message.success('删除成功')
  2493. } else {
  2494. this.$message.error(`删除失败:${res.message || '未知错误'}`)
  2495. }
  2496. })
  2497. .catch((error) => {
  2498. console.error('删除接口异常:', error)
  2499. this.$message.error('删除接口异常,请重试')
  2500. })
  2501. .finally(() => {})
  2502. }
  2503. switch (type) {
  2504. case '固定表表头':
  2505. if (this.contentEditForm.fixedTable.tableHeaders.length <= 1) {
  2506. this.$message.warning('至少保留一个表头')
  2507. return
  2508. }
  2509. this.contentEditForm.fixedTable.tableHeaders.splice(index, 1)
  2510. let fixedFields = this.contentEditForm.fixedTable.tableHeaders
  2511. .map((item) => item.fieldName)
  2512. .join(',')
  2513. this.contentEditForm.fixedTable.fixedTablesTitle =
  2514. this.stringToObjects(fixedFields || '')
  2515. this.contentEditForm.fixedTable.fixedTableHeaders =
  2516. this.contentEditForm.fixedTable.fixedTablesTitle.filter(
  2517. (title) => title.rkey !== '序号'
  2518. )
  2519. // 重新排序
  2520. this.updateTableHeadersOrderNumbers()
  2521. handleDelete()
  2522. break
  2523. case '固定表项目':
  2524. if (this.contentEditForm.fixedTable.fixedTables.length <= 1) {
  2525. this.$message.warning('至少保留一个项目')
  2526. return
  2527. }
  2528. this.contentEditForm.fixedTable.fixedTables.splice(index, 1)
  2529. handleDelete() // 执行删除逻辑
  2530. break
  2531. case '动态表表头':
  2532. if (this.contentEditForm.dynamicTable.tableHeaders.length <= 1) {
  2533. this.$message.warning('至少保留一个表头')
  2534. return
  2535. }
  2536. this.contentEditForm.dynamicTable.tableHeaders.splice(index, 1)
  2537. let dynamicFields = this.contentEditForm.dynamicTable.tableHeaders
  2538. .map((item) => item.fieldName)
  2539. .join(',')
  2540. this.contentEditForm.dynamicTable.dynamicTablesTitle =
  2541. this.stringToObjects(dynamicFields || '')
  2542. this.contentEditForm.dynamicTable.dynamicTableHeaders =
  2543. this.contentEditForm.dynamicTable.dynamicTablesTitle.filter(
  2544. (title) => title.rkey !== '序号'
  2545. )
  2546. // 重新排序
  2547. this.updateTableHeadersOrderNumbers()
  2548. handleDelete() // 执行删除逻辑
  2549. break
  2550. case '动态表项目':
  2551. if (this.contentEditForm.dynamicTable.dynamicTables.length <= 1) {
  2552. this.$message.warning('至少保留一个项目')
  2553. return
  2554. }
  2555. this.contentEditForm.dynamicTable.dynamicTables.splice(index, 1)
  2556. handleDelete() // 执行删除逻辑
  2557. break
  2558. case '单记录':
  2559. if (this.contentEditForm.tableHeaders.length <= 1) {
  2560. this.$message.warning('至少保留一个表头')
  2561. return
  2562. }
  2563. this.contentEditForm.tableHeaders.splice(index, 1)
  2564. handleDelete() // 执行删除逻辑
  2565. break
  2566. default:
  2567. break
  2568. }
  2569. },
  2570. // 上升
  2571. handleMoveUp(index, tableType) {
  2572. if (tableType === '固定表') {
  2573. if (index > 0) {
  2574. const temp = this.contentEditForm.fixedTable.fixedTables[index]
  2575. this.contentEditForm.fixedTable.fixedTables.splice(index, 1)
  2576. this.contentEditForm.fixedTable.fixedTables.splice(
  2577. index - 1,
  2578. 0,
  2579. temp
  2580. )
  2581. // 更新固定表行的序号
  2582. this.updateFixedTableOrderNumbers()
  2583. }
  2584. } else if (tableType === '动态表') {
  2585. if (index > 0) {
  2586. const temp = this.contentEditForm.dynamicTable.dynamicTables[index]
  2587. this.contentEditForm.dynamicTable.dynamicTables.splice(index, 1)
  2588. this.contentEditForm.dynamicTable.dynamicTables.splice(
  2589. index - 1,
  2590. 0,
  2591. temp
  2592. )
  2593. // 更新动态表行的序号
  2594. this.updateDynamicTableOrderNumbers()
  2595. }
  2596. } else {
  2597. if (index > 0) {
  2598. const temp = this.contentEditForm.tableHeaders[index]
  2599. this.contentEditForm.tableHeaders.splice(index, 1)
  2600. this.contentEditForm.tableHeaders.splice(index - 1, 0, temp)
  2601. // 更新表头的序号
  2602. this.updateTableHeadersOrderNumbers()
  2603. }
  2604. }
  2605. },
  2606. // 启动/停用状态
  2607. handleStatus(row) {
  2608. const action = row.status === '启用' ? '停用' : '启用'
  2609. if (row.status === '0') {
  2610. this.$confirm(`确认要停用该数据吗?`, '操作确认', {
  2611. confirmButtonText: '确定',
  2612. cancelButtonText: '取消',
  2613. type: 'warning',
  2614. })
  2615. .then(() => {
  2616. row.status = '-1'
  2617. putSurveyTemplatePublishVersion(row).then((res) => {
  2618. if (res.code === 200) {
  2619. this.$message.success(`停用成功`)
  2620. this.handleSearch()
  2621. }
  2622. })
  2623. })
  2624. .catch(() => {
  2625. this.$message({
  2626. type: 'info',
  2627. message: '已取消操作',
  2628. })
  2629. })
  2630. } else if (row.status === '-1') {
  2631. this.$confirm(`确认要启用该数据吗?`, '操作确认', {
  2632. confirmButtonText: '确定',
  2633. cancelButtonText: '取消',
  2634. type: 'warning',
  2635. })
  2636. .then(() => {
  2637. row.status = '0'
  2638. putSurveyTemplatePublishVersion(row).then((res) => {
  2639. if (res.code === 200) {
  2640. this.$message.success(`停用成功`)
  2641. this.handleSearch()
  2642. }
  2643. })
  2644. })
  2645. .catch(() => {
  2646. this.$message({
  2647. type: 'info',
  2648. message: '已取消操作',
  2649. })
  2650. })
  2651. }
  2652. },
  2653. // 下降
  2654. handleMoveDown(index, tableType) {
  2655. if (tableType === '固定表') {
  2656. if (index < this.contentEditForm.fixedTable.fixedTables.length - 1) {
  2657. const temp = this.contentEditForm.fixedTable.fixedTables[index]
  2658. this.contentEditForm.fixedTable.fixedTables.splice(index, 1)
  2659. this.contentEditForm.fixedTable.fixedTables.splice(
  2660. index + 1,
  2661. 0,
  2662. temp
  2663. )
  2664. // 更新固定表行的序号
  2665. this.updateFixedTableOrderNumbers()
  2666. }
  2667. } else if (tableType === '动态表') {
  2668. if (
  2669. index <
  2670. this.contentEditForm.dynamicTable.dynamicTables.length - 1
  2671. ) {
  2672. const temp = this.contentEditForm.dynamicTable.dynamicTables[index]
  2673. this.contentEditForm.dynamicTable.dynamicTables.splice(index, 1)
  2674. this.contentEditForm.dynamicTable.dynamicTables.splice(
  2675. index + 1,
  2676. 0,
  2677. temp
  2678. )
  2679. // 更新动态表行的序号
  2680. this.updateDynamicTableOrderNumbers()
  2681. }
  2682. } else {
  2683. if (index < this.contentEditForm.tableHeaders.length - 1) {
  2684. const temp = this.contentEditForm.tableHeaders[index]
  2685. this.contentEditForm.tableHeaders.splice(index, 1)
  2686. this.contentEditForm.tableHeaders.splice(index + 1, 0, temp)
  2687. // 更新表头的序号
  2688. this.updateTableHeadersOrderNumbers()
  2689. }
  2690. }
  2691. },
  2692. // 更新固定表行序号
  2693. updateFixedTableOrderNumbers() {
  2694. this.contentEditForm.fixedTable.fixedTables.forEach((row, index) => {
  2695. // 更新显示序号
  2696. this.$set(row, 'orderText', index + 1)
  2697. // 更新后端序号
  2698. this.$set(row, 'orderNum', index + 1)
  2699. })
  2700. },
  2701. // 更新动态表行序号
  2702. updateDynamicTableOrderNumbers() {
  2703. this.contentEditForm.dynamicTable.dynamicTables.forEach(
  2704. (row, index) => {
  2705. // 更新显示序号
  2706. this.$set(row, 'orderText', index + 1)
  2707. // 更新后端序号
  2708. this.$set(row, 'orderNum', index + 1)
  2709. }
  2710. )
  2711. },
  2712. // 更新表头序号
  2713. updateTableHeadersOrderNumbers() {
  2714. // 先按orderNum排序
  2715. this.contentEditForm.fixedTable.tableHeaders.sort((a, b) => {
  2716. // 处理序号字段(确保它始终在第一位)
  2717. if (a.fieldName === '序号') return -1
  2718. if (b.fieldName === '序号') return 1
  2719. // 按orderNum排序
  2720. const orderA = a.orderNum !== undefined ? parseInt(a.orderNum) : 0
  2721. const orderB = b.orderNum !== undefined ? parseInt(b.orderNum) : 0
  2722. return orderA - orderB
  2723. })
  2724. // 重新分配序号(从1开始)
  2725. this.contentEditForm.fixedTable.tableHeaders.forEach(
  2726. (header, index) => {
  2727. this.$set(header, 'orderNum', index + 1)
  2728. }
  2729. )
  2730. },
  2731. // 绑定字典变化
  2732. handleBindDictChange(row) {
  2733. if (row.isDict === 'false') {
  2734. row.dictid = ''
  2735. }
  2736. },
  2737. // 获取格式占位符
  2738. getFormatPlaceholder(fieldType) {
  2739. switch (fieldType) {
  2740. case '日期':
  2741. return '如:yyyy-MM-dd'
  2742. case '数字':
  2743. return '如:#,##0.00'
  2744. default:
  2745. return '请输入格式'
  2746. }
  2747. },
  2748. // 滚动到错误行
  2749. scrollToErrorRow(rowIndex) {
  2750. this.$nextTick(() => {
  2751. const tableBody = document.querySelector(
  2752. '.table-edit-container .el-table__body-wrapper'
  2753. )
  2754. if (tableBody) {
  2755. const scrollTop = rowIndex * 48
  2756. tableBody.scrollTop = scrollTop
  2757. }
  2758. })
  2759. },
  2760. // 保存内容
  2761. handleSaveContent(type) {
  2762. this.loading = true
  2763. let isValid = false
  2764. try {
  2765. if (type === '单记录') {
  2766. var data = {
  2767. headersList: this.contentEditForm.tableHeaders,
  2768. }
  2769. getBatchSaveOrUpdate(data)
  2770. .then((res) => {
  2771. if (res.code === 200) {
  2772. this.$message.success('保存成功')
  2773. this.contentEditDialogVisible = false
  2774. } else {
  2775. this.$message.error(`保存失败:${res.message || '未知错误'}`)
  2776. }
  2777. })
  2778. .catch((error) => {
  2779. console.error('保存接口异常:', error)
  2780. this.$message.error('保存接口异常,请重试')
  2781. })
  2782. .finally(() => {
  2783. this.loading = false
  2784. })
  2785. } else if (type === '固定表表头') {
  2786. var data = {
  2787. headersList: this.contentEditForm.fixedTable.tableHeaders,
  2788. }
  2789. getBatchSaveOrUpdate(data)
  2790. .then((res) => {
  2791. if (res.code === 200) {
  2792. this.contentEditForm.isFixedTables = true
  2793. this.loading = true
  2794. // 如果后端返回了保存后的数据,更新本地数据
  2795. if (res.value && Array.isArray(res.value)) {
  2796. this.contentEditForm.fixedTable.tableHeaders =
  2797. res.value.map((item) => ({
  2798. ...item,
  2799. }))
  2800. // 确保保存后的数据也按正确顺序显示
  2801. this.updateTableHeadersOrderNumbers()
  2802. }
  2803. this.getListBySurveyTemplateIdAndVersion(
  2804. this.surveyTemplateId,
  2805. this.versionId
  2806. )
  2807. listByTemplateIdAndVersion(
  2808. this.surveyTemplateId,
  2809. this.versionId
  2810. )
  2811. .then((res) => {
  2812. this.loading = false
  2813. this.contentEditForm.fixedTable.fixedTablesTitle =
  2814. this.stringToObjects(res.value.fixedFields)
  2815. this.contentEditForm.fixedTable.fixedTables.forEach(
  2816. (row) => {
  2817. this.initFixedTableRow(row)
  2818. }
  2819. )
  2820. this.contentEditForm.fixedTable.fixedTableHeaders =
  2821. this.contentEditForm.fixedTable.fixedTablesTitle.filter(
  2822. (title) => title.rkey !== '序号'
  2823. )
  2824. })
  2825. .catch((error) => {
  2826. console.error('查询失败:', error)
  2827. this.loading = false
  2828. })
  2829. } else {
  2830. this.$message.error(`保存失败:${res.message || '未知错误'}`)
  2831. }
  2832. })
  2833. .catch((error) => {
  2834. console.error('保存接口异常:', error)
  2835. this.$message.error('保存接口异常,请重试')
  2836. })
  2837. .finally(() => {
  2838. this.loading = false
  2839. })
  2840. } else if (type === '固定表项目') {
  2841. this.saveFixedTableData()
  2842. } else if (type === '动态表表头') {
  2843. var data = {
  2844. headersList: this.contentEditForm.dynamicTable.tableHeaders,
  2845. }
  2846. getBatchSaveOrUpdate(data)
  2847. .then((res) => {
  2848. if (res.code === 200) {
  2849. this.contentEditForm.isDynamicTables = true
  2850. this.loading = true
  2851. // 如果后端返回了保存后的数据,更新本地数据
  2852. if (res.value && Array.isArray(res.value)) {
  2853. this.contentEditForm.dynamicTable.tableHeaders =
  2854. res.value.map((item) => ({
  2855. ...item,
  2856. fieldKey: item.fieldEname
  2857. ? item.fieldEname.toLowerCase()
  2858. : `field_${Date.now()}_${Math.random()
  2859. .toString(36)
  2860. .substr(2, 9)}`,
  2861. }))
  2862. // 确保保存后的数据也按正确顺序显示
  2863. this.updateTableHeadersOrderNumbers()
  2864. }
  2865. this.getListBySurveyTemplateIdAndVersion(
  2866. this.surveyTemplateId,
  2867. this.versionId
  2868. )
  2869. listByTemplateIdAndVersion(
  2870. this.surveyTemplateId,
  2871. this.versionId
  2872. )
  2873. .then((res) => {
  2874. this.loading = false
  2875. this.contentEditForm.dynamicTable.dynamicTablesTitle =
  2876. this.stringToObjects(res.value.fixedFields || '')
  2877. // 初始化所有已有行的 dynamicValues
  2878. this.contentEditForm.dynamicTable.dynamicTables.forEach(
  2879. (row) => {
  2880. this.initDynamicTableRow(row)
  2881. }
  2882. )
  2883. this.contentEditForm.dynamicTable.dynamicTableHeaders =
  2884. this.contentEditForm.dynamicTable.dynamicTablesTitle.filter(
  2885. (title) => title.rkey !== '序号'
  2886. )
  2887. })
  2888. .catch((error) => {
  2889. console.error('查询失败:', error)
  2890. this.loading = false
  2891. })
  2892. } else {
  2893. this.$message.error(`保存失败:${res.message || '未知错误'}`)
  2894. }
  2895. })
  2896. .catch((error) => {
  2897. console.error('保存接口异常:', error)
  2898. this.$message.error('保存接口异常,请重试')
  2899. })
  2900. .finally(() => {
  2901. this.loading = false
  2902. })
  2903. } else if (type === '动态表项目') {
  2904. this.saveDynamicTableData()
  2905. }
  2906. } catch (error) {
  2907. console.error('保存处理异常:', error)
  2908. this.$message.error('保存过程中发生错误,请重试')
  2909. this.loading = false
  2910. }
  2911. },
  2912. // 公式验证函数
  2913. validateFormula(formula, data) {
  2914. if (!formula || typeof formula !== 'string') {
  2915. return { valid: false, errorMsg: '公式不能为空' }
  2916. }
  2917. // 定义有效的操作符
  2918. const operators = ['+', '-', '*', '/', '(', ')']
  2919. // 检查是否包含至少一个操作符
  2920. const hasOperator = operators.some((operator) =>
  2921. formula.includes(operator)
  2922. )
  2923. if (!hasOperator) {
  2924. return { valid: false, errorMsg: '公式必须包含操作符' }
  2925. }
  2926. // 检查值是否在data中存在
  2927. function checkValueInData(value, data) {
  2928. if (!data) return false
  2929. if (Array.isArray(data)) {
  2930. return data.includes(value)
  2931. } else if (typeof data === 'object') {
  2932. return Object.values(data).includes(value)
  2933. }
  2934. return data === value
  2935. }
  2936. // 提取公式中的变量/值
  2937. function extractValues(formulaStr) {
  2938. // 改进实现:支持形如"CeShi3.C2"的格式,提取点后面的部分作为变量,同时保留普通变量
  2939. const result = new Set()
  2940. // 1. 首先提取带点格式中的变量部分(如CeShi3.C2中的C2)
  2941. const dotRegex = /[A-Za-z0-9]+\.([A-Za-z0-9]+)/g
  2942. let dotMatch
  2943. while ((dotMatch = dotRegex.exec(formulaStr)) !== null) {
  2944. result.add(dotMatch[1]) // 提取点后面的部分作为变量
  2945. }
  2946. // 2. 然后提取普通变量(C3等),但排除已经从带点格式中提取的部分
  2947. // 移除所有带点的部分,然后提取剩余的变量
  2948. const remainingFormula = formulaStr.replace(
  2949. /[A-Za-z0-9]+\.[A-Za-z0-9]+/g,
  2950. ''
  2951. )
  2952. const normalRegex = /[A-Za-z0-9]+/g
  2953. let normalMatch
  2954. while ((normalMatch = normalRegex.exec(remainingFormula)) !== null) {
  2955. // 跳过纯数字
  2956. if (
  2957. !isNaN(Number(normalMatch[0])) &&
  2958. Number(normalMatch[0]).toString() === normalMatch[0]
  2959. ) {
  2960. continue
  2961. }
  2962. result.add(normalMatch[0])
  2963. }
  2964. return Array.from(result)
  2965. }
  2966. function checkOperatorContext(formulaStr, data) {
  2967. for (let i = 0; i < formulaStr.length; i++) {
  2968. const char = formulaStr[i]
  2969. // 跳过括号
  2970. if (char === '(' || char === ')') continue
  2971. // 检查操作符
  2972. if (operators.includes(char)) {
  2973. // 检查操作符前是否有值(开头或不是操作符和左括号)
  2974. if (
  2975. i === 0 ||
  2976. (operators.includes(formulaStr[i - 1]) &&
  2977. formulaStr[i - 1] !== ')') ||
  2978. formulaStr[i - 1] === '('
  2979. ) {
  2980. return {
  2981. valid: false,
  2982. errorMsg: `位置 ${i + 1} 的操作符 '${char}' 前缺少值`,
  2983. }
  2984. }
  2985. // 检查操作符后是否有值(结尾或不是操作符和右括号)
  2986. if (
  2987. i === formulaStr.length - 1 ||
  2988. (operators.includes(formulaStr[i + 1]) &&
  2989. formulaStr[i + 1] !== '(') ||
  2990. formulaStr[i + 1] === ')'
  2991. ) {
  2992. return {
  2993. valid: false,
  2994. errorMsg: `位置 ${i + 1} 的操作符 '${char}' 后缺少值`,
  2995. }
  2996. }
  2997. }
  2998. }
  2999. // 验证通过后,检查公式中的值是否都在data中存在
  3000. if (data) {
  3001. const values = extractValues(formulaStr)
  3002. for (const value of values) {
  3003. // 跳过纯数字(假设有值不在data中)
  3004. if (!isNaN(Number(value)) && Number(value).toString() === value) {
  3005. continue
  3006. }
  3007. if (!checkValueInData(value, data)) {
  3008. return {
  3009. valid: false,
  3010. errorMsg: `变量 '${value}' 在数据中不存在`,
  3011. }
  3012. }
  3013. }
  3014. }
  3015. return { valid: true }
  3016. }
  3017. // 执行验证
  3018. return checkOperatorContext(formula, data)
  3019. },
  3020. /**
  3021. * 将固定表项目的数据根据固定列拆分成对应的数据结构
  3022. * @returns {Array} 拆分后的数据数组,每个固定列对应一行数据
  3023. */
  3024. splitFixedTableDataForSave() {
  3025. const fixedTables = this.contentEditForm.fixedTable.fixedTables
  3026. const fixedTitles = this.contentEditForm.fixedTable.fixedTablesTitle
  3027. const fixedHeaders = this.contentEditForm.fixedTable.tableHeaders
  3028. // 结果数组
  3029. const result = []
  3030. // 遍历每一行数据
  3031. fixedTables.forEach((row, rowIndex) => {
  3032. // 为每个固定列创建一条记录
  3033. fixedTitles.forEach((title, colIndex) => {
  3034. // 找到对应的表头信息
  3035. const correspondingHeader = fixedHeaders.find(
  3036. (header) => header.fieldName === title.rkey
  3037. )
  3038. const newItem = {
  3039. rkey: title.rkey,
  3040. rvalue: row.fixedValues ? row.fixedValues[title.rkey] || '' : '',
  3041. surveyTemplateId: row.surveyTemplateId,
  3042. versionId: row.versionId,
  3043. tabtype: row.tabtype,
  3044. rowIndex: rowIndex,
  3045. // 添加 headersId 字段(表头的id)
  3046. headersId: correspondingHeader ? correspondingHeader.id : null,
  3047. // 添加记录的id(itemlist中每条记录的id)
  3048. id: row.itemId || null,
  3049. // 添加父子关系字段
  3050. parentid: row.parentid || -1, // 父项ID,默认为-1表示无父项
  3051. isChild: row.isChild || false, // 是否为子项
  3052. // 添加 rowid 字段
  3053. rowid: row.rowid || null,
  3054. // 添加计算公式相关字段
  3055. calculationFormula: row.calculationFormula || null,
  3056. jsonstr: row.jsonstr || null,
  3057. }
  3058. // 只有非子项才添加序号
  3059. if (!row.isSubItem && row.orderNum) {
  3060. newItem.orderNum =
  3061. typeof row.orderNum === 'number'
  3062. ? row.orderNum
  3063. : parseInt(row.orderNum, 10) || 0
  3064. }
  3065. // 添加其他固定表特有的字段
  3066. if (!row.isSubItem) {
  3067. newItem.cellCode = row.cellCode || ''
  3068. newItem.unit = row.unit || ''
  3069. }
  3070. // 添加其他可能需要的字段,但排除特定字段
  3071. Object.keys(row).forEach((key) => {
  3072. if (
  3073. !(key in newItem) &&
  3074. key !== 'fixedValues' &&
  3075. key !== 'itemId' &&
  3076. key !== 'id' &&
  3077. key !== 'parentid' &&
  3078. key !== 'isChild' &&
  3079. key !== 'isSubItem' &&
  3080. key !== 'rowid' &&
  3081. key !== 'jsonstr' &&
  3082. key !== 'calculationFormula'
  3083. ) {
  3084. newItem[key] = row[key]
  3085. }
  3086. })
  3087. result.push(newItem)
  3088. })
  3089. })
  3090. return result
  3091. },
  3092. /**
  3093. * 将动态表项目的数据根据动态列拆分成对应的数据结构
  3094. * @returns {Array} 拆分后的数据数组,每个动态列对应一行数据
  3095. */
  3096. splitDynamicTableDataForSave() {
  3097. const dynamicTables = this.contentEditForm.dynamicTable.dynamicTables
  3098. const dynamicTitles =
  3099. this.contentEditForm.dynamicTable.dynamicTablesTitle
  3100. const dynamicHeaders = this.contentEditForm.dynamicTable.tableHeaders
  3101. // 结果数组
  3102. const result = []
  3103. // 遍历每一行数据
  3104. dynamicTables.forEach((row, rowIndex) => {
  3105. // 为每个固定列创建一条记录
  3106. dynamicTitles.forEach((title, colIndex) => {
  3107. // 找到对应的表头信息
  3108. const correspondingHeader = dynamicHeaders.find(
  3109. (header) => header.fieldName === title.rkey
  3110. )
  3111. const newItem = {
  3112. rkey: title.rkey,
  3113. rvalue: row.dynamicValues
  3114. ? row.dynamicValues[title.rkey] || ''
  3115. : '',
  3116. surveyTemplateId: row.surveyTemplateId,
  3117. versionId: row.versionId,
  3118. tabtype: row.tabtype,
  3119. rowIndex: rowIndex,
  3120. // 添加 headersId 字段(表头的id)
  3121. headersId: correspondingHeader ? correspondingHeader.id : null,
  3122. // 添加记录的id(itemlist中每条记录的id)
  3123. id: row.itemId || null,
  3124. // 添加父子关系字段
  3125. parentid: row.parentid || -1, // 父项ID,默认为-1表示无父项
  3126. isChild: row.isChild || false, // 是否为子项
  3127. // 添加 rowid 字段
  3128. rowid: row.rowid || null,
  3129. // 添加计算公式相关字段
  3130. calculationFormula: row.calculationFormula || null,
  3131. jsonstr: row.jsonstr || null,
  3132. }
  3133. // 只有非子项才添加序号
  3134. if (!row.isSubItem && row.orderNum) {
  3135. newItem.orderNum =
  3136. typeof row.orderNum === 'number'
  3137. ? row.orderNum
  3138. : parseInt(row.orderNum, 10) || 0
  3139. }
  3140. // 添加其他可能需要的字段,但排除特定字段
  3141. Object.keys(row).forEach((key) => {
  3142. if (
  3143. !(key in newItem) &&
  3144. key !== 'dynamicValues' &&
  3145. key !== 'itemId' &&
  3146. key !== 'id' &&
  3147. key !== 'parentid' &&
  3148. key !== 'isChild' &&
  3149. key !== 'isSubItem' &&
  3150. key !== 'rowid' &&
  3151. key !== 'jsonstr' &&
  3152. key !== 'calculationFormula'
  3153. ) {
  3154. newItem[key] = row[key]
  3155. }
  3156. })
  3157. result.push(newItem)
  3158. })
  3159. })
  3160. return result
  3161. },
  3162. //保存固定表项目数据
  3163. saveFixedTableData() {
  3164. try {
  3165. // 获取拆分后的数据
  3166. const splitData = this.splitFixedTableDataForSave()
  3167. // 构造保存数据的结构
  3168. const saveData = {
  3169. itemsList: splitData,
  3170. }
  3171. // 调用保存接口
  3172. getBatchSaveOrUpdate(saveData)
  3173. .then((res) => {
  3174. if (res.code === 200) {
  3175. this.$message.success('固定表数据保存成功')
  3176. this.contentEditDialogVisible = false
  3177. } else {
  3178. this.$message.error(`保存失败:${res.message || '未知错误'}`)
  3179. }
  3180. })
  3181. .catch((error) => {
  3182. console.error('保存固定表数据接口异常:', error)
  3183. this.$message.error('保存固定表数据失败,请重试')
  3184. })
  3185. .finally(() => {
  3186. this.loading = false
  3187. })
  3188. return splitData
  3189. } catch (error) {
  3190. console.error('处理固定表数据保存时出错:', error)
  3191. this.$message.error('保存过程中发生错误,请重试')
  3192. this.loading = false
  3193. }
  3194. },
  3195. //保存动态表项目数据
  3196. saveDynamicTableData() {
  3197. try {
  3198. // 获取拆分后的数据
  3199. const splitData = this.splitDynamicTableDataForSave()
  3200. // 构造保存数据的结构
  3201. const saveData = {
  3202. itemsList: splitData,
  3203. }
  3204. // 调用保存接口
  3205. getBatchSaveOrUpdate(saveData)
  3206. .then((res) => {
  3207. if (res.code === 200) {
  3208. this.$message.success('动态表数据保存成功')
  3209. this.contentEditDialogVisible = false
  3210. } else {
  3211. this.$message.error(`保存失败:${res.message || '未知错误'}`)
  3212. }
  3213. })
  3214. .catch((error) => {
  3215. console.error('保存动态表数据接口异常:', error)
  3216. this.$message.error('保存动态表数据失败,请重试')
  3217. })
  3218. .finally(() => {
  3219. this.loading = false
  3220. })
  3221. return splitData
  3222. } catch (error) {
  3223. console.error('处理动态表数据保存时出错:', error)
  3224. this.$message.error('保存过程中发生错误,请重试')
  3225. this.loading = false
  3226. }
  3227. },
  3228. /**
  3229. * 解析并回显固定表项目数据
  3230. * @param {Object} responseData - listByTemplateIdAndVersion接口返回的数据
  3231. */
  3232. parseAndDisplayFixedTableData(responseData) {
  3233. if (responseData.value.fixedFields) {
  3234. this.contentEditForm.fixedTable.fixedTablesTitle =
  3235. this.stringToObjects(responseData.value.fixedFields || '')
  3236. } else {
  3237. let fixedFields = this.contentEditForm.fixedTable.tableHeaders
  3238. .map((item) => item.fieldName)
  3239. .join(',')
  3240. this.contentEditForm.fixedTable.fixedTablesTitle =
  3241. this.stringToObjects(fixedFields || '')
  3242. }
  3243. const fixedTitles = this.contentEditForm.fixedTable.fixedTablesTitle
  3244. this.contentEditForm.fixedTable.fixedTableHeaders = fixedTitles.filter(
  3245. (title) => title.rkey !== '序号'
  3246. )
  3247. if (
  3248. !responseData ||
  3249. !responseData.value ||
  3250. !responseData.value.itemlist
  3251. ) {
  3252. return
  3253. }
  3254. const itemList = responseData.value.itemlist
  3255. const allRows = []
  3256. // 清空现有数据
  3257. this.contentEditForm.fixedTable.fixedTables = []
  3258. // 遍历itemList,为每个项目创建一行数据
  3259. itemList.forEach((item, index) => {
  3260. // 判断是否为子项(parentid不为-1且不为"-1")
  3261. const isSubItem =
  3262. item.parentid && item.parentid !== -1 && item.parentid !== '-1'
  3263. const newRow = {
  3264. orderText: item.orderNum || '', // 显示用序号
  3265. orderNum: item.orderNum || '', // 保留原始序号用于发送后端
  3266. surveyTemplateId: item.surveyTemplateId,
  3267. versionId: item.versionId,
  3268. cellCode: item.cellCode || '',
  3269. calculationFormula: item.calculationFormula || '',
  3270. unit: item.unit || '',
  3271. fixedValues: {},
  3272. itemId: item.id || null,
  3273. parentid: item.parentid || -1,
  3274. isChild: isSubItem,
  3275. isSubItem: isSubItem,
  3276. rowid: item.rowid || this.generateUUID(),
  3277. jsonstr: item.jsonstr || null,
  3278. }
  3279. // 确保orderNum是数字类型
  3280. if (item.orderNum) {
  3281. newRow.orderNum = parseInt(item.orderNum, 10) || 0
  3282. }
  3283. // 初始化fixedValues并填充实际值
  3284. fixedTitles.forEach((title) => {
  3285. newRow.fixedValues[title.rkey] = item[title.rkey] || ''
  3286. })
  3287. allRows.push(newRow)
  3288. })
  3289. // 按父子关系排序:父项在前,子项在对应的父项后面
  3290. allRows.sort((a, b) => {
  3291. // 先按orderNum排序父项
  3292. if (a.isChild && !b.isChild) {
  3293. // 如果a是子项,b是父项,需要检查a的父项是否在b之后
  3294. const parentOfA = allRows.find(
  3295. (item) => item.rowid === a.parentid || item.itemId === a.parentid
  3296. )
  3297. if (parentOfA && parentOfA.orderNum > b.orderNum) {
  3298. return 1
  3299. }
  3300. return -1
  3301. }
  3302. if (!a.isChild && b.isChild) {
  3303. // 如果a是父项,b是子项,需要检查b的父项是否在a之前
  3304. const parentOfB = allRows.find(
  3305. (item) => item.rowid === b.parentid || item.itemId === b.parentid
  3306. )
  3307. if (parentOfB && parentOfB.orderNum < a.orderNum) {
  3308. return -1
  3309. }
  3310. return 1
  3311. }
  3312. // 如果都是父项或都是子项,按orderNum排序
  3313. return (a.orderNum || 0) - (b.orderNum || 0)
  3314. })
  3315. // 重新排序,确保子项紧跟在其对应的父项后面
  3316. const sortedArray = []
  3317. const parentItems = allRows.filter((item) => !item.isChild)
  3318. const childItems = allRows.filter((item) => item.isChild)
  3319. parentItems.forEach((parent) => {
  3320. sortedArray.push(parent)
  3321. // 找到并添加该父项的所有子项
  3322. const relatedChildren = childItems.filter(
  3323. (child) =>
  3324. child.parentid === parent.rowid ||
  3325. child.parentid === parent.itemId
  3326. )
  3327. // 子项按orderNum排序
  3328. relatedChildren.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0))
  3329. sortedArray.push(...relatedChildren)
  3330. })
  3331. this.contentEditForm.fixedTable.fixedTables = sortedArray
  3332. },
  3333. /**
  3334. * 解析并回显动态表项目数据
  3335. * @param {Object} responseData - listByTemplateIdAndVersion接口返回的数据
  3336. */
  3337. parseAndDisplayDynamicTableData(responseData) {
  3338. if (responseData.value.fixedFields) {
  3339. this.contentEditForm.dynamicTable.dynamicTablesTitle =
  3340. this.stringToObjects(responseData.value.fixedFields || '')
  3341. } else {
  3342. let fixedFields = this.contentEditForm.dynamicTable.tableHeaders
  3343. .map((item) => item.fieldName)
  3344. .join(',')
  3345. this.contentEditForm.dynamicTable.dynamicTablesTitle =
  3346. this.stringToObjects(fixedFields || '')
  3347. }
  3348. const dynamicTitles =
  3349. this.contentEditForm.dynamicTable.dynamicTablesTitle
  3350. this.contentEditForm.dynamicTable.dynamicTableHeaders =
  3351. dynamicTitles.filter((title) => title.rkey !== '序号')
  3352. if (
  3353. !responseData ||
  3354. !responseData.value ||
  3355. !responseData.value.itemlist
  3356. ) {
  3357. return
  3358. }
  3359. const itemList = responseData.value.itemlist
  3360. const allRows = []
  3361. // 清空现有数据
  3362. this.contentEditForm.dynamicTable.dynamicTables = []
  3363. // 遍历itemList,为每个项目创建一行数据
  3364. itemList.forEach((item, index) => {
  3365. // 判断是否为子项(parentid不为-1且不为"-1")
  3366. const isSubItem =
  3367. item.parentid && item.parentid !== -1 && item.parentid !== '-1'
  3368. const newRow = {
  3369. orderText: item.orderNum || '', // 显示用序号
  3370. orderNum: item.orderNum || '', // 保留原始序号用于发送后端
  3371. surveyTemplateId: item.surveyTemplateId,
  3372. dynamicValues: {},
  3373. itemId: item.id || null,
  3374. parentid: item.parentid || -1,
  3375. isChild: isSubItem,
  3376. isSubItem: isSubItem,
  3377. rowid: item.rowid || this.generateUUID(),
  3378. jsonstr: item.jsonstr || null,
  3379. }
  3380. // 确保orderNum是数字类型
  3381. if (item.orderNum) {
  3382. newRow.orderNum = parseInt(item.orderNum, 10) || 0
  3383. }
  3384. // 初始化dynamicValues并填充实际值
  3385. dynamicTitles.forEach((title) => {
  3386. // 特殊处理序号字段,需要保存到dynamicValues中供输入框使用
  3387. if (title.rkey === '序号') {
  3388. // 优先使用item中的序号值,如果没有则保持为空
  3389. newRow.dynamicValues[title.rkey] = item[title.rkey] || ''
  3390. }
  3391. // 排除其他序号相关字段,避免重复显示
  3392. else if (title.rkey !== 'ordernum' && title.rkey !== 'orderText') {
  3393. newRow.dynamicValues[title.rkey] = item[title.rkey] || ''
  3394. }
  3395. })
  3396. allRows.push(newRow)
  3397. })
  3398. // 按父子关系排序:父项在前,子项在对应的父项后面
  3399. // 1. 先创建一个映射表,方便通过ID查找父项
  3400. const rowMap = new Map()
  3401. const sortedArray = []
  3402. const addedItems = new Set()
  3403. // 深拷贝原始数据并过滤掉重复项
  3404. const uniqueRows = allRows.reduce((acc, current) => {
  3405. const isDuplicate = acc.some(
  3406. (row) =>
  3407. (row.rowid && current.rowid && row.rowid === current.rowid) ||
  3408. (row.itemId && current.itemId && row.itemId === current.itemId)
  3409. )
  3410. if (!isDuplicate) {
  3411. acc.push(JSON.parse(JSON.stringify(current)))
  3412. }
  3413. return acc
  3414. }, [])
  3415. // 填充映射表
  3416. uniqueRows.forEach((row) => {
  3417. if (row.rowid) rowMap.set(String(row.rowid), row)
  3418. if (row.itemId) rowMap.set(String(row.itemId), row)
  3419. })
  3420. // 先按orderNum排序所有父项
  3421. const parentItems = uniqueRows.filter((item) => !item.isChild)
  3422. parentItems.sort(
  3423. (a, b) => (Number(a.orderNum) || 0) - (Number(b.orderNum) || 0)
  3424. )
  3425. // 递归添加父项及其子项的函数
  3426. const addItemWithChildren = (item) => {
  3427. // 确保项目ID唯一
  3428. const itemIdKey = String(
  3429. item.rowid || item.itemId || `temp_${Math.random()}`
  3430. )
  3431. // 如果已经添加过,则跳过
  3432. if (addedItems.has(itemIdKey)) return
  3433. // 添加当前项目
  3434. sortedArray.push(item)
  3435. addedItems.add(itemIdKey)
  3436. // 找到并添加所有子项
  3437. const children = uniqueRows.filter((child) => {
  3438. if (child.isChild) {
  3439. const childParentId = String(child.parentid)
  3440. return (
  3441. childParentId === String(item.rowid) ||
  3442. childParentId === String(item.itemId)
  3443. )
  3444. }
  3445. return false
  3446. })
  3447. // 子项按orderNum排序
  3448. children.sort(
  3449. (a, b) => (Number(a.orderNum) || 0) - (Number(b.orderNum) || 0)
  3450. )
  3451. // 添加所有子项
  3452. children.forEach((child) => addItemWithChildren(child))
  3453. }
  3454. // 遍历所有父项,添加父项及其子项
  3455. parentItems.forEach((parent) => addItemWithChildren(parent))
  3456. // 添加剩余的没有被添加的项目(应该很少,但作为兜底)
  3457. uniqueRows.forEach((row) => {
  3458. const itemIdKey = String(
  3459. row.rowid || row.itemId || `temp_${Math.random()}`
  3460. )
  3461. if (!addedItems.has(itemIdKey)) {
  3462. sortedArray.push(row)
  3463. addedItems.add(itemIdKey)
  3464. }
  3465. })
  3466. // 最后,重新计算显示序号,确保序号连续且正确
  3467. sortedArray.forEach((item, index) => {
  3468. item.orderText = String(index + 1)
  3469. })
  3470. this.contentEditForm.dynamicTable.dynamicTables = sortedArray
  3471. },
  3472. //分割字符串
  3473. stringToObjects(str) {
  3474. const items = str.split(',')
  3475. return items.map((item) => ({
  3476. rkey: item,
  3477. rvalue: '',
  3478. }))
  3479. },
  3480. // 删除
  3481. handleDelete(row) {
  3482. this.$confirm('确定要删除该数据吗?', '提示', {
  3483. type: 'warning',
  3484. })
  3485. .then(() => {
  3486. this.loading = true
  3487. delSurveyTemplateVersionById(row.id)
  3488. .then((res) => {
  3489. if (res.code === 200) {
  3490. this.$message.success(res.message || '删除成功')
  3491. this.handleSearch()
  3492. this.loading = false
  3493. }
  3494. })
  3495. .catch((error) => {
  3496. console.error('删除失败:', error)
  3497. this.loading = false
  3498. })
  3499. })
  3500. .catch(() => {})
  3501. },
  3502. // 批量删除
  3503. handleBatchDelete() {
  3504. if (this.selectedRows.length === 0) {
  3505. this.$message.warning('请先选择要删除的数据')
  3506. return
  3507. }
  3508. this.$confirm(
  3509. `确定要删除选中的${this.selectedRows.length}条数据吗?`,
  3510. '提示',
  3511. {
  3512. type: 'warning',
  3513. }
  3514. )
  3515. .then(() => {
  3516. this.loading = true
  3517. const ids = this.selectedRows.map((row) => row.id)
  3518. batchDeleteCostForm(ids)
  3519. .then((res) => {
  3520. this.selectedRows = []
  3521. this.$message.success(res.message || '删除成功')
  3522. this.handleSearch()
  3523. this.loading = false
  3524. })
  3525. .catch((error) => {
  3526. console.error('批量删除失败:', error)
  3527. this.loading = false
  3528. })
  3529. })
  3530. .catch(() => {})
  3531. },
  3532. // 表格选择
  3533. handleSelectionChange(selection) {
  3534. this.selectedRows = selection
  3535. },
  3536. // 分页变化处理
  3537. handlePaginationChange({ currentPage, pageSize }) {
  3538. this.pagination.currentPage = currentPage
  3539. this.pagination.pageSize = pageSize
  3540. this.handleSearch()
  3541. },
  3542. // 提交表单
  3543. submitForm() {
  3544. this.$refs.dataForm.validate((valid) => {
  3545. if (valid) {
  3546. this.loading = true
  3547. const submitData = {
  3548. versionNo: this.dataForm.version,
  3549. status: this.dataForm.status,
  3550. createBy: this.dataForm.createBy,
  3551. createTime: this.dataForm.createTime,
  3552. remarks: this.dataForm.remarks,
  3553. templateType: this.currentRow.templateType,
  3554. surveyTemplateName: this.currentRow.surveyTemplateName,
  3555. surveyTemplateId: this.currentRow.surveyTemplateId,
  3556. }
  3557. if (this.dataForm.id) {
  3558. // 修改
  3559. submitData.formId = this.dataForm.id
  3560. editCostForm(submitData)
  3561. .then(() => {
  3562. this.loading = false
  3563. this.$message.success('修改成功')
  3564. this.dialogVisible = false
  3565. this.handleSearch() // 重新加载数据
  3566. })
  3567. .catch((error) => {
  3568. console.error('修改失败:', error)
  3569. this.$message.error('修改失败,请重试')
  3570. this.loading = false
  3571. })
  3572. } else {
  3573. addSurveyTemplateVersion(submitData)
  3574. .then(() => {
  3575. this.loading = false
  3576. this.$message.success('添加成功')
  3577. this.dialogVisible = false
  3578. this.handleSearch() // 重新加载数据
  3579. })
  3580. .catch((error) => {
  3581. console.error('添加失败:', error)
  3582. this.$message.error('添加失败,请重试')
  3583. this.loading = false
  3584. })
  3585. }
  3586. }
  3587. })
  3588. },
  3589. // 获取数据存储库表选项
  3590. loadDataStorageTableOptions() {
  3591. getDataStorageTableOptions()
  3592. .then((response) => {
  3593. this.dataStorageTableOptions = response.data || []
  3594. })
  3595. .catch((error) => {
  3596. console.error('获取数据存储库表选项失败:', error)
  3597. })
  3598. },
  3599. },
  3600. }
  3601. </script>
  3602. <style lang="scss" scoped>
  3603. @import '@/styles/costAudit.scss';
  3604. .top-wrapper {
  3605. display: flex;
  3606. align-items: center;
  3607. }
  3608. .data-form,
  3609. .detail-form {
  3610. ::v-deep .el-select {
  3611. width: 100%;
  3612. }
  3613. }
  3614. .content-edit-container {
  3615. overflow-y: auto;
  3616. .button-group {
  3617. margin: 10px 0;
  3618. .el-button {
  3619. margin-right: 10px;
  3620. }
  3621. }
  3622. .table-edit-container {
  3623. margin-top: 10px;
  3624. ::v-deep .el-table {
  3625. transition: height 0.3s ease;
  3626. }
  3627. ::v-deep .el-table__body-wrapper {
  3628. transition: scrollTop 0.3s ease;
  3629. }
  3630. }
  3631. .bind-dict-column {
  3632. display: flex;
  3633. flex-direction: column;
  3634. }
  3635. .table-actions {
  3636. display: flex;
  3637. justify-content: center;
  3638. align-items: center;
  3639. .el-button {
  3640. padding: 4px;
  3641. margin: 0 2px;
  3642. }
  3643. }
  3644. .format-input {
  3645. display: flex;
  3646. align-items: center;
  3647. .format-prefix {
  3648. font-size: 12px;
  3649. color: #606266;
  3650. margin-right: 5px;
  3651. white-space: nowrap;
  3652. }
  3653. }
  3654. }
  3655. .detail-info-container {
  3656. margin: 20px 0;
  3657. border-radius: 4px;
  3658. .detail-item {
  3659. display: inline-block;
  3660. margin-right: 30px;
  3661. margin-bottom: 10px;
  3662. .detail-label {
  3663. font-weight: bold;
  3664. color: #606266;
  3665. }
  3666. .detail-value {
  3667. color: #303133;
  3668. }
  3669. }
  3670. }
  3671. </style>