ListItem.vue 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. <template>
  2. <div class="data-fill-list-box">
  3. <el-collapse v-model="ActiveKey" accordion @change="CollapseChange">
  4. <template v-for="(item,index) in listDatas" :key="item?.pKeyId">
  5. <el-collapse-item :name="`item-${index}-${item?.pKeyId}`" :disabled="item['isBussShow'] === 2" :id="`item-${index}-${item?.pKeyId}`">
  6. <template #title>
  7. <div class="hc-collapse-item-header">
  8. <div class="text-lg truncate item-title">{{item.nodeName}}</div>
  9. <div class="hc-extra-text-box">
  10. <HcTooltip keys="wbs_del_table" v-if="item['isCopeTab'] === 2">
  11. <el-button type="danger" plain :disabled="item['isBussShow'] === 2" @click.stop="delClick(item,index)">删除本表</el-button>
  12. </HcTooltip>
  13. <HcTooltip keys="wbs_copy_table">
  14. <el-button type="primary" plain :disabled="item['isBussShow'] === 2" @click.stop="copyClick(item,index)">复制本表</el-button>
  15. </HcTooltip>
  16. <HcTooltip keys="wbs_hide_table">
  17. <el-button type="primary" plain @click.stop="hideClick(item,index)">
  18. <template v-if="item['isBussShow'] === 1">隐藏本表</template>
  19. <template v-else>显示本表</template>
  20. </el-button>
  21. </HcTooltip>
  22. <HcTooltip keys="wbs_preview_table">
  23. <el-button type="info" plain disabled v-if="item['isBussShow'] === 2 || item['isTabPdf'] === 1">预览</el-button>
  24. <el-button type="primary" plain @click.stop="previewClick(item,index)" v-else>预览</el-button>
  25. </HcTooltip>
  26. <HcTooltip keys="wbs_upload_table">
  27. <el-button :type="item['tabFileType'] === 2?'success':'primary'" plain :disabled="item['isBussShow'] === 2" @click.stop="uploadClick(item,index)">
  28. <template v-if="item['tabFileType'] === 2">已上传</template>
  29. <template v-else>上传</template>
  30. </el-button>
  31. </HcTooltip>
  32. </div>
  33. </div>
  34. </template>
  35. <div class="data-fill-list-item-content">
  36. <div class="data-fill-table-form-box">
  37. <div class="hc-excel-table-form-view" :id="`table-form-${item?.pKeyId}`"/>
  38. <div class="hc-no-table-form" v-if="item?.isTableForm === false">
  39. <div class="table-form-no">
  40. <img :src="notableform" alt=""/>
  41. <div class="desc">暂无表单数据</div>
  42. </div>
  43. </div>
  44. </div>
  45. <div class="data-fill-table-tip-box">
  46. <div class="text-orange tip-title">
  47. <HcIcon name="error" fill ui="text-2xl"/>
  48. <span class="ml-1">提示</span>
  49. </div>
  50. <div class="text-gray-400 tip-item">1、灰色框代表可通过系统识别计算,公式自动引用,可通过公式计算少量数据,(表头数据及简单),也可只填写白色框数据</div>
  51. <div class="text-gray-400 tip-item">2、系统支持键盘中,shift + tab键向上一个填报框切换,tab向下一个填报框切换。暂不支持上下按键切换输入框</div>
  52. <div class="table-tip-foot">
  53. <div class="tip-left-btn">
  54. <HcTooltip keys="wbs_import_table">
  55. <div class="text-gray-400 dow-text">
  56. <HcIcon name="publish" ui="text-lg"/>
  57. <span class="ml-1">导入列表数据</span>
  58. </div>
  59. </HcTooltip>
  60. <HcTooltip keys="wbs_download_table">
  61. <div class="text-main dow-text">
  62. <HcIcon name="file_download" ui="text-lg"/>
  63. <span class="ml-1">下载导入模板</span>
  64. </div>
  65. </HcTooltip>
  66. </div>
  67. <div class="tip-right-btn">
  68. <HcTooltip keys="wbs_save_table">
  69. <el-button type="primary" hc-btn :disabled="item?.isTableForm === false" :loading="tableFormSaveLoading" @click="tableFormSaveClick(item,index)">
  70. <HcIcon name="save"/>
  71. <span>保存</span>
  72. </el-button>
  73. </HcTooltip>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. </el-collapse-item>
  79. </template>
  80. </el-collapse>
  81. </div>
  82. <!--右键菜单-->
  83. <HcContextMenu ref="contextMenuRef" :datas="tableFormMenu" @item-click="handleMenuSelect"/>
  84. <!--上传文件-->
  85. <HcDialog :show="uploadModal" title="上传文件" widths="38rem" :footer="false" @close="uploadModal = false">
  86. <HcUpload :fileList="fileListData" :datas="uploadData" @change='uploadChange' :tableTypeValue="tableTypeValue" :contractId="contractId" :baseData="baseData"/>
  87. </HcDialog>
  88. <!--插入特殊字符-->
  89. <HcDialog :show="specialModal" title="插入特殊字符" widths="600px" saveText="确认插入" @close="specialModal = false" @save="specialNodeClick">
  90. <el-form ref="specialFormRef" :model="specialFormModel" :rules="specialFormRules" label-width="0px" size="large" class="mb-6">
  91. <el-form-item prop="val" class="special-form-item">
  92. <el-input v-model="specialFormModel.val" ref="specialRef" id="specialId" placeholder="请选择特殊字符代码" clearable @blur="specialInputBlur"/>
  93. </el-form-item>
  94. </el-form>
  95. <el-row :gutter="20" style="margin: -10px;">
  96. <el-col :span="3" style="padding: 10px;" v-for="item in specialCharacters">
  97. <div class="special-box" @click="specialClick">
  98. <span class="font-EUDC" :title="`字符代码(C):${item !== 'K̅'?item.slice(2,7):'K̅'}`" v-html="item"/>
  99. </div>
  100. </el-col>
  101. </el-row>
  102. </HcDialog>
  103. <!--引用容器参数-->
  104. <HcDialog :show="vesselModal" title="引用容器参数" widths="84%" saveText="确认引用" isTable @close="vesselModalClose" @save="vesselModalSave">
  105. <div class="adding-form-dialog-box">
  106. <div class="dialog-tree-box">
  107. <el-scrollbar>
  108. <HcMenuSimple :datas="menus" :props="menuProps" :keys="menuKey" @change="menuChange"/>
  109. </el-scrollbar>
  110. </div>
  111. <div class="dialog-table-box">
  112. <div class="dialog-table">
  113. <HcTable ref="vesselTableRef" :column="vesselTableColumn" :datas="vesselTableData" :loading="vesselTableLoading" isCheck @selection-change="vesselTableSelection"/>
  114. </div>
  115. <div class="dialog-pages">
  116. <HcPages :pages="vesselTablePage" @change="vesselTablePageChange"/>
  117. </div>
  118. </div>
  119. </div>
  120. </HcDialog>
  121. <!--引用设备仪器-->
  122. <HcDialog :show="deviceModal" title="引用设备仪器" widths="84%" saveText="确认引用" isTable @close="deviceModalClose" @save="deviceModalSave">
  123. <!-- <HcTable ref="deviceTableRef" :column="deviceTableColumn" :datas="deviceTableData" :loading="deviceTableLoading" isCheck @selection-change="deviceTableSelection"/> -->
  124. <div class="adding-form-dialog-box">
  125. <div class="dialog-tree-box">
  126. <el-scrollbar>
  127. <HcMenuSimple :datas="equipmentmenus" :props="equipmentmenuProps" :keys="equipmentmenuKey" @change="equipmentmenuChange"/>
  128. </el-scrollbar>
  129. </div>
  130. <div class="dialog-table-box">
  131. <div class="dialog-table">
  132. <HcTable ref="deviceTableRef" :column="deviceTableColumn" :datas="deviceTableData" :loading="deviceTableLoading" isCheck @selection-change="deviceTableSelection"/>
  133. </div>
  134. <div class="dialog-pages">
  135. <HcPages :pages="equipmentPage" @change="equipmentTablePageChange"/>
  136. </div>
  137. </div>
  138. </div>
  139. </HcDialog>
  140. </template>
  141. <script setup>
  142. import {ref,watch,nextTick} from "vue";
  143. import {useAppStore} from "~src/store";
  144. import {useRouter, useRoute} from 'vue-router'
  145. import wbsApi from "~api/data-fill/wbs"
  146. import HcUpload from "./HcUpload.vue"
  147. import HTableForm from "~src/plugins/HTableForm"
  148. import dataApi from "~api/tentative/detect/test";
  149. import dataApi1 from "~api/tentative/parameter/container"
  150. import dataApi2 from "~api/tentative/device/approach"
  151. import {getClassList} from "~api/tentative";
  152. import notableform from '~src/assets/view/notableform.svg';
  153. import {utilsText, isType, formValidate, deepClone} from "vue-utils-plus"
  154. const router = useRouter()
  155. const useRoutes = useRoute()
  156. //路由参数
  157. const routerQuery = useRoutes?.query;
  158. const isaddType = routerQuery?.isaddType || false;
  159. //初始
  160. const props = defineProps({
  161. datas: {
  162. type: Array,
  163. default: () => ([])
  164. },
  165. status: {
  166. type: [String,Number],
  167. default: ''
  168. },
  169. baseData: {
  170. type: Object,
  171. default: () => ({})
  172. },
  173. deviceUseIds:{
  174. type: String,
  175. default: () => ('')
  176. },
  177. authBtnTabKey:{
  178. type: String,
  179. default: () => ('')
  180. },
  181. checkTableId:{
  182. type: String,
  183. default: () => ('')
  184. }
  185. })
  186. const {isString, getObjNullValue, getArrValue} = isType()
  187. const {setPosInsert, setPosRange} = utilsText()
  188. const listDatas = ref(props.datas)
  189. const isStatus = ref(props.status)
  190. const baseData = ref(props.baseData)
  191. const authBtnTabKeyType = ref(props.authBtnTabKey)//所属方
  192. const useAppState = useAppStore()
  193. const projectId = ref(useAppState.getProjectId);
  194. const contractId = ref(useAppState.getContractId);
  195. //监听
  196. watch(() => [
  197. props.datas,
  198. ], ([datas]) => {
  199. listDatas.value = datas
  200. setFormDataNum(datas)
  201. })
  202. //监听
  203. watch(() => [
  204. props.status,
  205. props.baseData,
  206. ], ([val, base]) => {
  207. //1 未填报,2待上报,3已上报
  208. isStatus.value = val
  209. baseData.value = base
  210. })
  211. //渲染完成
  212. nextTick(() => {
  213. setFormDataNum(props.datas)
  214. })
  215. //获取pKeyId
  216. const getValString = (val) => {
  217. return val ? val + '' : ''
  218. }
  219. //获取表单初始数据
  220. const getFormDataInit = ({projectId, cid, pKeyId}) => {
  221. const { nodeId, contractId } = baseData.value
  222. return {
  223. projectId: projectId,
  224. contractId: cid || contractId,
  225. pkeyId: getValString(pKeyId),
  226. nodeId: nodeId
  227. }
  228. }
  229. //设置表单对象的数量
  230. const formData = ref([])
  231. const setFormDataNum = (datas) => {
  232. ActiveKey.value = ''
  233. let newArr = [];
  234. for (let i = 0; i < datas.length; i++) {
  235. newArr.push({
  236. ...getFormDataInit(datas[i]),
  237. isCollapseLoad: false,
  238. })
  239. }
  240. formData.value = newArr
  241. }
  242. //展开事件
  243. const ActiveKey = ref('')
  244. const formKeyIds = ref('')
  245. const CollapseChange = async (name) => {
  246. ActiveKey.value = name
  247. const names = name ? name.split('-') : []
  248. console.log(names[2]);
  249. formData.value.forEach((changeitem)=>{
  250. if(changeitem.pkeyId===names[2]){
  251. changeitem.isCollapseLoad=true
  252. }
  253. })
  254. if (names.length > 0) {
  255. getOffsetTop(name)
  256. const index = names[1]
  257. const item = listDatas.value[index]
  258. emit('upcheckTableId', item.id)
  259. formKeyIds.value = getValString(item.pKeyId)
  260. if (!item.isTableFormRender) {
  261. //获取已填写的数据
  262. if(!isaddType){
  263. await getBussDataInfo(item, index)
  264. }
  265. //渲染表单
  266. await getExcelHtml(item,index)
  267. }
  268. } else {
  269. getOffsetTop()
  270. formKeyIds.value = ''
  271. }
  272. }
  273. //获取模板标签数据
  274. const formRegExpJson = ref({})
  275. const getExcelHtml = async (item,index) => {
  276. const pkeyIds = getValString(item.pKeyId)
  277. if (pkeyIds) {
  278. const { id } = baseData.value
  279. const {error, code, data} = await dataApi.getExcelHtml({
  280. id: id,
  281. primaryKeyId: pkeyIds
  282. }, false)
  283. const resData = isString(data) ? data || '' : ''
  284. if (!error && code === 200 && resData) {
  285. item.isTableForm = true
  286. //渲染表单
  287. HTableForm.createForm({
  288. template: resData,
  289. tableForm: formData.value[index],
  290. appId: `#table-form-${pkeyIds}`,
  291. onRight: (event, KeyName) => {
  292. onRightClick(event, KeyName, index)
  293. },
  294. //表单正则效验
  295. onBlur: (event, key, reg, val, msg) => {
  296. setTableFormBlurReg(pkeyIds, event, key, reg, val, msg, item, index)
  297. }
  298. })
  299. item.isTableFormRender = true
  300. item.isRenderTableForm = true
  301. } else {
  302. item.isTableForm = false
  303. item.isRenderTableForm = true
  304. window?.$message?.warning('暂无表单')
  305. }
  306. } else {
  307. item.isTableForm = false
  308. item.isRenderTableForm = false
  309. window?.$message?.warning('pkeyId为空')
  310. }
  311. }
  312. //正则效验
  313. const setTableFormBlurReg = (pkeyId, event, key, reg, val, msg, item, index) => {
  314. const dom = document.getElementById(key)?.parentElement ?? ''
  315. if (dom) {
  316. if (val && reg) {
  317. let regx = new RegExp(reg);
  318. let state = regx.test(val);
  319. if (state) {
  320. delete formRegExpJson.value[pkeyId]
  321. dom.style = ''
  322. } else {
  323. formRegExpJson.value[pkeyId] = {key, reg, val, msg, state, nodeName: item.nodeName, itemId: `item-${index}-${item?.pKeyId}`}
  324. dom.style = '--el-input-border-color: #fe0000; box-shadow: 0 0 0 2px #fe0000 inset;'
  325. window?.$message?.warning(msg)
  326. }
  327. } else {
  328. delete formRegExpJson.value[pkeyId]
  329. dom.style = ''
  330. }
  331. }
  332. }
  333. //获取已填写的数据
  334. const getBussDataInfo = async (item, index) => {
  335. const pkeyIds = getValString(item.pKeyId)
  336. if (pkeyIds) {
  337. const { id } = baseData.value
  338. const {error, code, data} = await dataApi.getBussDataInfo({
  339. id: id,
  340. pkeyId: pkeyIds
  341. }, false)
  342. data.forEach((item1)=>{
  343. const resData = getObjNullValue(item1)
  344. if (!error && code === 200 && resData) {
  345. HTableForm.setPickerKey(resData)
  346. const InitObj = getFormDataInit(item) //有数据,关联数据
  347. formData.value[index] = {
  348. ...resData, ...InitObj,
  349. isCollapseLoad: true
  350. }
  351. }else {
  352. formData.value[index] = {
  353. ...getFormDataInit(item),
  354. isCollapseLoad: true
  355. }
  356. }
  357. })
  358. // if (!error && code === 200 && resData) {
  359. // HTableForm.setPickerKey(resData)
  360. // const InitObj = getFormDataInit(item) //有数据,关联数据
  361. // formData.value[index] = {
  362. // ...resData, ...InitObj,
  363. // isCollapseLoad: true
  364. // }
  365. // } else {
  366. // formData.value[index] = {
  367. // ...getFormDataInit(item),
  368. // isCollapseLoad: true
  369. // }
  370. // }
  371. } else {
  372. window?.$message?.warning('pkeyId为空')
  373. }
  374. }
  375. const toBackClick = () => {
  376. router.push({
  377. path: '/tentative/detect/test',
  378. query: {}
  379. })
  380. }
  381. //单个保存
  382. const tableFormSaveLoading = ref(false)
  383. const tableFormSaveClick = async (item,index) => {
  384. if (isStatus.value !== '3') {
  385. const res = await saveExcelBussData(item,index)
  386. if (res) {
  387. if(!isaddType){
  388. await getBussPdfInfo(item)
  389. }else{
  390. //返回
  391. toBackClick()
  392. }
  393. renewData()
  394. }
  395. } else {
  396. window?.$message?.warning('已上报的资料,不允许保存。')
  397. }
  398. }
  399. //保存表单数据
  400. const saveExcelBussData = async (item, index, showTip = true) => {
  401. if (!getObjNullValue(formRegExpJson.value)) {
  402. tableFormSaveLoading.value = true
  403. const InitObj = getFormDataInit(item)
  404. const {error, code} = await dataApi.saveExcelBussData({
  405. ...baseData.value,
  406. isBatchSave:0,
  407. dataInfo: {
  408. orderList: [{...formData.value[index], ...InitObj}]
  409. }
  410. })
  411. //处理数据
  412. tableFormSaveLoading.value = false
  413. if (!error && code === 200) {
  414. if(showTip) window?.$message?.success('保存成功')
  415. return true
  416. } else {
  417. return false
  418. }
  419. } else {
  420. window?.$message?.warning('请先修改完红色输入框的数据')
  421. return false
  422. }
  423. }
  424. //预览PDF
  425. const getBussPdfInfo = async ({pKeyId}, showTip = true) => {
  426. const pkeyIds = getValString(pKeyId)
  427. if (pkeyIds) {
  428. const { id } = baseData.value
  429. const {error, code, data} = await dataApi.getBussPdf({
  430. id: id,
  431. pKeyId: pkeyIds
  432. },false)
  433. if (!error && code === 200) {
  434. if (data) {
  435. window.open(data, '_blank')
  436. } else if(showTip) {
  437. window?.$message?.warning('PDF错误')
  438. }
  439. } else {
  440. if(showTip) {
  441. window?.$message?.warning(data.msg || '获取PDF失败')
  442. }
  443. }
  444. } else {
  445. window?.$message?.warning('pkeyId为空')
  446. }
  447. }
  448. //删除本表
  449. const delClick = async ({pKeyId}) => {
  450. const pkeyIds = getValString(pKeyId)
  451. if (pkeyIds) {
  452. const { id } = baseData.value
  453. const {error, code} = await dataApi.removeBussTabInfo({
  454. id: id,
  455. pKeyId: pkeyIds
  456. })
  457. if (!error && code === 200) {
  458. window?.$message?.success('操作成功')
  459. renewData()
  460. }
  461. } else {
  462. window?.$message?.warning('pkeyId为空')
  463. }
  464. }
  465. //复制本表
  466. const copyClick = async (item,index) => {
  467. const pkeyIds = getValString(item.pKeyId)
  468. if (pkeyIds) {
  469. if (isStatus.value !== '3') {
  470. if (!item.isRenderTableForm) {
  471. await copeBussTab(pkeyIds)
  472. } else if (!item.isTableForm) {
  473. window?.$message?.warning('暂无表单数据')
  474. } else if (item.isRenderTableForm) {
  475. const res = await saveExcelBussData(item,index,false)
  476. if (res) {
  477. await copeBussTab(pkeyIds)
  478. } else {
  479. window?.$message?.warning('复制本表操作失败')
  480. }
  481. } else {
  482. window?.$message?.warning(`数据异常了, isRenderTableForm: ${item.isRenderTableForm}, isTableForm: ${item.isTableForm}, pKeyId:${pkeyIds}`)
  483. }
  484. } else {
  485. window?.$message?.warning('已上报的资料,不允许复制')
  486. }
  487. } else {
  488. window?.$message?.warning('pkeyId为空')
  489. }
  490. }
  491. const copeBussTab = async (pkeyIds) => {
  492. const { id } = baseData.value
  493. const {error, code} = await dataApi.copyBussTab({
  494. id: id,
  495. pKeyId: pkeyIds
  496. })
  497. if (!error && code === 200) {
  498. window?.$message?.success('操作成功')
  499. renewData()
  500. }
  501. }
  502. //隐藏本表
  503. const hideClick = async ({pKeyId, isBussShow}) => {
  504. const pkeyIds = getValString(pKeyId)
  505. if (pkeyIds) {
  506. if (isStatus.value !== '3') {
  507. const { id } = baseData.value
  508. const isBussShows = isBussShow === 2 ? 1 : 2 //状态(1显示 2隐藏)
  509. const {error, code} = await dataApi.showBussTab({
  510. id: id,
  511. pKeyId: pkeyIds,
  512. status: isBussShows
  513. })
  514. if (!error && code === 200) {
  515. window?.$message?.success('操作成功')
  516. renewData()
  517. }
  518. } else {
  519. window?.$message?.warning('已上报的资料,不允许隐藏')
  520. }
  521. } else {
  522. window?.$message?.warning('pkeyId为空')
  523. }
  524. }
  525. //预览
  526. const previewClick = async (item,index) => {
  527. await getBussPdfInfo(item)
  528. }
  529. //上传变量
  530. const uploadModal = ref(false)
  531. const fileListData = ref([]);
  532. const uploadData = ref({})
  533. const tableTypeValue=ref('')
  534. //上传被点击
  535. const uploadClick = (item,index) => {
  536. const pkeyIds = item.pKeyId ? item.pKeyId + '' : ''
  537. const { id } = baseData.value
  538. const tableType = item.tableType ? item.tableType : ''
  539. tableTypeValue.value= item.tableType ? item.tableType : ''
  540. const classify = authBtnTabKeyType.value
  541. const keyName = `item-${index}-${pkeyIds}`
  542. if (pkeyIds) {
  543. if (isStatus.value !== '3' && item.isTableForm) {
  544. uploadModal.value = true
  545. uploadData.value = getFormDataInit(item,pkeyIds)
  546. uploadData.value.tableType =tableType
  547. uploadData.value.classify =classify
  548. uploadData.value.id =id
  549. console.log( uploadData.value,' uploadData.value');
  550. //获取文件列表
  551. getBussFileList(pkeyIds)
  552. } else if (!item.isRenderTableForm) {
  553. CollapseChange(keyName)
  554. window?.$message?.warning('请再次点击上传')
  555. } else if (!item.isTableForm) {
  556. window?.$message?.warning('暂无表单数据')
  557. } else {
  558. window?.$message?.warning('已上报的资料,不允许上传')
  559. }
  560. } else {
  561. window?.$message?.warning('pkeyId为空')
  562. }
  563. }
  564. //获取文件列表
  565. const getBussFileList = async (pkeyId) => {
  566. const { id } = baseData.value
  567. const {error, code, data} = await wbsApi.getBussFileList1({
  568. pkeyid: pkeyId,
  569. id:id
  570. })
  571. if (!error && code === 200) {
  572. fileListData.value = getArrValue(data)
  573. } else {
  574. fileListData.value = []
  575. }
  576. }
  577. //上传文件
  578. const uploadChange = async ({type}) => {
  579. if(type === 'success') {
  580. uploadModal.value = false
  581. renewData()
  582. } else if (type === 'del') {
  583. renewData()
  584. }
  585. }
  586. //相关变量
  587. const tableFormItemNode = ref({})
  588. //菜单数据
  589. const tableFormMenu = ref([
  590. {label: '容器参数', key: "vessel"},
  591. {label: '引用设备仪器', key: "device"},
  592. {label: '插入特殊字符', key: "special"},
  593. ])
  594. //鼠标右键事件
  595. const contextMenuRef = ref(null)
  596. const onRightClick = (event, KeyName, index) => {
  597. //取光标位置
  598. const specialDom = document.getElementById(KeyName + "")
  599. const startPos = specialDom?.selectionStart || 0
  600. const endPos = specialDom?.selectionEnd || 0
  601. //存储临时信息
  602. tableFormItemNode.value = {KeyName, index, startPos, endPos, pkeyId: formKeyIds.value}
  603. contextMenuRef.value?.showMenu(event) //展开菜单
  604. }
  605. //鼠标右键菜单被点击
  606. const handleMenuSelect = ({key}) => {
  607. if (key === 'vessel') {
  608. vesselModal.value = true
  609. getMenusData()
  610. } else if (key === 'special') {
  611. specialModalShow()
  612. } else if (key === 'device') {
  613. deviceModal.value = true
  614. getequipmentMenusData()
  615. }
  616. }
  617. //引用容器参数
  618. const vesselModal = ref(false)
  619. const vesselTableRef = ref(null)
  620. //引用容器参数菜单数据
  621. const menuProps = {
  622. key: 'id',
  623. label: 'containerName',
  624. }
  625. //引用容器参数菜单数据
  626. const equipmentmenuProps = {
  627. key: 'id',
  628. label: 'className',
  629. }
  630. const menus = ref([]);
  631. const getMenusData = async () => {
  632. const { data } = await dataApi1.queryClassification({
  633. projectId: projectId.value,
  634. contractId: contractId.value
  635. })
  636. const arr = getArrValue(data)
  637. menus.value = arr
  638. if (arr.length > 0) {
  639. const item = arr[0]
  640. console.log(item,'item');
  641. menuItem.value = item
  642. menuKey.value = item?.id
  643. getVesselTableData()
  644. }
  645. }
  646. //菜单被点击
  647. const menuKey = ref()
  648. const menuItem = ref({})
  649. const menuChange = (item) => {
  650. menuItem.value = item
  651. menuKey.value = item?.id
  652. getVesselTableData()
  653. }
  654. //表格数据
  655. const vesselTableColumn = ref([
  656. {key:'key_1', name: '容器编号'},
  657. ])
  658. const vesselTableData = ref([])
  659. const vesselTablePage = ref({current: 1, size: 20, total: 0})
  660. const vesselTablePageChange = ({current, size}) => {
  661. vesselTablePage.value.current = current
  662. vesselTablePage.value.size = size
  663. getVesselTableData()
  664. }
  665. //获取表格数据
  666. const vesselTableLoading = ref(false)
  667. const getVesselTableData = async () => {
  668. const {id, fieldList} = menuItem.value
  669. const fieldLists = getArrValue(fieldList)
  670. if (fieldLists.length > 0) {
  671. vesselTableLoading.value = true
  672. const { error, code, data } = await dataApi1.queryPage({
  673. projectId: projectId.value,
  674. contractId: contractId.value,
  675. containerId: menuKey.value,
  676. fieldKey:fieldList[0].fieldKey,
  677. size:vesselTablePage.value.size,
  678. current:vesselTablePage.value.current,
  679. })
  680. //处理数据
  681. vesselTableLoading.value = false
  682. if (!error && code === 200) {
  683. vesselTableData.value = getArrValue(data['records'])
  684. vesselTablePage.value.total = data.total || 0
  685. } else {
  686. vesselTableData.value = []
  687. vesselTablePage.value.total = 0
  688. }
  689. }
  690. }
  691. //多选
  692. const vesselTableKeys = ref([]);
  693. const vesselTableSelection = (rows) => {
  694. vesselTableKeys.value = rows
  695. }
  696. //确认引用
  697. const vesselModalSave = () => {
  698. if (vesselTableKeys.value.length>0) {
  699. const item = tableFormItemNode.value
  700. const form = formData.value[item.index]
  701. const val =[]
  702. vesselTableKeys.value.forEach((item)=>{
  703. val.push(item.key_1)
  704. })
  705. const newval=val.join('、')
  706. formData.value[item.index][item.KeyName] = setPosInsert(item.startPos, item.endPos, form[item.KeyName], newval)
  707. vesselModal.value = false
  708. let posVal = item.startPos + newval.length;
  709. nextTick(() => {
  710. setPosRange(item.KeyName, posVal)
  711. })
  712. }else{
  713. window?.$message?.warning('请先选择引用容器参数')
  714. }
  715. }
  716. //关闭
  717. const vesselModalClose = () => {
  718. vesselModal.value = false
  719. }
  720. const equipmentmenus = ref([]);
  721. const getequipmentMenusData = async () => {
  722. const { data } = await getClassList({
  723. projectId: projectId.value,
  724. contractId: contractId.value
  725. })
  726. const arr = getArrValue(data)
  727. equipmentmenus.value = arr
  728. if (arr.length > 0) {
  729. const item = arr[0]
  730. equipmentmenuItem.value = item
  731. equipmentmenuKey.value = item?.id
  732. getDeviceTableData()
  733. }
  734. }
  735. //菜单被点击
  736. const equipmentmenuKey = ref()
  737. const equipmentmenuItem = ref({})
  738. const equipmentmenuChange = (item) => {
  739. equipmentmenuItem.value = item
  740. equipmentmenuKey.value = item?.id
  741. getDeviceTableData()
  742. }
  743. //引用设备仪器
  744. const deviceModal = ref(false)
  745. const deviceTableRef = ref(null)
  746. //表格数据
  747. const deviceTableColumn = ref([
  748. {key:'deviceNumber', name: '设备编号'},
  749. {key:'deviceName', name: '设备仪器名称'},
  750. ])
  751. const deviceTableData = ref([])
  752. const equipmentPage = ref({current: 1, size: 20, total: 0})
  753. const equipmentTablePageChange = ({current, size}) => {
  754. equipmentPage.value.current = current
  755. equipmentPage.value.size = size
  756. getDeviceTableData()
  757. }
  758. //获取表格数据
  759. const deviceTableLoading = ref(false)
  760. const getDeviceTableData =async () => {
  761. deviceTableLoading.value = true
  762. const { error, code, data } = await dataApi2.queryPage({
  763. projectId: projectId.value,
  764. contractId: contractId.value,
  765. deviceClassId: equipmentmenuKey.value,
  766. size:equipmentPage.value.size,
  767. current:equipmentPage.value.current,
  768. })
  769. //处理数据
  770. deviceTableLoading.value = false
  771. if (!error && code === 200) {
  772. deviceTableData.value = getArrValue(data['records'])
  773. vesselTablePage.value.total = data.total || 0
  774. } else {
  775. deviceTableData.value = []
  776. equipmentPage.value.total = 0
  777. }
  778. }
  779. //多选
  780. const deviceTableKeys = ref([]);
  781. const deviceTableSelection = (rows) => {
  782. deviceTableKeys.value = rows
  783. }
  784. //确认引用
  785. const deviceModalSave = () => {
  786. if (deviceTableKeys.value.length>0) {
  787. const item = tableFormItemNode.value
  788. const form = formData.value[item.index]
  789. const val =[]
  790. const idarr=[]
  791. const listr=[]
  792. deviceTableKeys.value.forEach((item)=>{
  793. val.push(item.deviceNumber)
  794. idarr.push(item.id)
  795. listr.push(item.deviceNumber+"_"+item.deviceName)
  796. })
  797. const newval=listr.join('、');
  798. const idval=idarr.join(',')
  799. formData.value[item.index][item.KeyName] = setPosInsert(item.startPos, item.endPos, form[item.KeyName], newval)
  800. vesselModal.value = false
  801. let posVal = item.startPos + newval.length;
  802. nextTick(() => {
  803. setPosRange(item.KeyName, posVal)
  804. })
  805. deviceModal.value = false;
  806. emit('updeviceUseIds', idval)
  807. }else{
  808. window?.$message?.warning('请先选择引用容器设备')
  809. }
  810. }
  811. //关闭
  812. const deviceModalClose = () => {
  813. deviceModal.value = false
  814. }
  815. //插入特殊字符
  816. const specialModal = ref(false)
  817. const specialCharacters = ref([
  818. '&#57344;', "&#57345;", "&#57346;", "&#57347;", '&#8804;', '&#8805;', '&#8451;',
  819. '&#9312;', '&#9313;', '&#9314;', '&#9315;', '&#9316;', '&#9317;', '&#9318;', '&#9319;', '&#9320;', '&#9321;', '&#9322;', '&#9323;',
  820. '&#9324;', '&#9325;', '&#9326;', '&#9327;', '&#9328;', '&#9329;', '&#9330;', '&#9331;',
  821. "&#8544;", "&#8545;", "&#8546;", "&#8547;", "&#8548;", "&#8549;", "&#8550;", "&#8551;", "&#8552;", "&#8553;", "&#8554;", "&#8555;","K̅"
  822. ])
  823. //输入框验证
  824. const specialFormRef = ref(null)
  825. const specialFormModel = ref({val: ''})
  826. const specialFormRules = {
  827. val: {
  828. required: true,
  829. trigger: "blur",
  830. message: "请选择特殊字符代码"
  831. }
  832. }
  833. //显示插入特殊字符
  834. const specialRef = ref(null)
  835. const specialModalShow = () => {
  836. specialFormModel.value.val = ''
  837. specialModal.value = true
  838. nextTick(() => {
  839. specialRef.value?.focus();
  840. })
  841. }
  842. //失去焦点
  843. const specialPos = ref({start: 0, end: 0})
  844. const specialInputBlur = (e) => {
  845. specialPos.value = {
  846. start: e?.target?.selectionStart || 0,
  847. end: e?.target?.selectionEnd || 0
  848. }
  849. }
  850. //点击符号
  851. const specialClick = (event) => {
  852. const text = event?.target?.innerText ?? ''
  853. const start = specialPos.value.start
  854. const end = specialPos.value.end
  855. const form = specialFormModel.value.val
  856. specialFormModel.value.val = setPosInsert(start, end, form, text)
  857. specialRef.value?.focus();
  858. let posVal = start + text.length;
  859. nextTick(() => {
  860. setPosRange('specialId', posVal)
  861. })
  862. }
  863. //确认插入
  864. const specialNodeClick = async () => {
  865. const res = await formValidate(specialFormRef.value)
  866. if (res) {
  867. const item = tableFormItemNode.value
  868. const form = formData.value[item.index]
  869. const val = specialFormModel.value.val ?? ''
  870. formData.value[item.index][item.KeyName] = setPosInsert(item.startPos, item.endPos, form[item.KeyName], val)
  871. specialModal.value = false
  872. specialRef.value?.focus();
  873. let posVal = item.startPos + val.length;
  874. nextTick(() => {
  875. setPosRange(item.KeyName, posVal)
  876. })
  877. }
  878. }
  879. //事件
  880. const emit = defineEmits(['renew','offsetTop','updeviceUseIds','upcheckTableId'])
  881. //被点击
  882. const getOffsetTop = (key = '') => {
  883. if (key) {
  884. const dom = document.getElementById(key)
  885. emit('offsetTop', dom.offsetTop)
  886. } else {
  887. emit('offsetTop', 0)
  888. }
  889. }
  890. //通知数据更新
  891. const renewData = () => {
  892. emit('renew')
  893. ActiveKey.value = ''
  894. }
  895. //获取表单数据
  896. const getFormData = () => {
  897. const formArr = formData.value;
  898. console.log( formData.value,' formData.value');
  899. return formArr.filter(({pkeyId, isCollapseLoad}) => {
  900. return (pkeyId ?? '') !== '' && isCollapseLoad;
  901. })
  902. }
  903. //获取表单效验数据
  904. const getFormRegExpJson = () => {
  905. return deepClone(formRegExpJson.value);
  906. }
  907. //获取当前展开项
  908. const getActiveKey = () => {
  909. return ActiveKey.value;
  910. }
  911. //设置当前展开项
  912. const setActiveKey = (key) => {
  913. return ActiveKey.value = key;
  914. }
  915. // 暴露出去
  916. defineExpose({
  917. getFormData,
  918. getFormRegExpJson,
  919. getActiveKey,
  920. setActiveKey
  921. })
  922. </script>
  923. <style lang="scss" scoped>
  924. .data-fill-list-box {
  925. position: relative;
  926. //margin-bottom: 25%;
  927. .hc-collapse-item-header {
  928. flex: 1;
  929. position: relative;
  930. margin-left: 46px;
  931. display: flex;
  932. align-items: center;
  933. .item-title {
  934. flex: 1;
  935. position: relative;
  936. user-select: none;
  937. color: #50545E;
  938. font-size: 16px;
  939. font-weight: 400;
  940. cursor: pointer;
  941. }
  942. .hc-extra-text-box {
  943. position: relative;
  944. padding-right: 24px;
  945. }
  946. }
  947. .data-fill-list-item-content {
  948. position: relative;
  949. display: flex;
  950. height: calc(100vh - 428px);
  951. .data-fill-table-form-box {
  952. position: relative;
  953. padding: 24px 20px;
  954. height: 100%;
  955. overflow: auto;
  956. flex: 1;
  957. .hc-no-table-form {
  958. position: relative;
  959. height: 100%;
  960. display: flex;
  961. justify-content: center;
  962. align-items: center;
  963. .table-form-no {
  964. position: relative;
  965. img {
  966. width: 350px;
  967. }
  968. .desc {
  969. text-align: center;
  970. font-size: 20px;
  971. color: #aaa;
  972. }
  973. }
  974. }
  975. }
  976. .data-fill-table-tip-box {
  977. width: 240px;
  978. position: relative;
  979. border-left: 1px solid #E9E9E9;
  980. padding: 20px 15px 80px;
  981. .tip-title {
  982. font-size: 16px;
  983. margin-bottom: 10px;
  984. display: flex;
  985. align-items: center;
  986. }
  987. .tip-item {
  988. margin-bottom: 20px;
  989. }
  990. .table-tip-foot {
  991. position: absolute;
  992. bottom: 15px;
  993. right: 0;
  994. left: 0;
  995. display: flex;
  996. align-items: center;
  997. padding: 0 15px;
  998. .tip-left-btn {
  999. flex: 1;
  1000. .dow-text {
  1001. cursor: pointer;
  1002. display: flex;
  1003. align-items: center;
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. }
  1010. .special-box {
  1011. position: relative;
  1012. display: flex;
  1013. justify-content: center;
  1014. align-items: center;
  1015. border: 1px solid #eee;
  1016. border-radius: 3px;
  1017. height: 52px;
  1018. width: 52px;
  1019. cursor: pointer;
  1020. user-select: none;
  1021. transition: color .3s, background-color .3s;
  1022. &:hover {
  1023. color: var(--el-color-primary);
  1024. background-color: var(--el-color-primary-light-8);
  1025. }
  1026. .font-EUDC {
  1027. font-size: 22px;
  1028. }
  1029. }
  1030. </style>
  1031. <style lang="scss">
  1032. .data-fill-list-box {
  1033. .el-collapse {
  1034. --el-collapse-header-height: 60px;
  1035. border: 0;
  1036. .el-collapse-item {
  1037. margin: 0 0 16px;
  1038. background-color: #f1f5f8;
  1039. border: 1px solid #E9E9E9;
  1040. border-radius: 4px;
  1041. }
  1042. .el-collapse-item__header {
  1043. background-color: transparent;
  1044. font-weight: 400;
  1045. border-bottom: 0;
  1046. cursor: default;
  1047. font-size: 14px;
  1048. .el-collapse-item__arrow {
  1049. position: absolute;
  1050. color: #50545E;
  1051. cursor: pointer;
  1052. left: 20px;
  1053. margin: 0;
  1054. }
  1055. }
  1056. .el-collapse-item.is-active .el-collapse-item__header.is-active {
  1057. background-color: #E7EEF4;
  1058. }
  1059. .el-collapse-item__wrap {
  1060. background-color: transparent;
  1061. border-bottom: 0;
  1062. .el-collapse-item__content {
  1063. position: relative;
  1064. padding-bottom: 0;
  1065. font-size: 14px;
  1066. color: #50545E;
  1067. line-height: initial;
  1068. }
  1069. }
  1070. }
  1071. }
  1072. //插入特殊字符弹窗的输入框
  1073. .data-fill-list-box .data-fill-table-form-box td,
  1074. .data-fill-list-box .data-fill-table-form-box td .el-input .el-input__wrapper .el-input__inner,
  1075. .el-form-item.special-form-item .el-form-item__content .el-input .el-input__wrapper .el-input__inner {
  1076. font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  1077. }
  1078. //引用容器参数弹窗
  1079. //关联试验数据
  1080. .adding-form-dialog-box {
  1081. position: relative;
  1082. height: 100%;
  1083. display: flex;
  1084. .dialog-tree-box {
  1085. position: relative;
  1086. border-right: 1px solid #EEEEEE;
  1087. width: 500px;
  1088. height: 100%
  1089. }
  1090. .dialog-table-box {
  1091. position: relative;
  1092. flex: 1;
  1093. height: 100%;
  1094. padding: 18px;
  1095. .dialog-search {
  1096. position: relative;
  1097. display: flex;
  1098. }
  1099. .dialog-table {
  1100. position: relative;
  1101. height: calc(100% - 68px);
  1102. padding: 18px 0;
  1103. }
  1104. .dialog-pages {
  1105. position: relative;
  1106. }
  1107. }
  1108. }
  1109. </style>