index.vue 104 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081
  1. <template>
  2. <div class="supervision-content-container">
  3. <!-- 搜索表单 -->
  4. <div class="search-panel">
  5. <el-form :inline="true" :model="searchForm" class="search-form">
  6. <el-form-item label="监审类别:">
  7. <el-cascader
  8. v-model="searchForm.catalogId"
  9. :options="catalogListOptions"
  10. placeholder=" 请选择监审类别"
  11. v-bind="props"
  12. style="width: 100%"
  13. clearable
  14. ></el-cascader>
  15. </el-form-item>
  16. <el-form-item label="模板名称:">
  17. <el-input
  18. v-model="searchForm.keyword"
  19. placeholder="请输入模板名称"
  20. clearable
  21. ></el-input>
  22. </el-form-item>
  23. <el-form-item>
  24. <el-button
  25. type="primary"
  26. icon="iconfont-5039297 icon-chaxun"
  27. @click="handleSearch"
  28. >
  29. 搜索
  30. </el-button>
  31. <el-button
  32. plain
  33. type="primary"
  34. icon="iconfont-5039297 icon-zhongzhi"
  35. @click="handleReset"
  36. >
  37. 重置
  38. </el-button>
  39. </el-form-item>
  40. </el-form>
  41. </div>
  42. <!-- 操作按钮 -->
  43. <div class="operation-bar">
  44. <!-- v-region-permission="{
  45. category: 'costVerifyManage',
  46. action: 'add',
  47. }" -->
  48. <el-button
  49. plain
  50. type="success"
  51. icon="iconfont-5039297 icon-zengjia1"
  52. @click="handleAdd"
  53. >
  54. <!-- v-region-permission="{
  55. category: 'costVerifyManage',
  56. action: 'add',
  57. }" -->
  58. 添加
  59. </el-button>
  60. <!-- v-region-permission="{
  61. category: 'costVerifyManage',
  62. action: 'delete',
  63. }" -->
  64. <el-button
  65. plain
  66. type="danger"
  67. icon="iconfont-5039297 icon-shanchu1"
  68. :disabled="selectedRows.length === 0"
  69. @click="handleBatchDelete"
  70. >
  71. 删除
  72. </el-button>
  73. </div>
  74. <!-- 表格 -->
  75. <div class="table-container">
  76. <el-table
  77. v-loading="loading"
  78. :data="tableData"
  79. border
  80. style="width: 100%"
  81. :default-sort="{ prop: 'createTime', order: 'descending' }"
  82. @selection-change="handleSelectionChange"
  83. >
  84. <template slot="empty">
  85. <Empty></Empty>
  86. </template>
  87. <!-- :default-sort="{ prop: 'createTime', order: 'descending' }" -->
  88. <el-table-column
  89. type="selection"
  90. width="55"
  91. align="center"
  92. show-overflow-tooltip
  93. ></el-table-column>
  94. <el-table-column
  95. type="index"
  96. label="序号"
  97. width="60"
  98. align="center"
  99. show-overflow-tooltip
  100. ></el-table-column>
  101. <el-table-column
  102. prop="catalogId"
  103. label="监审类别"
  104. align="center"
  105. show-overflow-tooltip
  106. >
  107. <template slot-scope="scope">
  108. <div>{{ getCatalogNames(scope.row) }}</div>
  109. </template>
  110. </el-table-column>
  111. <el-table-column
  112. prop="surveyTemplateName"
  113. label="核定模板名称"
  114. show-overflow-tooltip
  115. align="center"
  116. ></el-table-column>
  117. <el-table-column
  118. prop="versionNo"
  119. label="版本号"
  120. align="center"
  121. width="150"
  122. ></el-table-column>
  123. <el-table-column
  124. prop="status"
  125. label="状态"
  126. width="100"
  127. show-overflow-tooltip
  128. align="center"
  129. >
  130. <template slot-scope="scope">
  131. <span>
  132. {{
  133. scope.row.status == '-1'
  134. ? '草稿'
  135. : scope.row.status == '0'
  136. ? '启用'
  137. : '停用'
  138. }}
  139. </span>
  140. </template>
  141. </el-table-column>
  142. <el-table-column
  143. prop="createBy"
  144. label="创建人"
  145. width="120"
  146. show-overflow-tooltip
  147. align="center"
  148. ></el-table-column>
  149. <el-table-column
  150. prop="createTime"
  151. label="创建时间"
  152. width="160"
  153. show-overflow-tooltip
  154. align="center"
  155. sortable
  156. >
  157. <!-- sortable -->
  158. <template slot-scope="scope">
  159. <div>{{ scope.row.createTime.split(' ')[0] }}</div>
  160. <div>{{ scope.row.createTime.split(' ')[1] }}</div>
  161. </template>
  162. </el-table-column>
  163. <el-table-column
  164. label="操作"
  165. width="240"
  166. fixed="right"
  167. show-overflow-tooltip
  168. align="center"
  169. >
  170. <template slot-scope="scope">
  171. <!-- v-region-permission="{
  172. category: 'costVerifyManage',
  173. action: 'view',
  174. }" -->
  175. <el-button
  176. type="text"
  177. size="mini"
  178. @click="handleViewDetail(scope.row)"
  179. >
  180. 查看
  181. </el-button>
  182. <!-- v-region-permission="{
  183. category: 'costVerifyManage',
  184. action: 'edit',
  185. targetData: scope.row,
  186. }" -->
  187. <el-button
  188. v-if="scope.row.status != '0'"
  189. type="text"
  190. size="mini"
  191. @click="handleEdit(scope.row)"
  192. >
  193. 修改
  194. </el-button>
  195. <!-- v-region-permission="{
  196. category: 'costVerifyManage',
  197. action: 'edit',
  198. targetData: scope.row,
  199. }" -->
  200. <el-button
  201. type="text"
  202. size="mini"
  203. @click="handleStatusChange(scope.row)"
  204. >
  205. <!-- (-1草稿,0启用,1停用) -->
  206. {{ scope.row.status == '0' ? '停用' : '启用' }}
  207. </el-button>
  208. <!-- v-region-permission="{
  209. category: 'costVerifyManage',
  210. action: 'delete',
  211. targetData: scope.row,
  212. }" -->
  213. <el-button
  214. v-if="scope.row.status != '0'"
  215. type="text"
  216. size="mini"
  217. @click="handleDeleteRow(scope.row)"
  218. >
  219. 删除
  220. </el-button>
  221. </template>
  222. </el-table-column>
  223. </el-table>
  224. <el-pagination
  225. class="mt20"
  226. :current-page.sync="searchForm.page"
  227. :page-size="searchForm.pageSize"
  228. :page-sizes="[50, 100]"
  229. layout="total, sizes, prev, pager, next, jumper"
  230. :total="pagination.total"
  231. @current-change="handleCurrentChange"
  232. @size-change="handleSizeChange"
  233. ></el-pagination>
  234. </div>
  235. <!-- 添加/修改弹窗 -->
  236. <el-dialog
  237. :title="dialogTitle"
  238. :visible.sync="dialogVisible"
  239. width="75%"
  240. :close-on-click-modal="false"
  241. >
  242. <el-form
  243. ref="contentEditForm"
  244. :model="contentEditForm"
  245. :rules="contentEditFormRules"
  246. label-width="220px"
  247. class="content-form"
  248. :disabled="dialogTitle == '查看成本核定模板'"
  249. >
  250. <el-row :gutter="20">
  251. <el-col :span="12">
  252. <el-form-item label="监审类别:" prop="catalogId">
  253. <el-cascader
  254. v-model="contentEditForm.catalogId"
  255. :options="catalogListOptions"
  256. v-bind="props"
  257. style="width: 100%"
  258. @change="handleCatalogChange"
  259. ></el-cascader>
  260. </el-form-item>
  261. </el-col>
  262. <el-col :span="12">
  263. <el-form-item label="核定模板名称:" prop="surveyTemplateName">
  264. <el-input
  265. v-model="contentEditForm.surveyTemplateName"
  266. placeholder="请输入核定模板名称"
  267. maxlength="30"
  268. show-word-limit
  269. ></el-input>
  270. </el-form-item>
  271. </el-col>
  272. </el-row>
  273. <el-row :gutter="20">
  274. <el-col :span="12">
  275. <el-form-item label="" prop="createtemplateid">
  276. <!-- :disabled="dialogTitle == '修改成本核定模板'" -->
  277. <template slot="label">
  278. <el-radio
  279. v-model="contentEditForm.createmode"
  280. label="1"
  281. :disabled="
  282. dialogTitle == '查看成本核定模板' ||
  283. dialogTitle == '修改成本核定模板' ||
  284. contentEditForm.surveyTemplateId != ''
  285. "
  286. @change="handleCreateModeChange"
  287. >
  288. 根据调查表生成:
  289. </el-radio>
  290. </template>
  291. <el-select
  292. v-model="contentEditForm.createtemplateid"
  293. placeholder="请选择"
  294. :disabled="
  295. dialogTitle == '查看成本核定模板' ||
  296. dialogTitle == '修改成本核定模板' ||
  297. contentEditForm.surveyTemplateId != ''
  298. "
  299. >
  300. <el-option
  301. v-for="item in surveyFormList"
  302. :key="item.id"
  303. :label="item.surveyTemplateName"
  304. :value="item.surveyTemplateId"
  305. ></el-option>
  306. </el-select>
  307. </el-form-item>
  308. </el-col>
  309. <el-col :span="12">
  310. <el-form-item label="" prop="">
  311. <template slot="label">
  312. <el-radio
  313. v-model="contentEditForm.createmode"
  314. label="2"
  315. :disabled="
  316. dialogTitle == '查看成本核定模板' ||
  317. dialogTitle == '修改成本核定模板' ||
  318. contentEditForm.surveyTemplateId != ''
  319. "
  320. @change="handleCreateModeChange"
  321. >
  322. 根据历史核定模板生成:
  323. </el-radio>
  324. </template>
  325. <el-select
  326. v-model="contentEditForm.createtemplateid1"
  327. placeholder="请选择"
  328. :disabled="
  329. dialogTitle == '查看成本核定模板' ||
  330. dialogTitle == '修改成本核定模板' ||
  331. contentEditForm.surveyTemplateId != '' ||
  332. contentEditForm.catalogId == ''
  333. "
  334. >
  335. <el-option
  336. v-for="item in contentEditFormList"
  337. :key="item.id"
  338. :label="item.surveyTemplateName"
  339. :value="item.surveyTemplateId"
  340. ></el-option>
  341. </el-select>
  342. </el-form-item>
  343. </el-col>
  344. </el-row>
  345. </el-form>
  346. <div>
  347. <div class="mb20">
  348. <el-button
  349. v-if="!contentEditForm.surveyTemplateId"
  350. type="primary"
  351. class="mr20"
  352. @click="handleGenerateTemplate"
  353. >
  354. 生成模版
  355. </el-button>
  356. </div>
  357. <div
  358. v-if="contentEditForm.surveyTemplateId"
  359. class="table-edit-container"
  360. >
  361. <div class="mb20">
  362. <el-button
  363. v-if="dialogTitle != '查看成本核定模板'"
  364. type="primary"
  365. @click="handleAddTableHeader('固定表表头')"
  366. >
  367. 添加表头
  368. </el-button>
  369. <el-button
  370. v-if="dialogTitle != '查看成本核定模板'"
  371. type="primary"
  372. @click="handleSaveContent('固定表表头')"
  373. >
  374. 下一步
  375. </el-button>
  376. </div>
  377. <div class="table-edit-container">
  378. <el-table
  379. :data="contentEditForm.fixedTable.tableHeaders"
  380. border
  381. style="width: 100%"
  382. >
  383. <el-table-column label="序号" width="80" align="center">
  384. <template slot-scope="scope">
  385. <span>{{ scope.$index + 1 }}</span>
  386. </template>
  387. </el-table-column>
  388. <el-table-column
  389. prop="fieldName"
  390. label="字段名称"
  391. min-width="150"
  392. align="center"
  393. >
  394. <template slot-scope="scope">
  395. <el-input
  396. v-model="scope.row.fieldName"
  397. placeholder="请输入字段名称"
  398. size="small"
  399. :disabled="
  400. scope.row.isReadOnly || dialogTitle == '查看成本核定模板'
  401. "
  402. @change="handleFieldNameChange(scope.row)"
  403. ></el-input>
  404. </template>
  405. </el-table-column>
  406. <el-table-column
  407. prop="fieldType"
  408. label="字段类型"
  409. width="120"
  410. align="center"
  411. >
  412. <template slot-scope="scope">
  413. <el-select
  414. v-model="scope.row.fieldType"
  415. placeholder="请选择字段类型"
  416. size="small"
  417. :disabled="
  418. scope.row.isReadOnly || dialogTitle == '查看成本核定模板'
  419. "
  420. @change="handleFieldTypeChange(scope.row)"
  421. >
  422. <el-option label="字符串" value="string"></el-option>
  423. <el-option label="整数" value="integer"></el-option>
  424. <el-option label="小数" value="double"></el-option>
  425. <el-option label="日期" value="datetime"></el-option>
  426. <el-option label="布尔值" value="boolean"></el-option>
  427. </el-select>
  428. </template>
  429. </el-table-column>
  430. <el-table-column
  431. prop="format"
  432. label="格式"
  433. width="220"
  434. align="center"
  435. >
  436. <template slot-scope="scope">
  437. <!-- 字符串类型格式 -->
  438. <div
  439. v-if="scope.row.fieldType === 'string'"
  440. class="format-input"
  441. >
  442. <span class="format-prefix">长度</span>
  443. <el-input
  444. v-model="scope.row.format"
  445. placeholder="请输入长度"
  446. size="small"
  447. style="width: calc(100% - 80px); margin-left: 5px"
  448. :disabled="
  449. scope.row.isReadOnly ||
  450. dialogTitle == '查看成本核定模板'
  451. "
  452. ></el-input>
  453. </div>
  454. <!-- 整数类型格式 -->
  455. <div
  456. v-else-if="scope.row.fieldType === 'integer'"
  457. class="format-input"
  458. >
  459. <span class="format-prefix">整数</span>
  460. <el-input
  461. v-model="scope.row.fieldTypelen"
  462. placeholder="整数位数"
  463. size="small"
  464. style="width: calc(100% - 80px); margin: 0 5px"
  465. :disabled="
  466. scope.row.isReadOnly ||
  467. dialogTitle == '查看成本核定模板'
  468. "
  469. ></el-input>
  470. </div>
  471. <!-- 小数类型格式 -->
  472. <div
  473. v-else-if="scope.row.fieldType === 'double'"
  474. class="format-input"
  475. >
  476. <span class="format-prefix">小数</span>
  477. <el-input
  478. v-model="scope.row.fieldTypenointlen"
  479. placeholder="小数位数"
  480. size="small"
  481. style="width: calc(100% - 80px); margin-left: 5px"
  482. :disabled="
  483. scope.row.isReadOnly ||
  484. dialogTitle == '查看成本核定模板'
  485. "
  486. ></el-input>
  487. </div>
  488. <!-- 日期类型格式 -->
  489. <div
  490. v-else-if="scope.row.fieldType === 'datetime'"
  491. class="format-input"
  492. >
  493. <el-select
  494. v-model="scope.row.format"
  495. placeholder="请选择日期格式"
  496. size="small"
  497. style="width: 100%"
  498. :disabled="
  499. scope.row.isReadOnly ||
  500. dialogTitle == '查看成本核定模板'
  501. "
  502. >
  503. <el-option
  504. label="yyyy-MM-dd HH:mm:ss"
  505. value="yyyy-MM-dd HH:mm:ss"
  506. ></el-option>
  507. <el-option
  508. label="yyyy-MM-dd"
  509. value="yyyy-MM-dd"
  510. ></el-option>
  511. </el-select>
  512. </div>
  513. <!-- 布尔类型格式 -->
  514. <div v-else-if="scope.row.fieldType === 'boolean'">
  515. <el-select
  516. v-model="scope.row.format"
  517. placeholder="请选择布尔值格式"
  518. size="small"
  519. style="width: 100%"
  520. :disabled="
  521. scope.row.isReadOnly ||
  522. dialogTitle == '查看成本核定模板'
  523. "
  524. >
  525. <el-option label="true" value="true"></el-option>
  526. <el-option label="false" value="false"></el-option>
  527. </el-select>
  528. </div>
  529. <!-- 默认情况 -->
  530. <el-input
  531. v-else
  532. v-model="scope.row.format"
  533. :placeholder="getFormatPlaceholder(scope.row.fieldType)"
  534. size="small"
  535. ></el-input>
  536. </template>
  537. </el-table-column>
  538. <el-table-column
  539. prop="isRequired"
  540. label="是否必填"
  541. width="120"
  542. align="center"
  543. >
  544. <template slot-scope="scope">
  545. <el-select
  546. v-model="scope.row.isRequired"
  547. size="small"
  548. :disabled="
  549. scope.row.isReadOnly || dialogTitle == '查看成本核定模板'
  550. "
  551. >
  552. <el-option label="是" value="true"></el-option>
  553. <el-option label="否" value="false"></el-option>
  554. </el-select>
  555. </template>
  556. </el-table-column>
  557. <el-table-column
  558. prop="showVisible"
  559. label="是否显示"
  560. width="120"
  561. align="center"
  562. >
  563. <template slot-scope="scope">
  564. <el-select
  565. v-model="scope.row.showVisible"
  566. size="small"
  567. :disabled="
  568. scope.row.isReadOnly || dialogTitle == '查看成本核定模板'
  569. "
  570. >
  571. <el-option label="是" value="1"></el-option>
  572. <el-option label="否" value="0"></el-option>
  573. </el-select>
  574. </template>
  575. </el-table-column>
  576. <el-table-column
  577. prop="isAuditPeriod"
  578. label="是否绑定监审期间"
  579. width="140"
  580. align="center"
  581. >
  582. <template slot-scope="scope">
  583. <el-select
  584. v-model="scope.row.isAuditPeriod"
  585. size="small"
  586. :disabled="
  587. scope.row.isReadOnly || dialogTitle == '查看成本核定模板'
  588. "
  589. >
  590. <el-option label="是" value="true"></el-option>
  591. <el-option label="否" value="false"></el-option>
  592. </el-select>
  593. </template>
  594. </el-table-column>
  595. <el-table-column prop="isDict" label="绑定字典" min-width="150">
  596. <template slot-scope="scope">
  597. <div class="bind-dict-column">
  598. <el-select
  599. v-model="scope.row.isDict"
  600. size="small"
  601. style="width: 80px"
  602. :disabled="
  603. scope.row.isReadOnly ||
  604. dialogTitle == '查看成本核定模板'
  605. "
  606. @change="handleBindDictChange(scope.row)"
  607. >
  608. <el-option label="是" value="true"></el-option>
  609. <el-option label="否" value="false"></el-option>
  610. </el-select>
  611. <el-select
  612. v-if="scope.row.isDict === 'true'"
  613. v-model="scope.row.dictid"
  614. placeholder="请选择字典"
  615. class="dict-select"
  616. size="small"
  617. style="width: 120px; margin-top: 5px"
  618. :disabled="
  619. scope.row.isReadOnly ||
  620. dialogTitle == '查看成本核定模板'
  621. "
  622. >
  623. <el-option
  624. v-for="(item, index) in dictTypeList"
  625. :key="index"
  626. :label="item.name"
  627. :value="String(item.id)"
  628. ></el-option>
  629. </el-select>
  630. </div>
  631. </template>
  632. </el-table-column>
  633. <el-table-column
  634. label="操作"
  635. width="150"
  636. fixed="right"
  637. align="center"
  638. >
  639. <template slot-scope="scope">
  640. <div class="table-actions">
  641. <el-button
  642. v-if="dialogTitle != '查看成本核定模板'"
  643. type="text"
  644. size="mini"
  645. :disabled="
  646. scope.row.isReadOnly ||
  647. dialogTitle == '查看成本核定模板'
  648. "
  649. @click="
  650. handleDeleteHeader(
  651. scope.$index,
  652. '固定表表头',
  653. scope.row
  654. )
  655. "
  656. >
  657. 删除
  658. </el-button>
  659. <el-button
  660. v-if="
  661. scope.$index !== 0 || dialogTitle != '查看成本核定模板'
  662. "
  663. type="text"
  664. size="mini"
  665. :disabled="
  666. scope.row.isReadOnly ||
  667. dialogTitle == '查看成本核定模板'
  668. "
  669. @click="handleMoveUp(scope.$index)"
  670. >
  671. 上升
  672. </el-button>
  673. <el-button
  674. v-if="
  675. scope.$index !==
  676. contentEditForm.fixedTable.tableHeaders.length - 1 ||
  677. dialogTitle == '查看成本核定模板'
  678. "
  679. type="text"
  680. size="mini"
  681. :disabled="
  682. scope.row.isReadOnly ||
  683. dialogTitle == '查看成本核定模板'
  684. "
  685. @click="handleMoveDown(scope.$index)"
  686. >
  687. 下降
  688. </el-button>
  689. </div>
  690. </template>
  691. </el-table-column>
  692. </el-table>
  693. </div>
  694. <div>
  695. <div class="button-group mt20 mb20">
  696. <el-button
  697. v-if="dialogTitle != '查看成本核定模板'"
  698. type="primary"
  699. @click="handleAddTableHeader('固定表项目')"
  700. >
  701. 添加项目
  702. </el-button>
  703. <el-button
  704. v-if="dialogTitle != '查看成本核定模板'"
  705. type="primary"
  706. @click="handleSaveTemplate"
  707. >
  708. 保存
  709. </el-button>
  710. </div>
  711. <div class="table-edit-container">
  712. <el-table
  713. :data="contentEditForm.fixedTable.fixedTables"
  714. border
  715. style="width: 100%"
  716. row-key="rowid"
  717. default-expand-all
  718. :tree-props="{
  719. children: 'children',
  720. hasChildren: 'hasChildren',
  721. }"
  722. @selection-change="handleSelectionChange"
  723. >
  724. <el-table-column label="父子节点" align="center" width="100">
  725. <template slot-scope="scope">
  726. <el-tag
  727. v-if="
  728. scope.row.isChild ||
  729. scope.row.isSubItem ||
  730. (scope.row.parentid &&
  731. scope.row.parentid != -1 &&
  732. scope.row.parentid != '-1')
  733. "
  734. type="success"
  735. size="small"
  736. >
  737. 子项
  738. </el-tag>
  739. <el-tag
  740. v-else-if="
  741. scope.row.parentid === -1 ||
  742. scope.row.parentid === '-1' ||
  743. !scope.row.parentid
  744. "
  745. type="primary"
  746. size="small"
  747. >
  748. 父项
  749. </el-tag>
  750. <el-tag v-else type="info" size="small">无</el-tag>
  751. </template>
  752. </el-table-column>
  753. <el-table-column label="序号" width="80" align="center">
  754. <template slot-scope="scope">
  755. <div
  756. class="row-indent-container"
  757. :style="getRowIndentStyle(scope.row)"
  758. >
  759. <el-input
  760. :value="
  761. scope.row.fixedValues
  762. ? scope.row.fixedValues['序号']
  763. : ''
  764. "
  765. size="small"
  766. placeholder="数字或中文"
  767. :disabled="dialogTitle == '查看成本核定模板'"
  768. @input="
  769. handleFixedValueChange(scope.row, '序号', $event)
  770. "
  771. ></el-input>
  772. </div>
  773. </template>
  774. </el-table-column>
  775. <el-table-column
  776. v-for="(item, index) in contentEditForm.fixedTable
  777. .fixedTableHeaders"
  778. :key="index"
  779. :label="item.rkey"
  780. width="120"
  781. align="center"
  782. >
  783. <template slot-scope="scope">
  784. <div class="row-indent-container">
  785. <el-input
  786. :value="
  787. scope.row.fixedValues
  788. ? scope.row.fixedValues[item.rkey]
  789. : ''
  790. "
  791. size="small"
  792. :disabled="dialogTitle == '查看成本核定模板'"
  793. @input="
  794. handleFixedValueChange(scope.row, item.rkey, $event)
  795. "
  796. ></el-input>
  797. </div>
  798. </template>
  799. </el-table-column>
  800. <el-table-column label="指标编号" width="100" align="center">
  801. <template slot-scope="scope">
  802. <div class="row-indent-container">
  803. <el-input
  804. :value="scope.row.cellCode"
  805. size="small"
  806. :disabled="dialogTitle == '查看成本核定模板'"
  807. @input="(val) => $set(scope.row, 'cellCode', val)"
  808. ></el-input>
  809. </div>
  810. </template>
  811. </el-table-column>
  812. <el-table-column
  813. label="计算公式"
  814. width="150"
  815. align="center"
  816. show-overflow-tooltip
  817. >
  818. <template slot-scope="scope">
  819. <div class="row-indent-container">
  820. <el-input
  821. :value="scope.row.calculationFormula"
  822. size="small"
  823. readonly
  824. :disabled="dialogTitle == '查看成本核定模板'"
  825. @click.native="
  826. openCalculationFormulaDialogVisible(
  827. scope.row,
  828. scope.$index
  829. )
  830. "
  831. ></el-input>
  832. </div>
  833. </template>
  834. </el-table-column>
  835. <el-table-column label="单位" width="80" align="center">
  836. <template slot-scope="scope">
  837. <div class="row-indent-container">
  838. <el-input
  839. :value="scope.row.unit"
  840. size="small"
  841. :disabled="dialogTitle == '查看成本核定模板'"
  842. @input="(val) => $set(scope.row, 'unit', val)"
  843. ></el-input>
  844. </div>
  845. </template>
  846. </el-table-column>
  847. <el-table-column
  848. label="操作"
  849. align="center"
  850. fixed="right"
  851. width="200"
  852. >
  853. <template slot-scope="scope">
  854. <div class="table-actions">
  855. <el-button
  856. v-if="!scope.row.isChild"
  857. type="text"
  858. size="mini"
  859. :disabled="dialogTitle == '查看成本核定模板'"
  860. @click="
  861. handleAddChildItem(
  862. scope.$index,
  863. '固定表项目',
  864. scope.row
  865. )
  866. "
  867. >
  868. 添加子项
  869. </el-button>
  870. <el-button
  871. type="text"
  872. size="mini"
  873. :disabled="dialogTitle == '查看成本核定模板'"
  874. @click="
  875. handleDeleteHeader(
  876. scope.$index,
  877. '固定表项目',
  878. scope.row
  879. )
  880. "
  881. >
  882. 删除
  883. </el-button>
  884. <el-button
  885. v-if="scope.$index !== 0"
  886. type="text"
  887. size="mini"
  888. :disabled="dialogTitle == '查看成本核定模板'"
  889. @click="handleMoveUp(scope.$index, '固定表', scope.row)"
  890. >
  891. 上升
  892. </el-button>
  893. <el-button
  894. v-if="
  895. scope.$index !==
  896. contentEditForm.fixedTable.fixedTables.length - 1
  897. "
  898. type="text"
  899. size="mini"
  900. :disabled="dialogTitle == '查看成本核定模板'"
  901. @click="handleMoveDown(scope.$index, '固定表')"
  902. >
  903. 下降
  904. </el-button>
  905. </div>
  906. </template>
  907. </el-table-column>
  908. </el-table>
  909. </div>
  910. </div>
  911. </div>
  912. </div>
  913. <!-- <div slot="footer" class="dialog-footer">
  914. <el-button type="primary" @click="handleSaveTemplate">确 认</el-button>
  915. <el-button @click="dialogVisible = false">取 消</el-button>
  916. </div> -->
  917. </el-dialog>
  918. <el-dialog
  919. title="计算公式"
  920. :visible.sync="calculationFormulaDialogVisible"
  921. width="500px"
  922. :before-close="handleDialogClose"
  923. :close-on-click-modal="false"
  924. >
  925. <!-- 单选按钮组:切换“当前指标项”/“其他模板指标项” -->
  926. <el-radio-group
  927. v-model="radioType"
  928. class="mb20"
  929. @change="handleRadioChange"
  930. >
  931. <el-radio label="current">当前指标项</el-radio>
  932. <el-radio label="other">其他模板指标项</el-radio>
  933. </el-radio-group>
  934. <!-- 「当前指标项」内容区域 -->
  935. <div v-if="radioType === 'current'" class="current-panel">
  936. <el-input
  937. v-model="formulaText"
  938. type="textarea"
  939. rows="4"
  940. placeholder="请输入公式(如 C1+C2+C3)"
  941. />
  942. </div>
  943. <!-- 「其他模板指标项」内容区域 -->
  944. <div v-else class="other-panel">
  945. <span>模板名称:</span>
  946. <el-select
  947. v-model="selectedTemplateId"
  948. style="width: 80%"
  949. placeholder="请选择模板"
  950. @change="handleTemplateChange"
  951. >
  952. <el-option
  953. v-for="(item, index) in templateList"
  954. :key="index"
  955. :label="item.surveyTemplateName"
  956. :value="item.pkVal"
  957. ></el-option>
  958. </el-select>
  959. <!-- 指标表格 -->
  960. <el-table
  961. ref="indicatorTable"
  962. :data="indicatorTableData"
  963. border
  964. style="width: 100%; margin-top: 10px"
  965. class="mb20"
  966. @row-click="handleRowClick"
  967. >
  968. <!-- @selection-change="selectionIndicatorChange" -->
  969. <el-table-column type="selection" label="选择" width="60">
  970. <template #default="scope">
  971. <el-checkbox
  972. v-model="scope.row.checked"
  973. @change="handleCheckboxChange(scope.row)"
  974. ></el-checkbox>
  975. </template>
  976. </el-table-column>
  977. <el-table-column
  978. prop="cellCode"
  979. label="指标编号"
  980. align="center"
  981. ></el-table-column>
  982. <!--循环表头 -->
  983. <el-table-column
  984. v-for="(item, index) in indicatorTableHeaders"
  985. :key="index"
  986. :label="item.rkey"
  987. align="center"
  988. show-overflow-tooltip
  989. >
  990. <template slot-scope="scope">
  991. {{
  992. scope.row.fixedValues ? scope.row.fixedValues[item.rkey] : ''
  993. }}
  994. </template>
  995. </el-table-column>
  996. </el-table>
  997. <el-input
  998. v-model="formulaText"
  999. type="textarea"
  1000. rows="4"
  1001. placeholder="请输入公式(如 C1+C2+C3)"
  1002. @input="handleFormulaTextChange"
  1003. />
  1004. </div>
  1005. <!-- 弹窗底部按钮 -->
  1006. <div slot="footer" class="dialog-footer">
  1007. <el-button type="primary" @click="handleConfirm">确定</el-button>
  1008. <el-button @click="calculationFormulaDialogVisible = false">
  1009. 取消
  1010. </el-button>
  1011. </div>
  1012. </el-dialog>
  1013. </div>
  1014. </template>
  1015. <script>
  1016. import {
  1017. getCostFormDataStorageTables,
  1018. deleteCostVerifyForm,
  1019. getActiveCostVerifyFormList,
  1020. getActiveCostVerifyFormListByType,
  1021. generateCostVerifyFormData,
  1022. generateCostVerifyForm,
  1023. addCostVerifyForm,
  1024. getCostFormVersionsByTemplateId,
  1025. batchSaveOrUpdate,
  1026. } from '@/api/costFormManage'
  1027. import {
  1028. getlistBySurveyTemplateId,
  1029. batchDeleteCostVerifyForm,
  1030. getlistBySurveyTemplateIdcurrentversion,
  1031. batchSave,
  1032. enable,
  1033. getListFixedEnabled,
  1034. listByVerifyTemplateId,
  1035. } from '@/api/costVerifyManage'
  1036. import { getCatalogDetail } from '@/api/catalogManage'
  1037. import { listByCurrentTemplateId } from '@/api/catalogManage.js'
  1038. import { catalogMixin, commonMixin } from '@/mixins/useDict'
  1039. import { getDictTypList } from '@/api/dictionaryManage.js'
  1040. export default {
  1041. name: 'SupervisionContent',
  1042. // 使用混入
  1043. mixins: [catalogMixin, commonMixin],
  1044. data() {
  1045. return {
  1046. loading: false,
  1047. searchForm: {
  1048. type: '',
  1049. catalogId: '',
  1050. keyword: '',
  1051. page: 1,
  1052. pageSize: 50,
  1053. },
  1054. props: {
  1055. filterable: true,
  1056. placeholder: '请选择监审类别',
  1057. style: 'width: 100%',
  1058. showAllLevels: false,
  1059. props: {
  1060. multiple: false,
  1061. children: 'children',
  1062. checkStrictly: false,
  1063. label: 'catalogName',
  1064. value: 'id',
  1065. emitPath: false,
  1066. },
  1067. },
  1068. tableData: [],
  1069. selectedRows: [],
  1070. pagination: {
  1071. currentPage: 1,
  1072. pageSize: 50,
  1073. total: 0,
  1074. },
  1075. dialogVisible: false,
  1076. detailDialogVisible: false,
  1077. dialogTitle: '',
  1078. contentEditForm: {
  1079. areaCode: '',
  1080. areaLevel: '',
  1081. catalogId: '',
  1082. contentType: '',
  1083. createBy: '',
  1084. createTime: '',
  1085. createmode: '',
  1086. createtemplateid: '',
  1087. createtemplateid1: '',
  1088. isDelete: '',
  1089. pkVal: '',
  1090. remarks: '',
  1091. status: '',
  1092. storageTable: '',
  1093. surveyTemplateId: '',
  1094. surveyTemplateName: '',
  1095. surveyTemplateNameYw: '',
  1096. templateType: '2',
  1097. type: '',
  1098. updateBy: '',
  1099. updateTime: '',
  1100. versionNo: '',
  1101. // 固定表列表
  1102. fixedTable: {
  1103. tableHeaders: [],
  1104. fixedTables: [],
  1105. fixedTablesTitle: [],
  1106. fixedTableHeaders: [],
  1107. },
  1108. },
  1109. dynamicTable: [],
  1110. contentEditFormRules: {
  1111. catalogId: [
  1112. { required: true, message: '请选择监审类别', trigger: 'change' },
  1113. ],
  1114. surveyTemplateName: [
  1115. { required: true, message: '请输入核定模板名称', trigger: 'blur' },
  1116. {
  1117. min: 1,
  1118. max: 30,
  1119. message: '核定模板名称长度应在1-30个字符之间',
  1120. trigger: 'blur',
  1121. },
  1122. ],
  1123. // createtemplateid: [
  1124. // { required: true, message: '请选择模板类型', trigger: 'change' },
  1125. // ],
  1126. },
  1127. // 成本核定表模板列表
  1128. contentEditFormList: [],
  1129. // 成本调查表模板列表
  1130. surveyFormList: [],
  1131. CatalogNameMap: {},
  1132. calculationFormulaDialogVisible: false,
  1133. currentEditingRow: null,
  1134. currentEditingRowIndex: -1,
  1135. radioType: 'current',
  1136. formulaText: 'C1+C2+C3',
  1137. templateName: '',
  1138. templateList: [],
  1139. indicatorTableData: [],
  1140. indicatorTableHeaders: [],
  1141. selectedIndicatorsPerTemplate: {},
  1142. selectedIndicatorCodes: [],
  1143. isAutoGeneratedFormula: false,
  1144. dictTypeList: [],
  1145. }
  1146. },
  1147. watch: {
  1148. // 监听目录数据变化,数据加载完成后处理回显
  1149. catalogListOptions: {
  1150. handler(newVal) {
  1151. if (newVal && newVal.length > 0) {
  1152. // 数据加载完成后,重新处理value
  1153. this.batchGetCatalogNames()
  1154. }
  1155. },
  1156. immediate: true,
  1157. },
  1158. indicatorTableData: {
  1159. handler(newVal) {
  1160. if (this.radioType === 'other' && this.selectedTemplateId) {
  1161. this.$set(
  1162. this.selectedIndicatorsPerTemplate,
  1163. this.selectedTemplateId,
  1164. newVal.filter((item) => item.checked)
  1165. )
  1166. }
  1167. this.updateSelectedIndicatorCodes()
  1168. },
  1169. deep: true,
  1170. },
  1171. selectedIndicatorCodes: {
  1172. handler(newVal) {
  1173. if (this.radioType === 'other') {
  1174. const allSelectedTemplateIds = [
  1175. ...new Set([
  1176. this.selectedTemplateId,
  1177. ...Object.keys(this.selectedIndicatorsPerTemplate).filter(
  1178. (id) =>
  1179. id !== this.selectedTemplateId &&
  1180. this.selectedIndicatorsPerTemplate[id].some(
  1181. (item) => item.checked
  1182. )
  1183. ),
  1184. ]),
  1185. ].filter((id) => id)
  1186. const isSingleTemplate = allSelectedTemplateIds.length === 1
  1187. if (isSingleTemplate && allSelectedTemplateIds[0]) {
  1188. const selectedTemplate = this.templateList.find(
  1189. (item) => item.pkVal === allSelectedTemplateIds[0]
  1190. )
  1191. const templateNameYw = selectedTemplate
  1192. ? selectedTemplate.surveyTemplateNameYw ||
  1193. selectedTemplate.surveyTemplateName ||
  1194. ''
  1195. : ''
  1196. let selectedItems = []
  1197. if (allSelectedTemplateIds[0] === this.selectedTemplateId) {
  1198. selectedItems = newVal
  1199. } else {
  1200. selectedItems = this.selectedIndicatorsPerTemplate[
  1201. allSelectedTemplateIds[0]
  1202. ]
  1203. .filter((item) => item.checked)
  1204. .map(
  1205. (item) => `${templateNameYw}.${item.code || item.cellCode}`
  1206. )
  1207. }
  1208. if (selectedItems.length > 0) {
  1209. this.formulaText = selectedItems.join('+')
  1210. this.isAutoGeneratedFormula = true
  1211. } else if (this.isAutoGeneratedFormula) {
  1212. this.formulaText = ''
  1213. }
  1214. } else {
  1215. let allSelectedCodes = []
  1216. if (newVal.length > 0 && this.selectedTemplateId) {
  1217. allSelectedCodes = [...newVal]
  1218. }
  1219. Object.keys(this.selectedIndicatorsPerTemplate).forEach(
  1220. (templateId) => {
  1221. if (templateId !== this.selectedTemplateId) {
  1222. const items = this.selectedIndicatorsPerTemplate[templateId]
  1223. const selectedTemplate = this.templateList.find(
  1224. (item) => item.pkVal === templateId
  1225. )
  1226. const templateName = selectedTemplate
  1227. ? selectedTemplate.surveyTemplateNameYw ||
  1228. selectedTemplate.surveyTemplateName ||
  1229. ''
  1230. : ''
  1231. items
  1232. .filter((item) => item.checked)
  1233. .forEach((item) => {
  1234. allSelectedCodes.push(
  1235. `${templateName}.${item.code || item.cellCode}`
  1236. )
  1237. })
  1238. }
  1239. }
  1240. )
  1241. if (allSelectedCodes.length > 0) {
  1242. this.formulaText = allSelectedCodes.join('+')
  1243. this.isAutoGeneratedFormula = true
  1244. } else if (this.isAutoGeneratedFormula) {
  1245. this.formulaText = ''
  1246. }
  1247. }
  1248. } else if (newVal.length > 0 && this.radioType === 'current') {
  1249. if (
  1250. !this.formulaText ||
  1251. this.formulaText === 'C1+C2+C3' ||
  1252. this.isAutoGeneratedFormula
  1253. ) {
  1254. this.formulaText = newVal.join('+')
  1255. this.isAutoGeneratedFormula = true
  1256. }
  1257. } else if (newVal.length === 0 && this.radioType === 'current') {
  1258. if (this.isAutoGeneratedFormula) {
  1259. this.formulaText = ''
  1260. }
  1261. }
  1262. },
  1263. deep: true,
  1264. },
  1265. },
  1266. mounted() {
  1267. this.handleSearch()
  1268. this.loadDictTypeList()
  1269. },
  1270. methods: {
  1271. async loadDictTypeList() {
  1272. try {
  1273. const res = await getDictTypList()
  1274. this.dictTypeList = res || []
  1275. } catch (error) {
  1276. console.error('加载字典类型失败:', error)
  1277. }
  1278. },
  1279. // 获取监审类别名称
  1280. batchGetCatalogNames() {
  1281. // 递归查找名称
  1282. this.CatalogNameMap = {}
  1283. this._recursiveCatalogMap(this.catalogListOptions)
  1284. },
  1285. // 递归遍历目录树并构建ID到名称的映射
  1286. _recursiveCatalogMap(catalogs) {
  1287. if (!Array.isArray(catalogs) || catalogs.length === 0) {
  1288. return
  1289. }
  1290. catalogs.forEach((item) => {
  1291. // 为当前目录项添加映射
  1292. this.CatalogNameMap[item.id] = item.catalogName
  1293. // 递归处理子目录
  1294. if (item.children && Array.isArray(item.children)) {
  1295. this._recursiveCatalogMap(item.children)
  1296. }
  1297. })
  1298. },
  1299. // 获取所有状态为启用的成本核定表模板数据
  1300. getActiveCostVerifyFormList() {
  1301. getActiveCostVerifyFormList({
  1302. catalogId: this.contentEditForm.catalogId,
  1303. }).then((res) => {
  1304. if (res.code === 200) {
  1305. this.contentEditFormList = res.value
  1306. }
  1307. })
  1308. },
  1309. // 获取所有模板类型为固定表的所有启用成本调查表数据
  1310. getActiveCostVerifyFormListByType() {
  1311. getActiveCostVerifyFormListByType().then((res) => {
  1312. if (res.code === 200) {
  1313. this.surveyFormList = res.value
  1314. }
  1315. })
  1316. },
  1317. getCatalogNames(row) {
  1318. if (!row.catalogId) return ''
  1319. return row.catalogId
  1320. .split(',')
  1321. .map((id) => {
  1322. const trimId = id.trim()
  1323. return this.CatalogNameMap[trimId] || '未知名称'
  1324. })
  1325. .join(',')
  1326. },
  1327. // 删除成本核定表模板
  1328. handleDeleteRow(row) {
  1329. this.$confirm('确定删除该成本核定表模板吗?', '提示', {
  1330. confirmButtonText: '确定',
  1331. cancelButtonText: '取消',
  1332. type: 'warning',
  1333. }).then(() => {
  1334. deleteCostVerifyForm(row.pkVal).then((res) => {
  1335. if (res.code === 200) {
  1336. this.$message({
  1337. type: 'success',
  1338. message: '删除成功',
  1339. })
  1340. this.handleSearch()
  1341. } else {
  1342. this.$message({
  1343. type: 'error',
  1344. message: res.msg || '删除失败',
  1345. })
  1346. }
  1347. })
  1348. })
  1349. },
  1350. // 状态转换
  1351. handleStatusChange(row) {
  1352. enable({
  1353. id: row.surveyTemplateId,
  1354. }).then((res) => {
  1355. if (res.code === 200) {
  1356. this.$message.success(`${res.message}`)
  1357. this.handleSearch()
  1358. }
  1359. })
  1360. },
  1361. // 搜索
  1362. handleSearch() {
  1363. this.loading = true
  1364. getCostFormDataStorageTables(this.searchForm).then((res) => {
  1365. this.loading = false
  1366. if (res.rows.length > 0) {
  1367. this.tableData = res.rows || []
  1368. this.pagination.total = res.total || 0
  1369. }
  1370. })
  1371. },
  1372. // 重置
  1373. handleReset() {
  1374. this.searchForm = {
  1375. catalogId: '',
  1376. keyword: '',
  1377. page: 1,
  1378. pageSize: 50,
  1379. }
  1380. this.handleSearch()
  1381. },
  1382. // 添加
  1383. handleAdd() {
  1384. this.dialogTitle = '添加成本核定模板'
  1385. this.contentEditForm = {
  1386. areaCode: '',
  1387. areaLevel: '',
  1388. catalogId: '',
  1389. contentType: '',
  1390. createBy: '',
  1391. createTime: '',
  1392. createmode: '1',
  1393. createtemplateid: '',
  1394. createtemplateid1: '',
  1395. isDelete: '',
  1396. pkVal: '',
  1397. remarks: '',
  1398. status: '',
  1399. storageTable: '',
  1400. surveyTemplateId: '',
  1401. surveyTemplateName: '',
  1402. surveyTemplateNameYw: '',
  1403. templateType: '2',
  1404. type: '',
  1405. updateBy: '',
  1406. updateTime: '',
  1407. versionNo: '',
  1408. // 固定表列表
  1409. fixedTable: {
  1410. tableHeaders: [],
  1411. fixedTables: [],
  1412. fixedTablesTitle: [],
  1413. },
  1414. }
  1415. // 成本调查表模板列表
  1416. this.getActiveCostVerifyFormListByType()
  1417. this.dialogVisible = true
  1418. // 清除表单校验
  1419. this.$nextTick(() => {
  1420. if (this.$refs.contentEditForm) {
  1421. this.$refs.contentEditForm.clearValidate()
  1422. }
  1423. })
  1424. },
  1425. // 级联选择器改变时触发
  1426. handleCatalogChange(val) {
  1427. // 成本核定表模板列表
  1428. this.getActiveCostVerifyFormList()
  1429. },
  1430. // 修改
  1431. handleEdit(row) {
  1432. this.dialogTitle = '修改成本核定模板'
  1433. this.contentEditForm = {
  1434. ...row,
  1435. // 固定表列表
  1436. fixedTable: {
  1437. tableHeaders: [],
  1438. fixedTables: [],
  1439. fixedTablesTitle: [],
  1440. },
  1441. }
  1442. if (row.createmode == '1') {
  1443. this.contentEditFormcreatetemplateid = row.createtemplateid || ''
  1444. this.contentEditForm.createtemplateid1 = ''
  1445. } else if (row.createmode == '2') {
  1446. this.contentEditForm.createtemplateid1 = row.createtemplateid || ''
  1447. this.contentEditForm.createtemplateid = ''
  1448. }
  1449. // 成本核定表模板列表
  1450. this.getActiveCostVerifyFormList()
  1451. // 成本调查表模板列表
  1452. this.getActiveCostVerifyFormListByType()
  1453. this.loadTemplateDataForEdit(this.contentEditForm.surveyTemplateId)
  1454. this.dialogVisible = true
  1455. },
  1456. // 查看详情
  1457. handleViewDetail(row) {
  1458. this.dialogTitle = '查看成本核定模板'
  1459. this.contentEditForm = {
  1460. ...row,
  1461. // 固定表列表
  1462. fixedTable: {
  1463. tableHeaders: [],
  1464. fixedTables: [],
  1465. fixedTablesTitle: [],
  1466. },
  1467. }
  1468. if (row.createmode == '1') {
  1469. this.contentEditFormcreatetemplateid = row.createtemplateid || ''
  1470. this.contentEditFormcreatetemplateid1 = ''
  1471. } else if (row.createmode == '2') {
  1472. this.contentEditForm.createtemplateid1 = row.createtemplateid1 || ''
  1473. this.contentEditFormcreatetemplateid = ''
  1474. }
  1475. // 成本核定表模板列表
  1476. this.getActiveCostVerifyFormList()
  1477. // 成本调查表模板列表
  1478. this.getActiveCostVerifyFormListByType()
  1479. this.loadTemplateDataForEdit(this.contentEditForm.surveyTemplateId)
  1480. this.dialogVisible = true
  1481. },
  1482. // 生成模板
  1483. handleGenerateTemplate() {
  1484. // 提示生成后不能修改
  1485. this.$confirm(
  1486. '生成后不能修改根据调查表生成还是根据历史核定模板生成,确定生成模板吗?',
  1487. '提示',
  1488. {
  1489. confirmButtonText: '确定',
  1490. cancelButtonText: '取消',
  1491. type: 'warning',
  1492. }
  1493. ).then(() => {
  1494. // 校验表单
  1495. this.$refs['contentEditForm'].validate((valid) => {
  1496. if (valid) {
  1497. if (this.contentEditForm.createmode == '1') {
  1498. if (!this.contentEditForm.createtemplateid) {
  1499. this.$message.error('请选择成本调查表模板')
  1500. return
  1501. }
  1502. this.generateFromSurveyTemplate()
  1503. } else if (this.contentEditForm.createmode == '2') {
  1504. if (!this.contentEditForm.createtemplateid1) {
  1505. this.$message.error('请选择历史核定模板')
  1506. return
  1507. }
  1508. this.generateFromHistoryTemplate()
  1509. }
  1510. } else {
  1511. this.$message.error('请填写表单数据')
  1512. return
  1513. }
  1514. })
  1515. })
  1516. },
  1517. async loadTemplateDataForEdit(surveyTemplateId) {
  1518. // 并行获取表头和表格数据
  1519. const [tableHeadersRes, tableDataRes] = await Promise.all([
  1520. getlistBySurveyTemplateId({
  1521. surveyTemplateId,
  1522. }),
  1523. getCostFormVersionsByTemplateId({
  1524. surveyTemplateId,
  1525. }),
  1526. ])
  1527. // 处理表头数据
  1528. if (tableHeadersRes.code == 200) {
  1529. this.contentEditForm.fixedTable.tableHeaders = Array.isArray(
  1530. tableHeadersRes.value
  1531. )
  1532. ? tableHeadersRes.value
  1533. : []
  1534. // 表头按照orderNum重新排序
  1535. this.contentEditForm.fixedTable.tableHeaders.sort(
  1536. (a, b) => a.orderNum - b.orderNum
  1537. )
  1538. // 检查是否有fieldName为"序号"的数据
  1539. const hasSerialNumber =
  1540. this.contentEditForm.fixedTable.tableHeaders.some(
  1541. (header) => header.fieldName === '序号'
  1542. )
  1543. // 如果没有序号数据,则添加一条默认的序号数据,并标记为不可编辑
  1544. if (!hasSerialNumber) {
  1545. this.contentEditForm.fixedTable.tableHeaders.unshift({
  1546. fieldName: '序号',
  1547. fieldType: 'string',
  1548. format: '30',
  1549. fieldTypelen: '',
  1550. fieldTypenointlen: '',
  1551. isRequired: 'false',
  1552. showVisible: '1',
  1553. isAuditPeriod: 'false',
  1554. tabtype: '2',
  1555. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  1556. versionId: this.versionId,
  1557. isFixed: '1',
  1558. isReadOnly: true, // 标记为不可编辑
  1559. orderNum: 1,
  1560. })
  1561. } else {
  1562. this.contentEditForm.fixedTable.tableHeaders.forEach((item) => {
  1563. if (item.fieldName === '序号') {
  1564. item.isReadOnly = true // 确保序号字段不可编辑
  1565. }
  1566. })
  1567. }
  1568. }
  1569. // 处理表格数据
  1570. if (tableDataRes.code == 200) {
  1571. this.parseAndDisplayFixedTableData(tableDataRes)
  1572. }
  1573. },
  1574. // 根据调查表生成模板
  1575. async generateFromSurveyTemplate() {
  1576. try {
  1577. // 显示加载状态
  1578. this.loading = true
  1579. // 保存模板基本信息
  1580. let data = await generateCostVerifyForm({
  1581. catalogId: this.contentEditForm.catalogId,
  1582. templatename: this.contentEditForm.surveyTemplateName,
  1583. templateId: this.contentEditForm.createtemplateid,
  1584. })
  1585. this.contentEditForm.surveyTemplateId = data.value
  1586. ? data.value.surveyTemplateId
  1587. : ''
  1588. this.loadTemplateDataForEdit(this.contentEditForm.surveyTemplateId)
  1589. // // 并行获取表头和表格数据
  1590. // const [tableHeadersRes, tableDataRes] = await Promise.all([
  1591. // getlistBySurveyTemplateIdcurrentversion({
  1592. // surveyTemplateId: this.contentEditForm.createtemplateid,
  1593. // }),
  1594. // listByCurrentTemplateId({
  1595. // surveyTemplateId: this.contentEditForm.createtemplateid,
  1596. // }),
  1597. // ])
  1598. // // 处理表头数据
  1599. // if (tableHeadersRes.code == 200) {
  1600. // this.contentEditForm.fixedTable.tableHeaders = Array.isArray(
  1601. // tableHeadersRes.value
  1602. // )
  1603. // ? tableHeadersRes.value
  1604. // : []
  1605. // }
  1606. // // 处理表格数据
  1607. // if (tableDataRes.code == 200) {
  1608. // const fieldNamesString =
  1609. // this.contentEditForm.fixedTable.tableHeaders
  1610. // .map((header) => header.fieldName)
  1611. // .join(', ')
  1612. // this.contentEditForm.fixedTable.fixedTablesTitle = fieldNamesString
  1613. // this.parseAndDisplayFixedTableData(tableDataRes)
  1614. // // this.$message.success('生成模板成功')
  1615. // }
  1616. } catch (error) {
  1617. console.error('生成模板失败:', error)
  1618. } finally {
  1619. this.loading = false
  1620. }
  1621. },
  1622. // 根据历史核定模板生成
  1623. async generateFromHistoryTemplate() {
  1624. // 保存模板基本信息
  1625. let data = await generateCostVerifyFormData({
  1626. catalogId: this.contentEditForm.catalogId,
  1627. templatename: this.contentEditForm.surveyTemplateName,
  1628. templateId: this.contentEditForm.createtemplateid1,
  1629. })
  1630. this.contentEditForm.surveyTemplateId = data.value
  1631. ? data.value.surveyTemplateId
  1632. : ''
  1633. this.loadTemplateDataForEdit(this.contentEditForm.surveyTemplateId)
  1634. },
  1635. // 添加表头
  1636. handleAddTableHeader(type) {
  1637. switch (type) {
  1638. case '固定表表头':
  1639. this.contentEditForm.fixedTable.tableHeaders.push({
  1640. fieldName: '',
  1641. fieldType: 'string',
  1642. format: '255',
  1643. fieldTypelen: '',
  1644. fieldTypenointlen: '',
  1645. isRequired: 'false',
  1646. showVisible: '1',
  1647. isAuditPeriod: 'false',
  1648. tabtype: '2',
  1649. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  1650. versionId: this.versionId,
  1651. orderNum: this.contentEditForm.fixedTable.tableHeaders.length + 1,
  1652. })
  1653. break
  1654. case '固定表项目':
  1655. let maxFixedOrderNum = 0
  1656. if (this.contentEditForm.fixedTable.fixedTables.length > 0) {
  1657. maxFixedOrderNum = Math.max(
  1658. ...this.contentEditForm.fixedTable.fixedTables.map(
  1659. (item) => item.orderNum || 0
  1660. )
  1661. )
  1662. }
  1663. const newRow = {
  1664. orderText: maxFixedOrderNum + 1,
  1665. orderNum: maxFixedOrderNum + 1,
  1666. cellCode: '',
  1667. calculationFormula: '',
  1668. unit: '',
  1669. tabtype: this.contentEditForm.templateType,
  1670. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  1671. versionId: this.versionId,
  1672. fixedValues: {},
  1673. parentid: -1,
  1674. rowid: this.generateUUID(),
  1675. }
  1676. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  1677. (title) => {
  1678. newRow.fixedValues[title.rkey] = ''
  1679. }
  1680. )
  1681. this.contentEditForm.fixedTable.fixedTables.push(newRow)
  1682. break
  1683. default:
  1684. break
  1685. }
  1686. },
  1687. // 字段名称改变
  1688. handleFieldNameChange(row) {
  1689. console.log(row)
  1690. if (row.fieldName) {
  1691. // 检查是否已存在相同的fieldName
  1692. const existsInTableHeaders =
  1693. this.contentEditForm.fixedTable.tableHeaders.some(
  1694. (item) => item.fieldName === row.fieldName
  1695. )
  1696. // 跳过"序号"列
  1697. if (row.fieldName !== '序号' && !existsInTableHeaders) {
  1698. // 更新tableHeaders数组,这是关键的数据源
  1699. this.contentEditForm.fixedTable.tableHeaders.push({
  1700. fieldName: row.fieldName,
  1701. fieldType: 'string',
  1702. format: '255',
  1703. fieldTypelen: '',
  1704. fieldTypenointlen: '',
  1705. isRequired: 'false',
  1706. showVisible: '1',
  1707. isAuditPeriod: 'false',
  1708. tabtype: '2',
  1709. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  1710. versionId: this.versionId || null,
  1711. orderNum: this.contentEditForm.fixedTable.tableHeaders.length + 1,
  1712. id: null,
  1713. })
  1714. // 同时更新fixedTablesTitle(这是源头数据)
  1715. const newTitle = {
  1716. rkey: row.fieldName,
  1717. rvalue: '',
  1718. }
  1719. this.contentEditForm.fixedTable.fixedTablesTitle.push(newTitle)
  1720. // 同时更新fixedTableHeaders
  1721. this.contentEditForm.fixedTable.fixedTableHeaders.push(newTitle)
  1722. // 为现有表格数据行添加对应的fixedValues属性
  1723. if (
  1724. this.contentEditForm.fixedTable.fixedTables &&
  1725. this.contentEditForm.fixedTable.fixedTables.length > 0
  1726. ) {
  1727. this.contentEditForm.fixedTable.fixedTables.forEach(
  1728. (tableRow) => {
  1729. // 确保fixedValues对象存在
  1730. if (!tableRow.fixedValues) {
  1731. tableRow.fixedValues = {}
  1732. }
  1733. // 为新字段设置默认值为空字符串
  1734. tableRow.fixedValues[row.fieldName] = ''
  1735. }
  1736. )
  1737. }
  1738. }
  1739. }
  1740. },
  1741. // 保存内容
  1742. handleSaveContent(type) {
  1743. try {
  1744. if (type === '固定表表头') {
  1745. var data = {
  1746. headersList: this.contentEditForm.fixedTable.tableHeaders,
  1747. }
  1748. batchSaveOrUpdate(data)
  1749. .then((res) => {
  1750. if (res.code === 200) {
  1751. // 如果后端返回了保存后的数据,更新本地数据
  1752. if (res.value && Array.isArray(res.value)) {
  1753. this.contentEditForm.fixedTable.tableHeaders =
  1754. res.value.map((item) => ({
  1755. ...item,
  1756. }))
  1757. }
  1758. this.loadTemplateDataForEdit(
  1759. this.contentEditForm.surveyTemplateId
  1760. )
  1761. this.contentEditForm.fixedTable.fixedTables.forEach((row) => {
  1762. this.initFixedTableRow(row)
  1763. })
  1764. }
  1765. })
  1766. .catch((error) => {
  1767. console.error('保存接口异常:', error)
  1768. })
  1769. .finally(() => {
  1770. this.loading = false
  1771. })
  1772. }
  1773. } catch (error) {
  1774. console.error('保存处理异常:', error)
  1775. }
  1776. },
  1777. initFixedTableRow(row) {
  1778. if (row.cellCode === undefined) {
  1779. this.$set(row, 'cellCode', '')
  1780. }
  1781. if (row.calculationFormula === undefined) {
  1782. this.$set(row, 'calculationFormula', '')
  1783. }
  1784. if (row.unit === undefined) {
  1785. this.$set(row, 'unit', '')
  1786. }
  1787. if (!row.fixedValues) {
  1788. this.$set(row, 'fixedValues', {})
  1789. }
  1790. // 初始化children数组,支持树形结构
  1791. if (!row.children) {
  1792. this.$set(row, 'children', [])
  1793. }
  1794. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  1795. (title, index) => {
  1796. if (!(title.rkey in row.fixedValues)) {
  1797. this.$set(row.fixedValues, title.rkey, '')
  1798. }
  1799. }
  1800. )
  1801. return row
  1802. },
  1803. // 删除表头
  1804. handleDeleteHeader(index, type, row) {
  1805. // 提取重复的删除逻辑为内部函数
  1806. const handleDelete = () => {
  1807. const data = {
  1808. deleteheadersList: [row],
  1809. }
  1810. batchSaveOrUpdate(data)
  1811. .then((res) => {
  1812. if (res.code === 200) {
  1813. this.$message.success('删除成功')
  1814. } else {
  1815. this.$message.error(`删除失败:${res.message || '未知错误'}`)
  1816. }
  1817. })
  1818. .catch((error) => {
  1819. console.error('删除接口异常:', error)
  1820. // this.$message.error('删除接口异常,请重试')
  1821. })
  1822. .finally(() => {})
  1823. }
  1824. switch (type) {
  1825. case '固定表表头':
  1826. if (this.contentEditForm.fixedTable.tableHeaders.length <= 1) {
  1827. this.$message.warning('至少保留一个表头')
  1828. return
  1829. }
  1830. this.contentEditForm.fixedTable.tableHeaders.splice(index, 1)
  1831. let fixedFields = this.contentEditForm.fixedTable.tableHeaders
  1832. .map((item) => item.fieldName)
  1833. .join(',')
  1834. this.contentEditForm.fixedTable.fixedTablesTitle =
  1835. this.stringToObjects(fixedFields || '')
  1836. this.contentEditForm.fixedTable.fixedTableHeaders =
  1837. this.contentEditForm.fixedTable.fixedTablesTitle.filter(
  1838. (title) => title.rkey !== '序号'
  1839. )
  1840. handleDelete()
  1841. // 重新排序
  1842. this.updateTableHeadersOrderNumbers()
  1843. break
  1844. case '固定表项目':
  1845. this.$confirm(
  1846. '确定要删除此行数据吗?如果删除的是父项,将同时删除其所有子项。',
  1847. '确认删除',
  1848. {
  1849. confirmButtonText: '确定',
  1850. cancelButtonText: '取消',
  1851. type: 'warning',
  1852. }
  1853. )
  1854. .then(() => {
  1855. // 检查是否是删除子项
  1856. const isChildItem = row.isChild || row.isSubItem || false
  1857. if (isChildItem) {
  1858. // 查找父项
  1859. const parentItem =
  1860. this.contentEditForm.fixedTable.fixedTables.find(
  1861. (item) =>
  1862. item.children &&
  1863. item.children.some((child) => child.rowid === row.rowid)
  1864. )
  1865. if (parentItem && parentItem.children) {
  1866. // 从父项的children数组中删除子项
  1867. const childIndex = parentItem.children.findIndex(
  1868. (child) => child.rowid === row.rowid
  1869. )
  1870. if (childIndex > -1) {
  1871. parentItem.children.splice(childIndex, 1)
  1872. // 如果children数组为空,将hasChildren设为false
  1873. if (parentItem.children.length === 0) {
  1874. this.$set(parentItem, 'hasChildren', false)
  1875. } else {
  1876. // 重新计算子项序号
  1877. parentItem.children.forEach((child, idx) => {
  1878. child.orderText = idx + 1
  1879. child.orderNum = idx + 1
  1880. })
  1881. }
  1882. // 确保Vue响应式系统检测到变化
  1883. const children = [...parentItem.children]
  1884. this.$set(parentItem, 'children', children)
  1885. this.handleSaveContent('固定表项目', 'delete') // 保存数据
  1886. }
  1887. }
  1888. } else {
  1889. // 处理删除父项的情况
  1890. if (this.contentEditForm.fixedTable.fixedTables.length <= 1) {
  1891. this.$message.warning('至少保留一个项目')
  1892. return
  1893. }
  1894. // 获取要删除的行
  1895. index =
  1896. this.contentEditForm.fixedTable.fixedTables.indexOf(row)
  1897. const rowToDelete =
  1898. this.contentEditForm.fixedTable.fixedTables[index]
  1899. // 先删除所有子项(parentid等于当前行的rowid或itemId的项)
  1900. // 从后往前删除,避免索引偏移
  1901. const rowsToDelete = []
  1902. // 找出所有需要删除的行(包括父项和子项)
  1903. for (
  1904. let i = 0;
  1905. i < this.contentEditForm.fixedTable.fixedTables.length;
  1906. i++
  1907. ) {
  1908. const currentRow =
  1909. this.contentEditForm.fixedTable.fixedTables[i]
  1910. // 是当前行或其子项(子项的parentid等于当前行的rowid或itemId)
  1911. if (
  1912. i === index ||
  1913. (currentRow.parentid &&
  1914. (currentRow.parentid === rowToDelete.rowid ||
  1915. currentRow.parentid === rowToDelete.itemId))
  1916. ) {
  1917. rowsToDelete.push(i)
  1918. }
  1919. }
  1920. // 从后往前删除,避免索引偏移
  1921. for (let i = rowsToDelete.length - 1; i >= 0; i--) {
  1922. this.contentEditForm.fixedTable.fixedTables.splice(
  1923. rowsToDelete[i],
  1924. 1
  1925. )
  1926. }
  1927. this.handleSaveContent('固定表项目', 'delete') // 保存数据
  1928. }
  1929. })
  1930. .catch(() => {})
  1931. break
  1932. default:
  1933. break
  1934. }
  1935. },
  1936. /**
  1937. * 处理固定表项目字段值变化
  1938. */
  1939. handleFixedValueChange(row, rkey, value) {
  1940. if (!row.fixedValues) {
  1941. this.$set(row, 'fixedValues', {})
  1942. }
  1943. this.$set(row.fixedValues, rkey, value)
  1944. },
  1945. // 上升
  1946. handleMoveUp(index, tableType, row) {
  1947. if (tableType === '固定表') {
  1948. const fixedTableData = this.contentEditForm.fixedTable.fixedTables
  1949. const newFixedTableData = [...fixedTableData]
  1950. this.swamTableArr(newFixedTableData, row, true)
  1951. this.contentEditForm.fixedTable.fixedTables = newFixedTableData
  1952. } else {
  1953. // const tableHeaders = this.contentEditForm.fixedTable.tableHeaders
  1954. // const newTableHeaders = [...tableHeaders]
  1955. // this.swamTableArr(newTableHeaders, row, true, true)
  1956. // this.contentEditForm.tableHeaders = newTableHeaders
  1957. if (index > 0) {
  1958. const temp = this.contentEditForm.fixedTable.tableHeaders[index]
  1959. this.contentEditForm.fixedTable.tableHeaders.splice(index, 1)
  1960. this.contentEditForm.fixedTable.tableHeaders.splice(
  1961. index - 1,
  1962. 0,
  1963. temp
  1964. )
  1965. // 更新表头的序号
  1966. this.updateTableHeadersOrderNumbers()
  1967. }
  1968. }
  1969. },
  1970. // 下降
  1971. handleMoveDown(index, tableType, row) {
  1972. if (tableType === '固定表') {
  1973. const fixedTableData = this.contentEditForm.fixedTable.fixedTables
  1974. const newFixedTableData = [...fixedTableData]
  1975. this.swamTableArr(newFixedTableData, row, false)
  1976. this.contentEditForm.fixedTable.fixedTables = newFixedTableData
  1977. } else {
  1978. // const tableHeaders = this.contentEditForm.tableHeaders
  1979. // const newTableHeaders = [...tableHeaders]
  1980. // this.swamTableArr(newTableHeaders, row, false)
  1981. // this.contentEditForm.tableHeaders = newTableHeaders
  1982. if (index < this.contentEditForm.fixedTable.tableHeaders.length - 1) {
  1983. const temp = this.contentEditForm.fixedTable.tableHeaders[index]
  1984. this.contentEditForm.fixedTable.tableHeaders.splice(index, 1)
  1985. this.contentEditForm.fixedTable.tableHeaders.splice(
  1986. index + 1,
  1987. 0,
  1988. temp
  1989. )
  1990. // 更新表头的序号
  1991. this.updateTableHeadersOrderNumbers()
  1992. }
  1993. }
  1994. },
  1995. swamTableArr(arr, row, asc, isHeader) {
  1996. const isChild = row.isChild || row.isSubItem || false
  1997. if (isChild) {
  1998. // 子节点处理逻辑后续实现 parentid rowid
  1999. let child = arr.find((item) => item.rowid === row.parentid)
  2000. // const rowIndex = arr.indexOf(row);
  2001. // newFixedTableData[rowIndex]
  2002. this.doSwamTableArr(child.children, row, asc, isHeader)
  2003. } else {
  2004. // 创建数组副本以确保Vue能检测到变化
  2005. // 直接替换整个数组,确保Vue能检测到变化
  2006. this.doSwamTableArr(arr, row, asc, isHeader)
  2007. }
  2008. },
  2009. doSwamTableArr(arr, row, asc, isHeader) {
  2010. const rowIndex = arr.indexOf(row)
  2011. let swamIndex = 0
  2012. if (asc) {
  2013. // 正序
  2014. if (rowIndex < 1) {
  2015. return
  2016. }
  2017. swamIndex = rowIndex - 1
  2018. } else {
  2019. // 倒序
  2020. if (rowIndex >= arr.length - 1) {
  2021. return
  2022. }
  2023. swamIndex = rowIndex + 1
  2024. }
  2025. const curr = arr[rowIndex]
  2026. const swam = arr[swamIndex]
  2027. // 交换orderNum
  2028. const tempOrderNum = curr.orderNum
  2029. curr.orderNum = swam.orderNum
  2030. swam.orderNum = tempOrderNum
  2031. // row.isChild &&
  2032. if (!isHeader) {
  2033. // 获取当前项的序号值
  2034. let currIndex = curr.fixedValues
  2035. ? curr.fixedValues['序号']
  2036. : curr.dynamicValues['序号']
  2037. // 获取交换项的序号值
  2038. let swamIndex = swam.fixedValues
  2039. ? swam.fixedValues['序号']
  2040. : swam.dynamicValues['序号']
  2041. // 先保存交换项的值,再进行赋值,避免值被覆盖
  2042. if (curr.fixedValues) {
  2043. curr.fixedValues['序号'] = swamIndex
  2044. } else {
  2045. curr.dynamicValues['序号'] = swamIndex
  2046. }
  2047. if (swam.fixedValues) {
  2048. swam.fixedValues['序号'] = currIndex
  2049. } else {
  2050. swam.dynamicValues['序号'] = currIndex
  2051. }
  2052. }
  2053. // 交换数组中的位置
  2054. arr[rowIndex] = swam
  2055. arr[swamIndex] = curr
  2056. },
  2057. // 更新表头序号
  2058. updateTableHeadersOrderNumbers() {
  2059. // 更新固定表的表头序号
  2060. if (
  2061. this.contentEditForm.fixedTable &&
  2062. this.contentEditForm.fixedTable.tableHeaders
  2063. ) {
  2064. this.contentEditForm.fixedTable.tableHeaders.forEach(
  2065. (header, index) => {
  2066. header.orderNum = index + 1
  2067. }
  2068. )
  2069. }
  2070. },
  2071. // 添加子项方法
  2072. handleAddChildItem(index, type, parentRow) {
  2073. if (!parentRow.rowid) {
  2074. this.$set(parentRow, 'rowid', this.generateUUID())
  2075. }
  2076. switch (type) {
  2077. case '固定表项目':
  2078. let parentIndex1 =
  2079. this.contentEditForm.fixedTable.fixedTables.findIndex(
  2080. (item) => item.rowid == parentRow.rowid
  2081. )
  2082. if (
  2083. !this.contentEditForm.fixedTable.fixedTables[parentIndex1]
  2084. .children
  2085. ) {
  2086. this.$set(
  2087. this.contentEditForm.fixedTable.fixedTables[parentIndex1],
  2088. 'children',
  2089. []
  2090. )
  2091. }
  2092. let childOrderNum =
  2093. this.contentEditForm.fixedTable.fixedTables[parentIndex1].children
  2094. .length + 1
  2095. let fixedValues = {
  2096. ...parentRow.fixedValues,
  2097. }
  2098. for (const key in fixedValues) {
  2099. if (key == '序号') {
  2100. fixedValues[key] = childOrderNum
  2101. } else {
  2102. fixedValues[key] = ''
  2103. }
  2104. }
  2105. const fixedNewRow = {
  2106. orderText: this.contentEditForm.fixedTable.fixedTables.length + 1,
  2107. orderNum: this.contentEditForm.fixedTable.fixedTables.length + 1,
  2108. cellCode: '',
  2109. calculationFormula: '',
  2110. unit: '',
  2111. tabtype: this.contentEditForm.templateType,
  2112. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  2113. versionId: this.versionId,
  2114. fixedValues: fixedValues,
  2115. parentid: parentRow.rowid,
  2116. isChild: true,
  2117. isSubItem: true,
  2118. rowid: this.generateUUID(),
  2119. }
  2120. this.contentEditForm.fixedTable.fixedTablesTitle.forEach(
  2121. (title) => {
  2122. if (!(title.rkey in fixedNewRow.fixedValues)) {
  2123. fixedNewRow.fixedValues[title.rkey] = ''
  2124. }
  2125. }
  2126. )
  2127. this.contentEditForm.fixedTable.fixedTables[
  2128. parentIndex1
  2129. ].children.push(fixedNewRow)
  2130. // this.contentEditForm.fixedTable.fixedTables.splice(
  2131. // index + 1,
  2132. // 0,
  2133. // fixedNewRow
  2134. // )
  2135. break
  2136. }
  2137. this.$nextTick(() => {
  2138. const tableBody = document.querySelector('.el-table__body-wrapper')
  2139. if (tableBody) {
  2140. tableBody.scrollTop = tableBody.scrollHeight
  2141. }
  2142. })
  2143. },
  2144. handleCreateModeChange() {
  2145. if (this.contentEditForm.createmode == 1) {
  2146. this.contentEditForm.createtemplateid1 = ''
  2147. } else if (this.contentEditForm.createmode == 2) {
  2148. this.contentEditForm.createtemplateid = ''
  2149. }
  2150. },
  2151. openCalculationFormulaDialogVisible(row, index) {
  2152. this.currentEditingRow = row
  2153. this.currentEditingRowIndex = index
  2154. this.calculationFormulaDialogVisible = true
  2155. this.formulaText = row.calculationFormula || ''
  2156. this.selectedTemplateId = '' // 重置选中的模板
  2157. this.indicatorTableData = [] // 清空指标数据
  2158. this.getListFixedEnabled()
  2159. },
  2160. getListFixedEnabled() {
  2161. getListFixedEnabled({
  2162. surveyTemplateId: this.contentEditForm.surveyTemplateId,
  2163. }).then((res) => {
  2164. this.templateList = res.value
  2165. })
  2166. },
  2167. // 处理模板选择变化
  2168. handleTemplateChange(templateId) {
  2169. if (templateId) {
  2170. // 根据选中的模板ID查找对应的surveyTemplateId
  2171. const selectedTemplate = this.templateList.find(
  2172. (item) => item.pkVal === templateId
  2173. )
  2174. if (selectedTemplate && selectedTemplate.surveyTemplateId) {
  2175. this.getCellCodesByTemplateId(selectedTemplate.surveyTemplateId)
  2176. } else {
  2177. this.indicatorTableData = []
  2178. }
  2179. } else {
  2180. this.indicatorTableData = []
  2181. }
  2182. // 恢复该模板之前选中的指标项
  2183. this.$nextTick(() => {
  2184. if (this.selectedIndicatorsPerTemplate[templateId]) {
  2185. this.indicatorTableData.forEach((item) => {
  2186. const isSelected = this.selectedIndicatorsPerTemplate[
  2187. templateId
  2188. ].some((selectedItem) => selectedItem.code === item.code)
  2189. this.$set(item, 'checked', isSelected)
  2190. if (isSelected) {
  2191. this.formatRowCode(item)
  2192. }
  2193. })
  2194. }
  2195. // 更新选中的指标代码列表
  2196. this.updateSelectedIndicatorCodes()
  2197. })
  2198. },
  2199. getCellCodesByTemplateId(surveyTemplateId) {
  2200. listByVerifyTemplateId({
  2201. surveyTemplateId: surveyTemplateId,
  2202. })
  2203. .then((res) => {
  2204. // 将返回的数据转换为表格需要的格式
  2205. if (res.value && Array.isArray(res.value.itemlist)) {
  2206. let fixedTablesTitle = this.stringToObjects(
  2207. res.value.fixedFields || ''
  2208. )
  2209. this.indicatorTableHeaders = fixedTablesTitle
  2210. this.indicatorTableData = res.value.itemlist.map((item) => ({
  2211. ...item,
  2212. checked: false,
  2213. cellCode: item.cellCode || '',
  2214. name: res.value.fixedFields.split(',')[0] || '',
  2215. formattedCode: '', // 添加格式化代码字段
  2216. }))
  2217. } else {
  2218. this.indicatorTableData = []
  2219. }
  2220. })
  2221. .catch((error) => {
  2222. console.error('获取指标数据失败:', error)
  2223. this.indicatorTableData = []
  2224. })
  2225. },
  2226. updateSelectedIndicatorCodes() {
  2227. // 获取当前选中的行
  2228. const selectedRows = this.indicatorTableData.filter(
  2229. (item) => item.checked
  2230. )
  2231. // 更新选中的指标代码列表
  2232. this.selectedIndicatorCodes = selectedRows.map((item) => {
  2233. // 获取选中的模板信息
  2234. const selectedTemplate = this.templateList.find(
  2235. (template) => template.pkVal === this.selectedTemplateId
  2236. )
  2237. // 获取模板的 surveyTemplateNameYw
  2238. const templateName = selectedTemplate
  2239. ? selectedTemplate.surveyTemplateNameYw ||
  2240. selectedTemplate.surveyTemplateName ||
  2241. ''
  2242. : ''
  2243. return templateName
  2244. ? `${templateName}.${item.code || item.cellCode || ''}`
  2245. : item.code || item.cellCode || ''
  2246. })
  2247. },
  2248. formatRowCode(row) {
  2249. const selectedTemplate = this.templateList.find(
  2250. (item) => item.pkVal === this.selectedTemplateId
  2251. )
  2252. const surveyTemplateNameYw = selectedTemplate
  2253. ? selectedTemplate.surveyTemplateNameYw ||
  2254. selectedTemplate.surveyTemplateName ||
  2255. ''
  2256. : ''
  2257. const formattedCode = surveyTemplateNameYw
  2258. ? `${surveyTemplateNameYw}.${row.code || row.cellCode || ''}`
  2259. : row.code || row.cellCode || ''
  2260. this.$set(row, 'formattedCode', formattedCode)
  2261. const templateCode = surveyTemplateNameYw
  2262. ? `${surveyTemplateNameYw}_${row.code || row.cellCode || ''}`
  2263. : row.code || row.cellCode || ''
  2264. this.$set(
  2265. row,
  2266. 'jsonStr',
  2267. JSON.stringify([
  2268. {
  2269. [templateCode]: this.selectedTemplateId,
  2270. },
  2271. ])
  2272. )
  2273. },
  2274. handleRowClick(row, column, event) {
  2275. // 只有点击非 checkbox 列才触发
  2276. if (column && column.property !== 'checked') {
  2277. // 如果没有 cellCode,则不允许选中
  2278. if (!row.cellCode) {
  2279. // this.$message.warning('该数据没有指标编号,无法选择')
  2280. return
  2281. }
  2282. // 切换选中状态
  2283. this.toggleRowSelection(row)
  2284. }
  2285. },
  2286. toggleRowSelection(row) {
  2287. // 切换选中状态
  2288. this.$set(row, 'checked', !row.checked)
  2289. // 格式化代码并存储在行数据中
  2290. if (row.checked) {
  2291. this.formatRowCode(row)
  2292. }
  2293. // 触发选中状态更新
  2294. this.$forceUpdate()
  2295. },
  2296. selectionIndicatorChange(val) {
  2297. this.indicatorTableData.forEach((item) => {
  2298. item.checked = val.includes(item)
  2299. })
  2300. },
  2301. handleCheckboxChange(row) {
  2302. // 如果没有 cellCode,则不允许选中
  2303. if (!row.cellCode) {
  2304. this.$message.warning('该数据没有指标编号,无法选择')
  2305. this.$set(row, 'checked', false)
  2306. return
  2307. }
  2308. this.$set(row, 'checked', !row.checked)
  2309. if (row.checked) {
  2310. this.formatRowCode(row)
  2311. }
  2312. this.updateSelectedIndicatorCodes()
  2313. this.$forceUpdate()
  2314. },
  2315. handleFormulaTextChange(value) {
  2316. // 当用户手动修改公式文本时,标记为非自动生成
  2317. this.isAutoGeneratedFormula = false
  2318. },
  2319. handleDialogClose(done) {
  2320. this.selectedIndicatorsPerTemplate = {}
  2321. done()
  2322. },
  2323. handleRadioChange(value) {
  2324. this.formulaText = ''
  2325. },
  2326. handleConfirm() {
  2327. const result = {
  2328. type: this.radioType,
  2329. formula: this.formulaText,
  2330. selectedTemplate: this.selectedTemplateId,
  2331. selectedItems: this.indicatorTableData.filter((item) => item.checked),
  2332. }
  2333. let _data = []
  2334. if (this.radioType == 'current') {
  2335. // 使用递归函数扁平化树形结构
  2336. const flattenTree = (nodes) => {
  2337. let result = []
  2338. nodes.forEach((node) => {
  2339. result.push(node)
  2340. if (node.children && node.children.length > 0) {
  2341. result = result.concat(flattenTree(node.children))
  2342. }
  2343. })
  2344. return result
  2345. }
  2346. // 扁平化数据并提取cellCode
  2347. _data = flattenTree(this.contentEditForm.fixedTable.fixedTables)
  2348. .filter((item) => item.cellCode)
  2349. .map((item) => item.cellCode)
  2350. } else if (this.radioType == 'other') {
  2351. if (!result.selectedTemplate) {
  2352. this.$message.error('请选择指标编号')
  2353. return
  2354. }
  2355. _data = this.indicatorTableData
  2356. .filter((item) => item.cellCode)
  2357. .map((item) => item.cellCode)
  2358. }
  2359. if (!this.validateFormula(this.formulaText, _data).valid) {
  2360. this.$message.error(
  2361. this.validateFormula(this.formulaText, _data).errorMsg
  2362. )
  2363. return
  2364. }
  2365. // 生成 jsonstr 字段
  2366. const jsonStrArray = this.indicatorTableData
  2367. .filter((item) => item.checked)
  2368. .map((item) => {
  2369. if (item.jsonStr) {
  2370. try {
  2371. return JSON.parse(item.jsonStr)[0]
  2372. } catch (e) {
  2373. console.error('解析 jsonStr 失败:', e)
  2374. return {}
  2375. }
  2376. }
  2377. return {}
  2378. })
  2379. .filter((item) => Object.keys(item).length > 0)
  2380. const jsonstr = JSON.stringify(jsonStrArray)
  2381. // 更新当前编辑行的计算公式值
  2382. if (this.currentEditingRow) {
  2383. this.$set(
  2384. this.currentEditingRow,
  2385. 'calculationFormula',
  2386. this.formulaText
  2387. )
  2388. this.$set(this.currentEditingRow, 'jsonstr', jsonstr)
  2389. }
  2390. console.log('点击了确定,获取到的数据:', {
  2391. ...result,
  2392. jsonstr: jsonstr,
  2393. })
  2394. // 清空当前操作的状态
  2395. this.calculationFormulaDialogVisible = false
  2396. this.currentEditingRow = null
  2397. this.currentEditingRowIndex = -1
  2398. this.isAutoGeneratedFormula = false
  2399. this.selectedTemplateId = ''
  2400. this.indicatorTableData = []
  2401. this.selectedIndicatorsPerTemplate = {} // 清空模板选中记录
  2402. },
  2403. /**
  2404. * 解析并回显固定表项目数据
  2405. * @param {Object} responseData - listByCurrentTemplateId接口返回的数据
  2406. */
  2407. parseAndDisplayFixedTableData(responseData) {
  2408. // if (responseData.value.fixedFields) {
  2409. // this.contentEditForm.fixedTable.fixedTablesTitle =
  2410. // this.stringToObjects(responseData.value.fixedFields || '')
  2411. // } else {
  2412. // let fixedFields = this.contentEditForm.fixedTable.tableHeaders
  2413. // .map((item) => item.fieldName)
  2414. // .join(',')
  2415. // this.contentEditForm.fixedTable.fixedTablesTitle =
  2416. // this.stringToObjects(fixedFields || '')
  2417. // }
  2418. let fixedFields = this.contentEditForm.fixedTable.tableHeaders
  2419. .map((item) => item.fieldName)
  2420. .join(',')
  2421. this.contentEditForm.fixedTable.fixedTablesTitle = this.stringToObjects(
  2422. fixedFields || ''
  2423. )
  2424. const fixedTitles = this.contentEditForm.fixedTable.fixedTablesTitle
  2425. this.contentEditForm.fixedTable.fixedTableHeaders = fixedTitles.filter(
  2426. (title) => title.rkey !== '序号'
  2427. )
  2428. if (
  2429. !responseData ||
  2430. !responseData.value ||
  2431. !responseData.value.itemlist
  2432. ) {
  2433. return
  2434. }
  2435. const itemList = responseData.value.itemlist
  2436. const allRows = []
  2437. const rowMap = new Map()
  2438. // 清空现有数据
  2439. this.contentEditForm.fixedTable.fixedTables = []
  2440. // 遍历itemList,为每个项目创建一行数据
  2441. itemList.forEach((item, index) => {
  2442. // 判断是否为子项(parentid不为-1且不为"-1")
  2443. const isSubItem =
  2444. item.parentid && item.parentid !== -1 && item.parentid !== '-1'
  2445. const newRow = {
  2446. orderText: item.orderNum || '', // 显示用序号
  2447. orderNum: item.orderNum || '', // 保留原始序号用于发送后端
  2448. surveyTemplateId: item.surveyTemplateId,
  2449. versionId: item.versionId,
  2450. cellCode: item.cellCode || '',
  2451. calculationFormula: item.calculationFormula || '',
  2452. unit: item.unit || '',
  2453. fixedValues: {},
  2454. itemId: item.id || null,
  2455. parentid: item.parentid || -1,
  2456. isChild: isSubItem,
  2457. isSubItem: isSubItem,
  2458. rowid: item.rowid || this.generateUUID(),
  2459. jsonstr: item.jsonstr || null,
  2460. children: [], // 添加children数组用于树形结构
  2461. }
  2462. // 确保orderNum是数字类型
  2463. if (item.orderNum) {
  2464. newRow.orderNum = parseInt(item.orderNum, 10) || 0
  2465. }
  2466. // 初始化fixedValues并填充实际值
  2467. fixedTitles.forEach((title) => {
  2468. newRow.fixedValues[title.rkey] = item[title.rkey] || ''
  2469. })
  2470. allRows.push(newRow)
  2471. // 构建rowMap用于快速查找
  2472. if (newRow.rowid) rowMap.set(String(newRow.rowid), newRow)
  2473. if (newRow.itemId) rowMap.set(String(newRow.itemId), newRow)
  2474. })
  2475. // 构建树形结构
  2476. const treeData = []
  2477. const parentItems = allRows.filter((item) => !item.isChild)
  2478. // 父级按orderNum正序排序
  2479. parentItems.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0))
  2480. // 将子项添加到对应的父项的children中
  2481. allRows.forEach((item) => {
  2482. if (item.isChild) {
  2483. const parentId = String(item.parentid)
  2484. const parent = rowMap.get(parentId)
  2485. if (parent) {
  2486. parent.children.push(item)
  2487. }
  2488. }
  2489. })
  2490. // 对子项进行排序
  2491. parentItems.forEach((parent) => {
  2492. parent.children.sort(
  2493. (a, b) =>
  2494. (a.fixedValues['序号'] || 0) - (b.fixedValues['序号'] || 0)
  2495. )
  2496. treeData.push(parent)
  2497. })
  2498. this.contentEditForm.fixedTable.fixedTables = treeData
  2499. },
  2500. /**
  2501. * 将固定表项目的数据根据固定列拆分成对应的数据结构
  2502. * @returns {Array} 拆分后的数据数组,每个固定列对应一行数据
  2503. */
  2504. splitFixedTableDataForSave() {
  2505. const fixedTables = this.contentEditForm.fixedTable.fixedTables
  2506. const fixedTitles = this.contentEditForm.fixedTable.fixedTablesTitle
  2507. const fixedHeaders = this.contentEditForm.fixedTable.tableHeaders
  2508. // 结果数组
  2509. const result = []
  2510. // 递归处理树形结构中的所有节点
  2511. const processNode = (node, parentRowIndex = 0) => {
  2512. // 确保node和fixedValues存在
  2513. if (!node) {
  2514. console.warn('遇到空节点,跳过处理')
  2515. return
  2516. }
  2517. // 确保fixedValues属性存在,如果不存在则初始化为空对象
  2518. if (!node.fixedValues) {
  2519. node.fixedValues = {}
  2520. }
  2521. // 为每个固定列创建一条记录
  2522. fixedTitles.forEach((title) => {
  2523. // 找到对应的表头信息
  2524. const correspondingHeader = fixedHeaders.find(
  2525. (header) => header.fieldName === title.rkey
  2526. )
  2527. const newItem = {
  2528. rkey: title.rkey,
  2529. rvalue: node.fixedValues[title.rkey] || '',
  2530. surveyTemplateId: node.surveyTemplateId || this.surveyTemplateId,
  2531. versionId: node.versionId || this.versionId,
  2532. tabtype: node.tabtype || this.templateType,
  2533. // 添加 headersId 字段(表头的id)
  2534. headersId: correspondingHeader ? correspondingHeader.id : null,
  2535. // 添加记录的id(itemlist中每条记录的id)
  2536. id: node.itemId || null,
  2537. // 添加父子关系字段
  2538. parentid: node.parentid || -1, // 父项ID,默认为-1表示无父项
  2539. isChild: node.isChild || false, // 是否为子项
  2540. // 添加 rowid 字段
  2541. rowid: node.rowid || null,
  2542. // 添加计算公式相关字段
  2543. calculationFormula: node.calculationFormula || null,
  2544. jsonstr: node.jsonstr || null,
  2545. orderNum:
  2546. typeof node.orderNum === 'number'
  2547. ? node.orderNum
  2548. : parseInt(node.orderNum, 10) || 0,
  2549. }
  2550. // 添加其他固定表特有的字段
  2551. if (!node.isSubItem) {
  2552. newItem.cellCode = node.cellCode || ''
  2553. newItem.unit = node.unit || ''
  2554. }
  2555. // 添加其他可能需要的字段,但排除特定字段
  2556. Object.keys(node).forEach((key) => {
  2557. if (
  2558. !(key in newItem) &&
  2559. key !== 'fixedValues' &&
  2560. key !== 'itemId' &&
  2561. key !== 'id' &&
  2562. key !== 'parentid' &&
  2563. key !== 'isChild' &&
  2564. key !== 'isSubItem' &&
  2565. key !== 'rowid' &&
  2566. key !== 'jsonstr' &&
  2567. key !== 'calculationFormula' &&
  2568. key !== 'children' // 排除children字段
  2569. ) {
  2570. newItem[key] = node[key]
  2571. }
  2572. })
  2573. result.push(newItem)
  2574. })
  2575. // 递归处理子节点
  2576. if (node.children && node.children.length > 0) {
  2577. node.children.forEach((childNode) => {
  2578. processNode(childNode)
  2579. })
  2580. }
  2581. }
  2582. // 遍历所有顶级节点
  2583. fixedTables.forEach((row) => {
  2584. processNode(row)
  2585. })
  2586. // 重新给子节点赋值orderNum 保证所有元素orderNum字段不重复
  2587. // 为所有子节点分配唯一的orderNum,但保持父节点的orderNum不变
  2588. // 计算所有已存在的orderNum中的最大值
  2589. let maxExistingOrderNum = 0
  2590. // 首先遍历结果数组找出当前最大的orderNum
  2591. result.forEach((item) => {
  2592. const orderNum =
  2593. typeof item.orderNum === 'number'
  2594. ? item.orderNum
  2595. : parseInt(item.orderNum, 10) || 0
  2596. if (orderNum > maxExistingOrderNum) {
  2597. maxExistingOrderNum = orderNum
  2598. }
  2599. })
  2600. // 子节点orderNum从当前最大orderNum + 1开始
  2601. let childOrderNumCounter = maxExistingOrderNum + 1
  2602. // 创建一个映射表,用于记录每个子节点对应的新orderNum
  2603. const childOrderMap = new Map()
  2604. // 第一次遍历:为每个子节点分配新的orderNum并存储映射关系
  2605. function assignChildOrderNums(nodes) {
  2606. nodes.forEach((node) => {
  2607. if (node.isChild || node.isSubItem) {
  2608. // 为每个子节点分配唯一的orderNum
  2609. childOrderMap.set(node.id || node.rowid, childOrderNumCounter++)
  2610. }
  2611. // 递归处理子节点
  2612. if (node.children && node.children.length > 0) {
  2613. assignChildOrderNums(node.children)
  2614. }
  2615. })
  2616. }
  2617. // 第二次遍历:更新结果数组中的orderNum
  2618. assignChildOrderNums(fixedTables)
  2619. // 应用新的orderNum到结果数组
  2620. result.forEach((item) => {
  2621. // 只更新子节点的orderNum
  2622. if (item.isChild || item.isSubItem) {
  2623. const newOrderNum =
  2624. childOrderMap.get(item.id) || childOrderMap.get(item.rowid)
  2625. if (newOrderNum) {
  2626. item.orderNum = newOrderNum
  2627. }
  2628. }
  2629. })
  2630. return result
  2631. },
  2632. //分割字符串
  2633. stringToObjects(str) {
  2634. const items = str.split(',')
  2635. return items.map((item) => ({
  2636. rkey: item,
  2637. rvalue: '',
  2638. }))
  2639. },
  2640. /**
  2641. * 获取行缩进样式,用于树形结构展示
  2642. * @param {Object} row - 表格行数据
  2643. * @returns {Object} 样式对象
  2644. */
  2645. getRowIndentStyle(row) {
  2646. // 为子项添加缩进
  2647. if (row.isChild) {
  2648. return {
  2649. marginLeft: '30px',
  2650. }
  2651. }
  2652. return {}
  2653. },
  2654. handleSaveTemplate() {
  2655. // 校验表单
  2656. this.$refs['contentEditForm'].validate((valid) => {
  2657. if (valid) {
  2658. // 显示加载状态
  2659. this.$loading({
  2660. lock: true,
  2661. text: '保存数据中...',
  2662. spinner: 'el-icon-loading',
  2663. background: 'rgba(0, 0, 0, 0.7)',
  2664. })
  2665. if (this.dialogTitle == '修改成本核定模板') {
  2666. let data = {
  2667. ...this.contentEditForm,
  2668. }
  2669. delete data.fixedTable
  2670. // 修改表单数据
  2671. addCostVerifyForm(data).then((res) => {})
  2672. }
  2673. // 获取拆分后的数据
  2674. const splitData = this.splitFixedTableDataForSave()
  2675. const headersList =
  2676. this.contentEditForm.fixedTable.tableHeaders.map(
  2677. (header, index) => ({
  2678. ...header,
  2679. orderNum: header.orderNum || index + 1,
  2680. })
  2681. )
  2682. let data = {
  2683. costVerifyTemplateId: this.contentEditForm.surveyTemplateId,
  2684. headersList: headersList,
  2685. itemsList: splitData,
  2686. }
  2687. batchSaveOrUpdate(data)
  2688. .then((data) => {
  2689. // 关闭加载状态
  2690. this.$loading().close()
  2691. this.dialogVisible = false
  2692. this.$message.success('保存成功')
  2693. this.handleSearch()
  2694. })
  2695. .catch((err) => {
  2696. // 关闭加载状态
  2697. this.$loading().close()
  2698. console.log(err)
  2699. })
  2700. } else {
  2701. this.$message.error('请填写表单数据')
  2702. return
  2703. }
  2704. })
  2705. },
  2706. // 批量删除
  2707. handleBatchDelete() {
  2708. if (this.selectedRows.length === 0) {
  2709. this.$message.warning('请先选择要删除的数据')
  2710. return
  2711. }
  2712. this.$confirm(
  2713. `确定要删除选中的${this.selectedRows.length}条数据吗?`,
  2714. '提示',
  2715. {
  2716. type: 'warning',
  2717. }
  2718. )
  2719. .then(() => {
  2720. const ids = this.selectedRows.map((row) => row.surveyTemplateId)
  2721. batchDeleteCostVerifyForm(ids).then((res) => {
  2722. if (res.code === 200) {
  2723. this.selectedRows = []
  2724. this.$message.success('批量删除成功')
  2725. this.handleSearch()
  2726. }
  2727. })
  2728. })
  2729. .catch(() => {})
  2730. },
  2731. // 表格选择
  2732. handleSelectionChange(selection) {
  2733. this.selectedRows = selection
  2734. },
  2735. // 分页相关
  2736. handleSizeChange(val) {
  2737. this.searchForm.pageSize = val
  2738. this.handleSearch()
  2739. },
  2740. handleCurrentChange(val) {
  2741. this.searchForm.page = val
  2742. this.handleSearch()
  2743. },
  2744. // 获取或设置序号字段
  2745. getOrSetOrder(row, value) {
  2746. // 如果提供了value参数,则设置值
  2747. if (value !== undefined) {
  2748. // 使用this.$set确保响应式更新
  2749. if (row['序号'] === undefined) {
  2750. this.$set(row, '序号', value)
  2751. } else {
  2752. row['序号'] = value
  2753. }
  2754. }
  2755. // 如果没有提供value参数,则获取值
  2756. return row['序号'] !== undefined && row['序号'] !== null
  2757. ? row['序号']
  2758. : row.orderNum || ''
  2759. },
  2760. // 公式验证函数
  2761. validateFormula(formula, data) {
  2762. if (!formula || typeof formula !== 'string') {
  2763. return { valid: false, errorMsg: '公式不能为空' }
  2764. }
  2765. // 定义有效的操作符
  2766. const operators = ['+', '-', '*', '/', '(', ')']
  2767. // 检查是否包含至少一个操作符
  2768. const hasOperator = operators.some((operator) =>
  2769. formula.includes(operator)
  2770. )
  2771. if (!hasOperator) {
  2772. return { valid: false, errorMsg: '公式必须包含操作符' }
  2773. }
  2774. // 检查值是否在data中存在
  2775. function checkValueInData(value, data) {
  2776. if (!data) return false
  2777. if (Array.isArray(data)) {
  2778. return data.includes(value)
  2779. } else if (typeof data === 'object') {
  2780. return Object.values(data).includes(value)
  2781. }
  2782. return data === value
  2783. }
  2784. // 提取公式中的变量/值
  2785. function extractValues(formulaStr) {
  2786. // 改进实现:支持形如"CeShi3.C2"的格式,提取点后面的部分作为变量,同时保留普通变量
  2787. const result = new Set()
  2788. // 1. 首先提取带点格式中的变量部分(如CeShi3.C2中的C2)
  2789. const dotRegex = /[A-Za-z0-9]+\.([A-Za-z0-9]+)/g
  2790. let dotMatch
  2791. while ((dotMatch = dotRegex.exec(formulaStr)) !== null) {
  2792. result.add(dotMatch[1]) // 提取点后面的部分作为变量
  2793. }
  2794. // 2. 然后提取普通变量(C3等),但排除已经从带点格式中提取的部分
  2795. // 移除所有带点的部分,然后提取剩余的变量
  2796. const remainingFormula = formulaStr.replace(
  2797. /[A-Za-z0-9]+\.[A-Za-z0-9]+/g,
  2798. ''
  2799. )
  2800. const normalRegex = /[A-Za-z0-9]+/g
  2801. let normalMatch
  2802. while ((normalMatch = normalRegex.exec(remainingFormula)) !== null) {
  2803. // 跳过纯数字
  2804. if (
  2805. !isNaN(Number(normalMatch[0])) &&
  2806. Number(normalMatch[0]).toString() === normalMatch[0]
  2807. ) {
  2808. continue
  2809. }
  2810. result.add(normalMatch[0])
  2811. }
  2812. return Array.from(result)
  2813. }
  2814. function checkOperatorContext(formulaStr, data) {
  2815. for (let i = 0; i < formulaStr.length; i++) {
  2816. const char = formulaStr[i]
  2817. // 跳过括号
  2818. if (char === '(' || char === ')') continue
  2819. // 检查操作符
  2820. if (operators.includes(char)) {
  2821. // 检查操作符前是否有值(开头或不是操作符和左括号)
  2822. if (
  2823. i === 0 ||
  2824. (operators.includes(formulaStr[i - 1]) &&
  2825. formulaStr[i - 1] !== ')') ||
  2826. formulaStr[i - 1] === '('
  2827. ) {
  2828. return {
  2829. valid: false,
  2830. errorMsg: `位置 ${i + 1} 的操作符 '${char}' 前缺少值`,
  2831. }
  2832. }
  2833. // 检查操作符后是否有值(结尾或不是操作符和右括号)
  2834. if (
  2835. i === formulaStr.length - 1 ||
  2836. (operators.includes(formulaStr[i + 1]) &&
  2837. formulaStr[i + 1] !== '(') ||
  2838. formulaStr[i + 1] === ')'
  2839. ) {
  2840. return {
  2841. valid: false,
  2842. errorMsg: `位置 ${i + 1} 的操作符 '${char}' 后缺少值`,
  2843. }
  2844. }
  2845. }
  2846. }
  2847. // 验证通过后,检查公式中的值是否都在data中存在
  2848. if (data.length > 0) {
  2849. const values = extractValues(formulaStr)
  2850. for (const value of values) {
  2851. // 跳过纯数字(假设有值不在data中)
  2852. if (!isNaN(Number(value)) && Number(value).toString() === value) {
  2853. continue
  2854. }
  2855. if (!checkValueInData(value, data)) {
  2856. return {
  2857. valid: false,
  2858. errorMsg: `变量 '${value}' 在数据中不存在`,
  2859. }
  2860. }
  2861. }
  2862. }
  2863. return { valid: true }
  2864. }
  2865. // 执行验证
  2866. return checkOperatorContext(formula, data)
  2867. },
  2868. },
  2869. }
  2870. </script>
  2871. <style lang="scss" scoped>
  2872. .row-indent-container {
  2873. display: flex;
  2874. align-items: center;
  2875. position: relative;
  2876. }
  2877. .child-item {
  2878. padding-left: 30px; /* 增加子项缩进,为'子项'文字留出空间 */
  2879. }
  2880. .child-item-indicator {
  2881. position: absolute;
  2882. left: 0;
  2883. color: $base-color-default; /* 使用主题色,更醒目 */
  2884. font-size: 12px;
  2885. width: 30px;
  2886. text-align: left;
  2887. font-weight: 500;
  2888. }
  2889. @import '@/styles/costAudit.scss';
  2890. .supervision-content-container {
  2891. padding: 20px;
  2892. .operation-bar {
  2893. margin-bottom: 20px;
  2894. }
  2895. .table-container {
  2896. .table-name-link {
  2897. color: #409eff;
  2898. cursor: pointer;
  2899. &:hover {
  2900. color: #66b1ff;
  2901. text-decoration: underline;
  2902. }
  2903. }
  2904. .pagination-container {
  2905. margin-top: 20px;
  2906. text-align: right;
  2907. }
  2908. }
  2909. .content-form,
  2910. .detail-form {
  2911. ::v-deep .el-select {
  2912. width: 100%;
  2913. }
  2914. }
  2915. }
  2916. </style>