index.vue 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  1. <template>
  2. <div class="data-fill-list-box">
  3. <el-collapse v-model="ActiveKey" accordion @change="CollapseChange">
  4. <el-collapse-item v-for="(item,index) in listDatas" :id="`item-${index}-${item?.pkeyId}`"
  5. :key="item?.pkeyId" :disabled="item['isBussShow'] === 2"
  6. :name="`item-${index}-${item?.pkeyId}`">
  7. <template #title>
  8. <div class="hc-collapse-item-header">
  9. <div class="text-lg truncate item-title"> {{ item.nodeName }}</div>
  10. <div class="hc-extra-text-box">
  11. <HcTooltip v-if="item['isCopeTab'] === 2 || item['isCopeTab'] === 3" keys="wbs_del_table">
  12. <el-button :disabled="item['isBussShow'] === 2" :loading="tableFormDelLoading" plain
  13. type="danger"
  14. @click.stop="delClick(item)">删除本表
  15. </el-button>
  16. </HcTooltip>
  17. <HcTooltip keys="wbs_copy_table">
  18. <el-button
  19. v-if="item['isLinkTable'] === 1"
  20. disabled plain
  21. type="info">
  22. 复制本表
  23. </el-button>
  24. <el-button v-else :loading="copyClickLoading" plain type="primary"
  25. @click.stop="copyClick(item,index)">复制本表
  26. </el-button>
  27. </HcTooltip>
  28. <HcTooltip keys="wbs_hide_table">
  29. <el-button :loading="tableFormHideLoading" plain type="primary"
  30. @click.stop="hideClick(item,index)">
  31. <template v-if="item['isBussShow'] === 1">隐藏本表</template>
  32. <template v-else>显示本表</template>
  33. </el-button>
  34. </HcTooltip>
  35. <HcTooltip v-if="isStatus !== 3" keys="wbs_preview_table">
  36. <el-button
  37. v-if="item['isBussShow'] === 2 || item['isTabPdf'] === 1|| item['pdfUrl'] === ''"
  38. disabled plain
  39. type="info">
  40. 预览
  41. </el-button>
  42. <el-button v-else :loading="tableFormPreviewLoading" plain type="primary"
  43. @click.stop="previewClick(item)">预览
  44. </el-button>
  45. </HcTooltip>
  46. <HcTooltip keys="wbs_upload_table">
  47. <el-button :disabled="item['isBussShow'] === 2"
  48. :type="item['tabFileType'] === 2?'success':'primary'"
  49. plain
  50. @click.stop="uploadClick(item,index)">
  51. <template v-if="item['tabFileType'] === 2">已上传</template>
  52. <template v-else>上传</template>
  53. </el-button>
  54. </HcTooltip>
  55. </div>
  56. </div>
  57. </template>
  58. <div :style="`height: calc(100vh - ${draw_type ? '555px' : '360px'});`"
  59. class="data-fill-list-item-content">
  60. <div v-if="item?.isWindow" class="data-fill-table-form-box is-window">
  61. <div class="hc-window-tip">
  62. <div class="table-form-no">
  63. <img :src="NoDataSvg" alt=""/>
  64. <div class="desc">当前表单处于窗口模式,关闭相关窗口后恢复</div>
  65. </div>
  66. </div>
  67. </div>
  68. <div v-else class="data-fill-table-form-box">
  69. <TableFormItem v-if="item.isTableRender"
  70. :ref="(el) => setItemRefs(el, item)"
  71. :classify="classifys"
  72. :datas="changeFormDatas(item?.pkeyId, 'collapse')"
  73. :kid="item?.pkeyId"
  74. :nodeName="item.nodeName"
  75. :pid="`table-form-${item?.pkeyId}`"
  76. :tid="treeId"
  77. @excelBodyTap="excelTableFormClick($event)"
  78. @render="tableFormRender($event, item, index)"
  79. @rightTap="tableFormRightTap($event, index)"/>
  80. </div>
  81. <div class="hc-window-switch-box">
  82. <el-tooltip :content="item.isWindow?'关闭窗口并恢复':'当前表单窗口化'" :hide-after="0"
  83. placement="top">
  84. <div class="icon-btn-view" @click.stop="windowClick(item, index)">
  85. <template v-if="item.isWindow">
  86. <HcIcon class="icon" name="picture-in-picture-2"/>
  87. <span class="ml-1">关闭窗口化</span>
  88. </template>
  89. <template v-else>
  90. <HcIcon class="icon" name="picture-in-picture-exit"/>
  91. <span class="ml-1">表单窗口化</span>
  92. </template>
  93. </div>
  94. </el-tooltip>
  95. </div>
  96. <div class="data-fill-table-tip-box">
  97. <el-scrollbar>
  98. <div class="text-orange tip-title">
  99. <HcIcon fill name="information" ui="text-2xl"/>
  100. <span class="ml-1">提示</span>
  101. </div>
  102. <div class="text-gray-400 tip-item">
  103. 1、灰色框代表可通过系统识别计算,公式自动引用,可通过公式计算少量数据,(表头数据及简单),也可只填写白色框数据
  104. </div>
  105. <div class="text-gray-400 tip-item">2、系统支持键盘中,shift +
  106. tab键向上一个填报框切换,tab向下一个填报框切换。Shift + 上 ( ↑ )、下 ( ↓ )、左 ( ← )、右 ( →
  107. )键,切换填报输入框焦点。
  108. </div>
  109. <div class="text-gray-400 tip-item">3、先点击一下表单任一区域,再键盘按住 ctrl +
  110. 点击,选择输入框,变为绿色边框,选中成功。选择完毕后,键盘按 ctrl + c 复制所选中的数据,
  111. 再其它表内,或同一张表内,再次按住 ctrl + 点击,选择输入框。键盘按 ctrl + v
  112. 依次粘贴所选的数据。(目前仅支持输入框和文本框的操作)
  113. </div>
  114. <div class="text-orange-500 tip-item">4、完善资料填写后记得一定要保存哦</div>
  115. </el-scrollbar>
  116. <div class="table-tip-foot">
  117. <div class="tip-left-btn">
  118. <HcTooltip keys="wbs_import_table">
  119. <div class="text-gray-400 dow-text">
  120. <HcIcon name="publish" ui="text-lg"/>
  121. <span class="ml-1">导入列表数据</span>
  122. </div>
  123. </HcTooltip>
  124. <HcTooltip keys="wbs_download_table">
  125. <div class="text-main dow-text">
  126. <HcIcon name="file_download" ui="text-lg"/>
  127. <span class="ml-1">下载导入模板</span>
  128. </div>
  129. </HcTooltip>
  130. </div>
  131. <div class="tip-right-btn">
  132. <HcTooltip keys="wbs_save_table">
  133. <el-button :disabled="!item?.isTableForm"
  134. :loading="tableFormSaveLoading" hc-btn
  135. type="primary"
  136. @click="tableFormSaveClick(item)">
  137. <HcIcon name="save"/>
  138. <span>保存</span>
  139. </el-button>
  140. </HcTooltip>
  141. </div>
  142. </div>
  143. </div>
  144. </div>
  145. </el-collapse-item>
  146. </el-collapse>
  147. </div>
  148. <!--右键菜单-->
  149. <HcContextMenu ref="contextMenuRef" :datas="tableFormMenu" @item-click="handleMenuSelect"/>
  150. <!--上传文件-->
  151. <HcDialog :footer="false" :show="uploadModal" title="上传文件" widths="38rem" @close="uploadModalClose">
  152. <HcUpload :datas="uploadData" :fileList="fileListData" @change='uploadChange'/>
  153. </HcDialog>
  154. <!--插入设计值/频率-->
  155. <HcDialog :loading="designModalLoading" :show="designModal" isToBody saveText="确认插入"
  156. title="插入设计值/频率" widths="600px"
  157. @close="closeDesignModal" @save="designModalSave">
  158. <el-alert :closable="false" title="填写完设计值和频率,系统自动计算实测值" type="warning"/>
  159. <el-form ref="formDesignRef" :model="formDesignModel" label-width="auto" size="large">
  160. <div class="form-item-div text-center mb-3">
  161. <el-radio-group v-model="formDesignModel.type" size="large">
  162. <el-radio :label="1">公路工程</el-radio>
  163. <el-radio :label="2" class="ml-4">水利水电</el-radio>
  164. </el-radio-group>
  165. </div>
  166. <el-form-item label="设计值">
  167. <!-- onkeyup="value = value.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g,'$1')" -->
  168. <el-input v-model="formDesignModel.design" placeholder="如果设计值存在两个,则使用 '/' 连接,例如12/23"/>
  169. </el-form-item>
  170. <el-form-item v-if="formDesignModel.type === 1" label="频率">
  171. <!-- onkeyup="value = value.replace(/^(0+)|[^\d]+/g,'')" -->
  172. <el-input v-model="formDesignModel.size"
  173. placeholder="如果设计值使用 '/' 连接,则频率也是用 '/' 连接,例如5/10"/>
  174. </el-form-item>
  175. <el-form-item v-if="formDesignModel.type === 2" label="容量">
  176. <!-- onkeyup="value = value.replace(/^(0+)|[^\d]+/g,'')" -->
  177. <el-input v-model="formDesignModel.capacity"
  178. placeholder="如果容量存在两个,则使用 '*',或者 '/' 连接例如2*4,5/7"/>
  179. </el-form-item>
  180. <el-form-item label="合格点数">
  181. <el-input v-model="formDesignModel.pass"
  182. placeholder="如果设计值使用 '/' 连接,则合格点数也是用 '/' 连接,例如2/5"/>
  183. </el-form-item>
  184. <el-form-item label="偏差范围">
  185. <el-input v-model="formDesignModel.dev"
  186. placeholder="如果设计值使用 '/' 连接,则偏差范围也是用 '/' 连接,例如±2/±3"/>
  187. </el-form-item>
  188. </el-form>
  189. </HcDialog>
  190. <!--插入特殊字符-->
  191. <HcDialog :loading="specialModalLoading" :show="specialModal" isToBody saveText="确认插入" title="插入特殊字符"
  192. widths="600px" @close="specialModalClose" @save="specialNodeClick">
  193. <HcSpecialDiaolg v-if="specialModal" ref="specialRef" @change="specialDiaolgChange"/>
  194. </HcDialog>
  195. <!--关联试验数据-->
  196. <HcDialog :footer="false" :loading="testModalLoading" :show="testModal" isTable isToBody title="关联试验数据"
  197. widths="84%" @close="testModalClose">
  198. <HcTestDiaolg v-if="testModal" :contractId="contract_id" :projectId="projectId" :tenantId="tenant_id"
  199. :wbsId="wbsTemp_id"
  200. :wbsType="wbs_type" @change="testTableRowName"/>
  201. </HcDialog>
  202. <!-- 选择要插入的数据 -->
  203. <HcDialog :loading="insertDataLoading" :show="insertDataShow" isTable isToBody saveText="保存"
  204. title="选择需要插入的数据" widths="84%" @close="cancelinsertData"
  205. @save="submitinsertData">
  206. <HcTestData v-if="insertDataShow" ref="insertDataRef" :contractId="contract_id" :projectId="projectId"
  207. :tableId="itinsertTableId"
  208. :treeId="itinsertTreeId"/>
  209. </HcDialog>
  210. <!--关联试验文件-->
  211. <HcDialog :loading="fileModalLoading" :show="fileModal" isTable isToBody saveText="保存" title="关联试验文件"
  212. widths="84%" @close="fileModalClose"
  213. @save="savefileModal">
  214. <HcTestFile v-if="fileModal" ref="testFileRefs" :contractId="contract_id" :projectId="projectId"
  215. :tenantId="tenant_id"
  216. :treeId="treeId" :wbsId="wbsTemp_id"
  217. :wbsType="wbs_type"/>
  218. </HcDialog>
  219. <!-- 公式参数配置 -->
  220. <HcDialog :loading="formulaModalLoading" :show="formulaModal" isToBody saveText="保存" title="公式参数配置"
  221. widths="84%" @close="formulaModalClose"
  222. @save="formulaSaveClick">
  223. <HcFormula v-if="formulaModal" ref="formulaRefs" :KeyName="tableFormItemNode.KeyName" :contractId="contract_id"
  224. :formparentId="formparentId"
  225. :pkeyId="tableFormItemNode.pkeyId" :projectId="projectId"/>
  226. </HcDialog>
  227. <!--查看表单-->
  228. <template v-for="(item,index) in DragModalTableForm">
  229. <HcDragModal :closeIconArr="closeIconArr" :eid="item.pkeyId" :height="DragModalHeight" :isShow="item.isShow"
  230. :loading="item.loading" :loadingText="item.loadingText" :title="item.title"
  231. isSortTop
  232. @close="TableFormClose(item, index)" @closeIconTap="closeIconTap($event, item, index)">
  233. <HcDragNode :more-menu="dragNodeMoreMenu" @menuTap="dragNodeMoreMenuTap($event, item)">
  234. <TableFormItem :ref="(el) => setItemRefs(el, item)"
  235. :classify="item.classify"
  236. :datas="changeFormDatas(item?.pkeyId, 'window')"
  237. :height="item.height"
  238. :kid="item.pkeyId"
  239. :nodeName="item.title"
  240. :pid="`table-form-${item?.pkeyId}`"
  241. :scroll="false"
  242. :tid="item.treeId"
  243. :width="item.width"
  244. @excelBodyTap="excelTableFormClick($event)"
  245. @render="tableFormRender($event, item['item'], item['index'])"
  246. @rightTap="tableFormRightTap($event, item['index'])"/>
  247. </HcDragNode>
  248. </HcDragModal>
  249. </template>
  250. </template>
  251. <script setup>
  252. import {ref, watch, nextTick, onUnmounted} from "vue";
  253. import {useAppStore} from "~src/store";
  254. import wbsApi from "~api/data-fill/wbs"
  255. import HcUpload from "../components/HcUpload.vue"
  256. import TableFormItem from "./table-form-item.vue"
  257. import HcSpecialDiaolg from "./special-diaolg.vue"
  258. import HcTestDiaolg from "./test-diaolg.vue"
  259. import HcTestData from "./test-data.vue"
  260. import HcTestFile from "./test-file.vue"
  261. import HcFormula from "./formula.vue"
  262. import HcDragNode from "~com/drag-node/index.vue"
  263. import NoDataSvg from '~src/assets/view/no-data.svg'
  264. import {setPosRange, isType, utilsArray, deepClone, isValueNull} from "vue-utils-plus"
  265. //初始变量
  266. const useAppState = useAppStore()
  267. const {isIndex, getIndex} = utilsArray()
  268. const {isString, getObjNullValue, getArrValue, getObjValue} = isType()
  269. //参数
  270. const props = defineProps({
  271. datas: {
  272. type: Array,
  273. default: () => ([])
  274. },
  275. classify: {
  276. type: [String, Number],
  277. default: ''
  278. },
  279. status: {
  280. type: [String, Number],
  281. default: ''
  282. },
  283. primaryKeyId: {
  284. type: [String, Number],
  285. default: ''
  286. },
  287. contractId: {
  288. type: [String, Number],
  289. default: ''
  290. },
  291. drawType: {
  292. type: Boolean,
  293. default: false
  294. },
  295. wbsTempId: {
  296. type: [String, Number],
  297. default: ''
  298. },
  299. tenantId: {
  300. type: [String, Number],
  301. default: ''
  302. },
  303. wbsType: {
  304. type: [String, Number],
  305. default: ''
  306. },
  307. })
  308. //全局变量
  309. const projectId = ref(useAppState.projectId);
  310. const contract_id = ref(props.contractId)
  311. const treeId = ref(props.primaryKeyId)
  312. const classifys = ref(props.classify)
  313. const wbsTemp_id = ref(props.wbsTempId);
  314. const tenant_id = ref(props.tenantId);
  315. const wbs_type = ref(props.wbsType);
  316. const isStatus = ref(parseInt(props.status))
  317. const listDatas = ref([])
  318. const draw_type = ref(props.drawType)
  319. //表单变量
  320. const formDataList = ref([])
  321. const formKeyIds = ref('')
  322. const formparentId = ref('')
  323. //处理ref
  324. const itemRefs = ref([])
  325. const setItemRefs = (el, {pkeyId}) => {
  326. if (el) {
  327. let index = getIndex(itemRefs.value, 'pkeyId', pkeyId)
  328. if (index !== -1) {
  329. itemRefs.value[index].ref = el
  330. } else {
  331. itemRefs.value.push({
  332. pkeyId: pkeyId,
  333. ref: el
  334. });
  335. }
  336. }
  337. }
  338. //处理表单的ref
  339. const setSpliceItemRefs = async ({pkeyId}) => {
  340. const refs = itemRefs.value
  341. let index = getIndex(refs, 'pkeyId', pkeyId)
  342. if (index !== -1) {
  343. refs.splice(index, 1)
  344. itemRefs.value = refs
  345. }
  346. }
  347. const closeIconArr = [
  348. {key: 'reduction', icon: 'picture-in-picture-2', name: '还原到面板内,并自动展开面板'}
  349. ]
  350. //事件
  351. const emit = defineEmits(['renew', 'offsetTop'])
  352. //组件参数变量
  353. const apis = ref({
  354. dataInfo: wbsApi.getBussDataInfo,
  355. bussCols: wbsApi.getHtmlBussCols,
  356. excelHtml: wbsApi.getExcelHtml
  357. })
  358. //深度监听数据
  359. watch(() => [
  360. props.datas,
  361. ], ([datas]) => {
  362. setFormDataNum(datas)
  363. }, {deep: true})
  364. //监听变量值
  365. watch(() => [
  366. useAppState.projectId,
  367. props.contractId,
  368. props.wbsTempId,
  369. props.tenantId,
  370. props.wbsType,
  371. props.status,
  372. props.classify,
  373. props.primaryKeyId,
  374. ], ([pid, cid, temp_id, tid, type, status, class_id, tree_id]) => {
  375. projectId.value = pid
  376. contract_id.value = cid
  377. wbsTemp_id.value = temp_id
  378. tenant_id.value = tid
  379. wbs_type.value = type
  380. isStatus.value = parseInt(status)
  381. classifys.value = class_id
  382. treeId.value = tree_id
  383. })
  384. //渲染完成
  385. nextTick(() => {
  386. setFormDataNum(props.datas)
  387. setTableFormMenu(useAppState.projectInfo)
  388. const {offsetHeight} = document.body
  389. DragModalHeight.value = offsetHeight - 200
  390. })
  391. //处理变动的数据
  392. const changeFormData = ref({
  393. 'window': [],
  394. 'collapse': [],
  395. })
  396. const changeFormDatas = (pkeyId, type) => {
  397. const changeData = changeFormData.value[type]
  398. const index = getIndex(changeData, 'pkeyId', pkeyId)
  399. if (index !== -1) {
  400. return changeData[index]
  401. } else {
  402. return {}
  403. }
  404. }
  405. //设置变动的数据
  406. const setChangeFormDatas = async (pkeyId, type) => {
  407. const refs = await getFormRef(pkeyId)
  408. const formData = refs?.getFormData()
  409. const changeData = changeFormData.value[type]
  410. const index = getIndex(changeData, 'pkeyId', pkeyId)
  411. if (index !== -1) {
  412. changeData[index] = formData
  413. } else {
  414. changeData.push(formData)
  415. }
  416. changeFormData.value[type] = changeData
  417. }
  418. //展开事件
  419. const ActiveKey = ref('')
  420. const CollapseChange = (name) => {
  421. ActiveKey.value = name
  422. let index = getCollapseItemIndex(name)
  423. if (index > -1) {
  424. getOffsetTop(name);
  425. const item = listDatas.value[index]
  426. formKeyIds.value = setToString(item.pkeyId)
  427. formparentId.value = setToString(item.parentId)
  428. nextTick(() => {
  429. if (!item.isTableRender) {
  430. item.isTableRender = true
  431. }
  432. })
  433. } else {
  434. getOffsetTop()
  435. formKeyIds.value = ''
  436. formparentId.value = ''
  437. }
  438. }
  439. //初始设置
  440. const setFormDataNum = (datas) => {
  441. itemRefs.value = []
  442. ActiveKey.value = ''
  443. let newArr = [];
  444. for (let i = 0; i < datas.length; i++) {
  445. newArr.push({isCollapseLoad: false})
  446. }
  447. formDataList.value = newArr
  448. listDatas.value = deepClone(datas)
  449. }
  450. //渲染完成
  451. const tableFormRender = (form, item, index) => {
  452. formDataList.value[index] = {
  453. ...form,
  454. isCollapseLoad: form.isRenderForm
  455. }
  456. item.isTableForm = form.isRenderForm
  457. }
  458. //菜单数据
  459. const contextMenuRef = ref(null)
  460. const tableFormMenu = ref([])
  461. const tableFormItemNode = ref({}) //临时信息
  462. //设置菜单权限数据
  463. const setTableFormMenu = (info) => {
  464. let newArr = [], infos = getObjValue(info)
  465. const isOpen = infos['isOpenRandomNumber'] ?? 0
  466. if (isOpen === 1 && isStatus.value !== 3) {
  467. newArr.push({label: '插入设计值/频率', key: "design"})
  468. }
  469. newArr.push({label: '插入特殊字符', key: "special"})
  470. newArr.push({label: '关联试验数据', key: "test"})
  471. newArr.push({label: '关联试验文件', key: "file"})
  472. newArr.push({label: '公式参数', key: "formula"})
  473. tableFormMenu.value = newArr
  474. }
  475. //鼠标右键事件
  476. const tableFormRightTap = ({event, KeyName, startPos, endPos, pkeyId}, index) => {
  477. //存储临时信息
  478. tableFormItemNode.value = {KeyName, index, startPos, endPos, pkeyId}
  479. contextMenuRef.value?.showMenu(event, false) //展开菜单
  480. }
  481. //鼠标右键菜单被点击
  482. const handleMenuSelect = ({key}) => {
  483. if (key === 'design') {
  484. setInitDesignForm()
  485. designModalLoading.value = false
  486. designModal.value = true
  487. } else if (key === 'special') {
  488. specialModalShow()
  489. } else if (key === 'test') {
  490. testModalLoading.value = false
  491. testModal.value = true
  492. } else if (key === 'file') {
  493. fileModalLoading.value = false
  494. fileModal.value = true;
  495. } else if (key === 'formula') {
  496. formulaModalLoading.value = false
  497. formulaModal.value = true
  498. }
  499. }
  500. //插入设计值
  501. const designModal = ref(false)
  502. const formDesignRef = ref(null)
  503. const formDesignModel = ref()
  504. //初始设计值/频率表单
  505. const setInitDesignForm = () => {
  506. formDesignModel.value = {
  507. type: 1, design: '', size: '',
  508. dev: '', key: '', capacity: '',
  509. pass: '', pkId: ''
  510. }
  511. }
  512. //设计值频率计算
  513. const designModalLoading = ref(false)
  514. const designModalSave = async () => {
  515. const {pkeyId, KeyName} = tableFormItemNode.value
  516. if (pkeyId) {
  517. designModalLoading.value = true
  518. //const {design, size} = formDesignModel.value
  519. const {error, code, data} = await wbsApi.queryFormulaRange({
  520. ...formDesignModel.value,
  521. // dev: (!design && !size) ? '±5': '',
  522. key: KeyName,
  523. pkId: pkeyId,
  524. })
  525. //处理数据
  526. const res = getObjNullValue(data)
  527. if (!error && code === 200 && res) {
  528. try {
  529. const refs = await getFormRef(pkeyId)
  530. const itemFormData = refs?.getFormData()
  531. Object.keys(data).forEach(key => {
  532. itemFormData[key] = data[key]
  533. })
  534. refs?.setFormData(itemFormData)
  535. } catch {
  536. }
  537. designModalLoading.value = false
  538. designModal.value = false
  539. } else {
  540. designModalLoading.value = false
  541. }
  542. } else {
  543. window?.$message?.warning('pkeyId为空')
  544. }
  545. }
  546. //关闭设计值/频率弹窗
  547. const closeDesignModal = () => {
  548. designModal.value = false
  549. setInitDesignForm()
  550. }
  551. //插入特殊字符
  552. const specialModal = ref(false)
  553. const specialModalLoading = ref(false)
  554. const specialModalShow = () => {
  555. specialFormValue.value = ''
  556. specialModalLoading.value = false
  557. specialModal.value = true
  558. }
  559. //监听特殊符号输入框的内容
  560. const specialFormValue = ref('')
  561. const specialDiaolgChange = (val) => {
  562. specialFormValue.value = val
  563. }
  564. //确认插入
  565. const specialRef = ref(null)
  566. const specialNodeClick = async () => {
  567. specialModalLoading.value = true
  568. const itemNode = tableFormItemNode.value
  569. const {KeyName, pkeyId} = itemNode
  570. try {
  571. const refs = await getFormRef(pkeyId)
  572. const itemFormData = refs?.getFormData()
  573. const {code, val, posVal} = await specialRef.value?.getSpecialNode(itemNode, itemFormData[KeyName])
  574. if (code === 200 && val) {
  575. itemFormData[KeyName] = val
  576. refs?.setFormData(itemFormData)
  577. specialModalLoading.value = false
  578. specialModal.value = false
  579. await nextTick(() => {
  580. setPosRange(KeyName, posVal)
  581. })
  582. } else {
  583. specialModalLoading.value = false
  584. }
  585. } catch (e) {
  586. specialModalLoading.value = false
  587. }
  588. }
  589. //关闭插入特殊字符
  590. const specialModalClose = () => {
  591. specialModalLoading.value = false
  592. specialModal.value = false
  593. }
  594. //关联试验数据
  595. const testModal = ref(false)
  596. const testModalLoading = ref(false)
  597. //关联试验数据被点击
  598. const itinsertTableId = ref('')
  599. const itinsertTreeId = ref('')
  600. const testTableRowName = ({row, treeId}) => {
  601. itinsertTableId.value = row.id
  602. itinsertTreeId.value = treeId
  603. insertDataLoading.value = false
  604. insertDataShow.value = true
  605. }
  606. //关闭弹窗
  607. const testModalClose = () => {
  608. testModal.value = false
  609. testModalLoading.value = false
  610. }
  611. //选择要插入的实验数据
  612. const insertDataShow = ref(false);
  613. const insertDataLoading = ref(false);
  614. //确定关联试验数据数据
  615. const insertDataRef = ref(null)
  616. const submitinsertData = async () => {
  617. insertDataLoading.value = true
  618. const itemNode = tableFormItemNode.value
  619. const {KeyName, pkeyId} = itemNode
  620. try {
  621. const refs = await getFormRef(pkeyId)
  622. const itemFormData = refs?.getFormData()
  623. const {code, val, posVal} = await insertDataRef.value?.submitinsertData(itemNode, itemFormData[KeyName])
  624. if (code === 200 && val) {
  625. itemFormData[KeyName] = val
  626. refs?.setFormData(itemFormData)
  627. insertDataLoading.value = false
  628. insertDataShow.value = false
  629. testModal.value = false
  630. await nextTick(() => {
  631. setPosRange(KeyName, posVal)
  632. })
  633. }
  634. } catch {
  635. insertDataLoading.value = false
  636. }
  637. }
  638. //取消关联数据
  639. const cancelinsertData = async () => {
  640. insertDataShow.value = false
  641. insertDataLoading.value = false
  642. }
  643. //关联试验文件
  644. const fileModal = ref(false)
  645. const testFileRefs = ref(null)
  646. //确认关联文件
  647. const fileModalLoading = ref(false)
  648. const savefileModal = async () => {
  649. fileModalLoading.value = true
  650. await testFileRefs.value?.savefileSubmit()
  651. fileModalLoading.value = false
  652. fileModal.value = false
  653. }
  654. //关闭弹窗
  655. const fileModalClose = () => {
  656. fileModal.value = false
  657. fileModalLoading.value = false
  658. }
  659. //公式参数配置
  660. const formulaModal = ref(false)
  661. const formulaRefs = ref(null)
  662. //保存
  663. const formulaModalLoading = ref(false)
  664. const formulaSaveClick = async () => {
  665. formulaModalLoading.value = true
  666. await formulaRefs.value?.panelSave()
  667. formulaModalLoading.value = false
  668. formulaModal.value = false
  669. }
  670. //关闭
  671. const formulaModalClose = () => {
  672. formulaModal.value = false
  673. formulaModalLoading.value = false
  674. }
  675. //窗口化
  676. const DragModalTableForm = ref([])
  677. const DragModalHeight = ref(600)
  678. const windowClick = async (item, indexs) => {
  679. const list = deepClone(DragModalTableForm.value)
  680. let index = getIndex(list, 'pkeyId', item.pkeyId)
  681. if (!item.isWindow) {
  682. const formSize = getTableFormSize(item?.pkeyId)
  683. const newTableForm = {
  684. ...setInitDragModalTableForm(item, indexs),
  685. ...formSize
  686. }
  687. await setChangeFormDatas(item?.pkeyId, 'window')
  688. item.isWindow = true
  689. //处理表单的ref
  690. await setSpliceItemRefs(item)
  691. //弹窗表单的排序
  692. if (index === -1) {
  693. list.push(newTableForm)
  694. } else if (index !== list.length - 1) {
  695. //检查是否在最上层,不在则置顶,可以解决多次点击时,频繁更改全局状态的问题
  696. list.splice(index, 1)
  697. list.push(newTableForm)
  698. }
  699. DragModalTableForm.value = list
  700. ActiveKey.value = ''
  701. } else {
  702. await setChangeFormDatas(item?.pkeyId, 'collapse')
  703. //处理表单的ref
  704. await setSpliceItemRefs(item)
  705. if (index !== -1) {
  706. list.splice(index, 1)
  707. DragModalTableForm.value = list
  708. }
  709. item.isWindow = false
  710. }
  711. }
  712. //初始拖动表单的内容
  713. const setInitDragModalTableForm = (item, index) => {
  714. return {
  715. projectId: projectId.value,
  716. contractId: contract_id.value,
  717. wbsTempId: wbsTemp_id.value,
  718. tenantId: tenant_id.value,
  719. wbsType: wbs_type.value,
  720. classify: classifys.value,
  721. treeId: treeId.value,
  722. pkeyId: item.pkeyId,
  723. height: '100%',
  724. width: '100%',
  725. title: item.nodeName,
  726. isShow: true,
  727. index: index,
  728. item: item
  729. }
  730. }
  731. //关闭窗口
  732. const TableFormClose = async ({pkeyId, index}, indexs) => {
  733. const list = deepClone(DragModalTableForm.value)
  734. //取表单的数据
  735. await setChangeFormDatas(pkeyId, 'collapse')
  736. //关闭窗口
  737. list.splice(indexs, 1)
  738. DragModalTableForm.value = list
  739. listDatas.value[index].isWindow = false
  740. }
  741. const dragNodeMoreMenu = [
  742. {key: 'save', icon: 'save-2', name: '保存'},
  743. {key: 'preview', icon: 'eye', name: '预览'},
  744. ]
  745. //还原窗口
  746. const closeIconTap = async (event, item, indexs) => {
  747. const {index, pkeyId} = item
  748. let KeyId = `item-${index}-${pkeyId}`
  749. await TableFormClose(item, indexs)
  750. ActiveKey.value = KeyId
  751. }
  752. //菜单被点击
  753. const dragNodeMoreMenuTap = ({key}, items) => {
  754. const {item} = items
  755. if (key === 'save') {
  756. if (item?.isTableForm) {
  757. tableFormSaveClick(item, items)
  758. } else {
  759. window.$message.warning('此表单暂无数据和文件')
  760. }
  761. } else if (key === 'preview') {
  762. if (item['isBussShow'] === 2 || item['isTabPdf'] === 1 || item['pdfUrl'] === '') {
  763. window.$message.warning('此表单暂无可预览文件')
  764. } else {
  765. previewClick(item, items)
  766. }
  767. }
  768. }
  769. //删除本表
  770. const tableFormDelLoading = ref(false)
  771. const delClick = async ({pkeyId}) => {
  772. if (pkeyId) {
  773. if (isStatus.value !== 3) {
  774. tableFormDelLoading.value = true
  775. const {error, code} = await wbsApi.removeBussTabInfo({
  776. pkeyid: pkeyId,
  777. classify: classifys.value,
  778. })
  779. tableFormDelLoading.value = false
  780. if (!error && code === 200) {
  781. window?.$message?.success('操作成功')
  782. //判断是否存在窗口,如果存在,就删除窗口
  783. delWindowRefs(pkeyId)
  784. renewData()
  785. }
  786. } else {
  787. window?.$message?.warning('已上报的资料,不允许删除')
  788. }
  789. } else {
  790. window?.$message?.warning('pkeyId为空')
  791. }
  792. }
  793. //复制本表
  794. const copyClickLoading = ref(false)
  795. const copyClick = async (items) => {
  796. const {pkeyId, isTableRender, isTableForm} = items
  797. if (pkeyId) {
  798. if (isStatus.value !== 3) {
  799. if (!isTableRender) {
  800. await copeBussTab(pkeyId)
  801. } else if (!isTableForm) {
  802. window?.$message?.warning('暂无表单数据')
  803. } else if (isTableRender) {
  804. copyClickLoading.value = true
  805. const isSave = await saveExcelBussData(items, null, false)
  806. if (isSave) {
  807. await copeBussTab(pkeyId)
  808. } else {
  809. copyClickLoading.value = false
  810. window?.$message?.warning('复制本表操作失败')
  811. }
  812. } else {
  813. window?.$message?.warning(`数据异常了, isRenderTableForm: ${isTableRender}, isTableForm: ${isTableForm}, pkeyIds:${pkeyId}`)
  814. }
  815. } else {
  816. window?.$message?.warning('已上报的资料,不允许复制')
  817. }
  818. } else {
  819. window?.$message?.warning('pkeyId为空')
  820. }
  821. }
  822. //复制表的请求
  823. const copeBussTab = async (pkeyId) => {
  824. copyClickLoading.value = true
  825. const {error, code} = await wbsApi.copeBussTab({
  826. pkeyId: pkeyId
  827. })
  828. copyClickLoading.value = false
  829. if (!error && code === 200) {
  830. window?.$message?.success('操作成功')
  831. renewData()
  832. }
  833. }
  834. //隐藏本表
  835. const tableFormHideLoading = ref(false)
  836. const hideClick = async ({pkeyId, isBussShow}) => {
  837. if (pkeyId) {
  838. if (isStatus.value !== 3) {
  839. tableFormHideLoading.value = true
  840. const bussShow = isBussShow === 2 ? 1 : 2 //状态(1显示 2隐藏)
  841. const {error, code} = await wbsApi.showBussTab({
  842. pkeyId: pkeyId,
  843. status: bussShow
  844. })
  845. tableFormHideLoading.value = false
  846. if (!error && code === 200) {
  847. window?.$message?.success('操作成功')
  848. if (bussShow === 2) {
  849. //判断是否存在窗口,如果存在,就删除窗口
  850. delWindowRefs(pkeyId)
  851. }
  852. renewData()
  853. }
  854. } else {
  855. window?.$message?.warning('已上报的资料,不允许隐藏')
  856. }
  857. } else {
  858. window?.$message?.warning('pkeyId为空')
  859. }
  860. }
  861. //预览本表
  862. const tableFormPreviewLoading = ref(false)
  863. const previewClick = async (item, dragItem = null) => {
  864. tableFormPreviewLoading.value = true
  865. await getBussPdfInfo(item, dragItem)
  866. tableFormPreviewLoading.value = false
  867. }
  868. //上传变量
  869. const uploadModal = ref(false)
  870. const fileListData = ref([]);
  871. const uploadData = ref({})
  872. //上传附件
  873. const uploadClick = (items, index) => {
  874. const {pkeyId, isTableForm, isTableRender} = items
  875. const keyName = `item-${index}-${pkeyId}`
  876. if (pkeyId) {
  877. if (isStatus.value !== 3 && isTableForm) {
  878. uploadModal.value = true
  879. uploadData.value = {
  880. projectId: projectId.value,
  881. contractId: contract_id.value,
  882. classify: classifys.value,
  883. pkeyId: pkeyId,
  884. nodeId: treeId.value
  885. }
  886. //获取文件列表
  887. getBussFileList(pkeyId)
  888. } else if (!isTableRender) {
  889. CollapseChange([keyName])
  890. window?.$message?.warning('请再次点击上传')
  891. } else if (!isTableForm) {
  892. window?.$message?.warning('暂无表单数据')
  893. } else {
  894. window?.$message?.warning('已上报的资料,不允许上传')
  895. }
  896. } else {
  897. window?.$message?.warning('pkeyId为空')
  898. }
  899. }
  900. //获取文件列表
  901. const getBussFileList = async (pkeyId) => {
  902. const {error, code, data} = await wbsApi.getBussFileList({
  903. pkeyid: pkeyId
  904. })
  905. if (!error && code === 200) {
  906. fileListData.value = getArrValue(data)
  907. } else {
  908. fileListData.value = []
  909. }
  910. }
  911. //上传文件
  912. const uploadChange = async ({type}) => {
  913. if (type === 'success') {
  914. uploadModal.value = false
  915. renewData()
  916. } else if (type === 'del') {
  917. renewData()
  918. }
  919. }
  920. //关闭上传附件窗口
  921. const uploadModalClose = () => {
  922. uploadModal.value = false
  923. }
  924. //单个保存
  925. const tableFormSaveLoading = ref(false)
  926. const tableFormSaveClick = async (item, dragItem = null) => {
  927. if (isStatus.value !== 3) {
  928. tableFormSaveLoading.value = true
  929. const isSave = await saveExcelBussData(item, dragItem)
  930. if (isSave) {
  931. await getBussPdfInfo(item, dragItem)
  932. tableFormSaveLoading.value = false
  933. renewData()
  934. } else {
  935. tableFormSaveLoading.value = false
  936. }
  937. } else {
  938. window?.$message?.warning('已上报的资料,不允许保存。')
  939. }
  940. }
  941. //保存表单数据
  942. const saveExcelBussData = async ({pkeyId}, dragItem = null, showTip = true) => {
  943. setDragModalLoading(dragItem, '保存中...', true)
  944. const refs = await getFormRef(pkeyId)
  945. const isRegExp = await refs?.isFormRegExp()
  946. if (isRegExp) {
  947. const formData = refs?.getFormData()
  948. const {error, code} = await wbsApi.saveExcelBussData(formData)
  949. setDragModalLoading(dragItem)
  950. if (!error && code === 200) {
  951. if (showTip) {
  952. window?.$message?.success('保存成功')
  953. }
  954. return true
  955. } else {
  956. return false
  957. }
  958. } else {
  959. setDragModalLoading(dragItem)
  960. return false
  961. }
  962. }
  963. //预览PDF
  964. const getBussPdfInfo = async ({pkeyId}, dragItem = null, showTip = true) => {
  965. setDragModalLoading(dragItem, '获取pdf中...', true)
  966. const {error, code, data} = await wbsApi.getBussPdfInfo({
  967. pkeyId: pkeyId
  968. }, false)
  969. setDragModalLoading(dragItem)
  970. if (!error && code === 200) {
  971. if (data) {
  972. window.open(data, '_blank')
  973. } else if (showTip) {
  974. window?.$message?.warning('PDF错误')
  975. }
  976. } else {
  977. if (showTip) {
  978. window?.$message?.warning(data.msg || '获取PDF失败')
  979. }
  980. }
  981. }
  982. //通知数据更新
  983. const renewData = () => {
  984. emit('renew')
  985. ActiveKey.value = ''
  986. }
  987. //设置表单的加载状态
  988. const setDragModalLoading = (dragItem, text = '保存中...', show = false) => {
  989. if (dragItem && show) {
  990. dragItem.loading = true
  991. dragItem.loadingText = text
  992. }
  993. if (dragItem && !show) {
  994. dragItem.loading = false
  995. }
  996. }
  997. //获取表单的ref
  998. const getFormRef = async (pkeyId) => {
  999. const itemRef = itemRefs.value
  1000. const index = getIndex(itemRef, 'pkeyId', pkeyId)
  1001. return itemRef[index].ref
  1002. }
  1003. //删除打开的窗口
  1004. const delWindowRefs = (pkeyId) => {
  1005. //判断是否存在窗口,如果存在,就删除窗口
  1006. const list = DragModalTableForm.value
  1007. const index = getIndex(list, 'pkeyId', pkeyId)
  1008. if (index !== -1) {
  1009. list.splice(index, 1)
  1010. DragModalTableForm.value = list
  1011. }
  1012. }
  1013. //计算展开高度和滚动位置
  1014. const getOffsetTop = (key = '') => {
  1015. if (key) {
  1016. const dom = document.getElementById(key)
  1017. if (!draw_type.value) {
  1018. if (dom?.offsetTop >= 583 && key) {
  1019. emit('offsetTop', dom?.offsetTop - 583)
  1020. } else {
  1021. emit('offsetTop', dom?.offsetTop)
  1022. }
  1023. } else {
  1024. if (dom.offsetTop >= 424 && key) {
  1025. emit('offsetTop', dom?.offsetTop - 424)
  1026. } else {
  1027. emit('offsetTop', dom?.offsetTop)
  1028. }
  1029. }
  1030. } else {
  1031. emit('offsetTop', 0)
  1032. }
  1033. ActiveKey.value = key
  1034. }
  1035. //获取折叠面板的索引
  1036. const getCollapseItemIndex = (name) => {
  1037. const keys = name.split('-')
  1038. if (keys.length > 0) {
  1039. return keys[1]
  1040. } else {
  1041. return -1
  1042. }
  1043. }
  1044. //获取表单的大小
  1045. const getTableFormSize = (pkeyId) => {
  1046. let formId = `table-form-${pkeyId}`
  1047. try {
  1048. const {clientWidth, clientHeight} = document.getElementById(formId).children[0]
  1049. return {
  1050. width: (clientWidth + 40) + 'px',
  1051. height: (clientHeight + 80) + 'px'
  1052. }
  1053. } catch {
  1054. return {
  1055. width: '100%',
  1056. height: '100%'
  1057. }
  1058. }
  1059. }
  1060. //转字符串
  1061. const setToString = (val) => {
  1062. return val ? val + '' : ''
  1063. }
  1064. //表单被点击
  1065. const presentId = ref('')
  1066. const excelTableFormClick = (key) => {
  1067. presentId.value = key
  1068. }
  1069. //全局按键按下监听
  1070. document.onkeydown = async (event) => {
  1071. const pkeyId = presentId.value
  1072. if (!isValueNull(pkeyId)) {
  1073. const {key, ctrlKey} = event
  1074. //按下ctrl键
  1075. if (ctrlKey && key === 'Control') {
  1076. const refs = await getFormRef(pkeyId)
  1077. refs?.setIsCtrlKey(true)
  1078. }
  1079. //按下复制快捷键
  1080. if (ctrlKey && key === 'c') {
  1081. const refs = await getFormRef(pkeyId)
  1082. refs?.setCopyKeyList(event)
  1083. }
  1084. //按下粘贴快捷键
  1085. if (ctrlKey && key === 'v') {
  1086. const refs = await getFormRef(pkeyId)
  1087. await refs?.setPasteKeyList(event)
  1088. }
  1089. }
  1090. }
  1091. //全局键盘放开监听
  1092. document.onkeyup = async (event) => {
  1093. const pkeyId = presentId.value
  1094. if (!isValueNull(pkeyId)) {
  1095. const {key, ctrlKey} = event
  1096. if (!ctrlKey && key === 'Control') {
  1097. const refs = await getFormRef(pkeyId)
  1098. refs?.setIsCtrlKey(false)
  1099. }
  1100. }
  1101. }
  1102. //获取已渲染的表单
  1103. const getFilterFormData = async () => {
  1104. const formArr = formDataList.value;
  1105. return formArr.filter((item) => {
  1106. return (item.pkeyId ?? '') !== '' && item.isCollapseLoad;
  1107. })
  1108. }
  1109. //获取表单数据
  1110. const getFormData = async () => {
  1111. const formArr = await getFilterFormData();
  1112. //获取表单数据
  1113. let newArr = [];
  1114. for (let i = 0; i < formArr.length; i++) {
  1115. const pkeyId = formArr[i].pkeyId
  1116. const refs = await getFormRef(pkeyId)
  1117. const form = refs?.getFormData()
  1118. newArr.push({
  1119. ...form
  1120. })
  1121. }
  1122. return newArr
  1123. }
  1124. //获取表单效验数据
  1125. const getFormRegExpJson = async () => {
  1126. const formArr = await getFilterFormData();
  1127. const list = listDatas.value
  1128. //获取表单数据
  1129. let formRegExpJson = {};
  1130. for (let i = 0; i < formArr.length; i++) {
  1131. const pkeyId = formArr[i].pkeyId
  1132. const refs = await getFormRef(pkeyId)
  1133. const regExp = refs?.getRegExpJson()
  1134. const nodeName = refs?.getNodeName()
  1135. if (getObjNullValue(regExp)) {
  1136. const index = getIndex(list, 'pkeyId', pkeyId)
  1137. formRegExpJson[pkeyId] = {
  1138. ...regExp,
  1139. itemId: `item-${index}-${pkeyId}`,
  1140. nodeName: nodeName
  1141. }
  1142. }
  1143. }
  1144. return formRegExpJson
  1145. }
  1146. //获取当前展开项
  1147. const getActiveKey = () => {
  1148. return ActiveKey.value;
  1149. }
  1150. //设置当前展开项
  1151. const setActiveKey = (key) => {
  1152. return ActiveKey.value = key;
  1153. }
  1154. //卸载页面
  1155. onUnmounted(() => {
  1156. console.log('卸载页面')
  1157. document.onkeydown = null
  1158. document.onkeyup = null
  1159. })
  1160. // 暴露出去
  1161. defineExpose({
  1162. getFormData,
  1163. getFormRegExpJson,
  1164. getActiveKey,
  1165. setActiveKey
  1166. })
  1167. </script>
  1168. <style lang="scss" scoped>
  1169. @import "./index.scss";
  1170. </style>
  1171. <style lang="scss">
  1172. @import "./style.scss";
  1173. </style>