plm前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2930 lines
119 KiB

  1. <template>
  2. <div class="mod-config">
  3. <el-form :inline="true" label-position="top" :model="searchData">
  4. <el-form-item label="序列号">
  5. <el-input v-model="searchData.referenceNo" clearable style="width: 140px"></el-input>
  6. </el-form-item>
  7. <el-form-item label="单据状态">
  8. <el-select v-model="searchData.status" clearable style="width: 120px">
  9. <el-option label="草稿" value="草稿"></el-option>
  10. <el-option label="审批中" value="审批中"></el-option>
  11. <el-option label="已完成" value="已完成"></el-option>
  12. </el-select>
  13. </el-form-item>
  14. <el-form-item label="节点审批人">
  15. <el-input v-model="searchData.currentApprover" clearable style="width: 120px"></el-input>
  16. </el-form-item>
  17. <el-form-item label="当前节点">
  18. <el-select v-model="searchData.nodeId" placeholder="请选择节点" clearable style="width: 140px">
  19. <el-option
  20. v-for="option in nodeOptions"
  21. :key="option.id"
  22. :label="option.name"
  23. :value="option.id">
  24. </el-option>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item :label="' '">
  28. <el-button v-if="authSearch" @click="getDataList">查询</el-button>
  29. <el-button v-if="authUpdate" @click="addOrUpdateHandle()">新增</el-button>
  30. <el-button v-if="authDelete" type="danger" @click="deleteHandle()">删除</el-button>
  31. <download-excel
  32. v-if="authSearch"
  33. :fields="exportFieldMap"
  34. :data="exportData"
  35. type="xls"
  36. :name="exportName"
  37. :header="exportHeader"
  38. :footer="exportFooter"
  39. :fetch="createExportData"
  40. :before-generate="startDownload"
  41. :before-finish="finishDownload"
  42. worksheet="导出信息"
  43. :class="['el-button', 'el-button--primary', 'el-button--medium', {'is-loading': exportLoading}]">
  44. <i v-if="exportLoading" class="el-icon-loading"></i>
  45. <span>导出</span>
  46. </download-excel>
  47. <el-button v-if="authSearch" @click="searchHandle()">搜索</el-button>
  48. </el-form-item>
  49. </el-form>
  50. <el-table
  51. ref="labTable"
  52. :height="height"
  53. :data="dataList"
  54. border
  55. :row-style="rowStyle"
  56. @row-click="changeClickRow"
  57. @current-change="currentChange"
  58. @selection-change="dataListSelectionChange"
  59. v-loading="dataListLoading"
  60. style="width: 100%;">
  61. <el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
  62. <el-table-column prop="referenceNo" header-align="center" align="center" label="序列号" width="180"></el-table-column>
  63. <el-table-column prop="status" header-align="center" align="center" label="单据状态" width="110"></el-table-column>
  64. <el-table-column prop="nodeName" header-align="center" align="center" label="当前节点" width="140"></el-table-column>
  65. <el-table-column prop="currentApprover" header-align="center" align="center" label="当前审批人" width="150"></el-table-column>
  66. <el-table-column prop="applicant" header-align="center" align="center" label="申请人编码" width="120"></el-table-column>
  67. <el-table-column prop="applicantName" header-align="center" align="center" label="申请人名称" width="140"></el-table-column>
  68. <el-table-column prop="applicationDate" header-align="center" align="center" label="申请日期" width="120">
  69. <template slot-scope="scope">
  70. <span>{{ normalizeDateOnly(scope.row.applicationDate) }}</span>
  71. </template>
  72. </el-table-column>
  73. <el-table-column prop="applyDepartment" header-align="center" align="center" label="申请部门" width="150"></el-table-column>
  74. <el-table-column prop="requestedDate" header-align="center" align="center" label="需求日期" width="120">
  75. <template slot-scope="scope">
  76. <span>{{ normalizeDateOnly(scope.row.requestedDate) }}</span>
  77. </template>
  78. </el-table-column>
  79. <el-table-column prop="customerId" header-align="center" align="center" label="客户编码" width="120"></el-table-column>
  80. <el-table-column prop="customerName" header-align="center" align="center" label="客户名称" width="160"></el-table-column>
  81. <el-table-column prop="projectId" header-align="center" align="center" label="项目编码" width="130"></el-table-column>
  82. <el-table-column prop="projectName" header-align="center" align="center" label="项目名称" width="170"></el-table-column>
  83. <el-table-column prop="sampleName" header-align="center" align="center" label="样品名称" width="150"></el-table-column>
  84. <el-table-column prop="sampleModel" header-align="center" align="center" label="样品型号" width="150"></el-table-column>
  85. <el-table-column prop="sampleQty" header-align="center" align="center" label="样品数量" width="100"></el-table-column>
  86. <el-table-column prop="productStage" header-align="center" align="center" label="产品阶段" width="120"></el-table-column>
  87. <el-table-column prop="testType" header-align="center" align="center" label="测试类型" width="120"></el-table-column>
  88. <el-table-column prop="reportDocument" header-align="center" align="center" label="报告出具" width="120"></el-table-column>
  89. <el-table-column prop="returnSample" header-align="center" align="center" label="样品退回" width="100">
  90. <template slot-scope="scope">
  91. <span>{{ displayYesNo(scope.row.returnSample) }}</span>
  92. </template>
  93. </el-table-column>
  94. <el-table-column prop="testLab" header-align="center" align="center" label="测试实验室" width="140"></el-table-column>
  95. <el-table-column prop="testStartDate" header-align="center" align="center" label="测试开始时间" width="120">
  96. <template slot-scope="scope">
  97. <span>{{ normalizeDateOnly(scope.row.testStartDate) }}</span>
  98. </template>
  99. </el-table-column>
  100. <el-table-column prop="completedDate" header-align="center" align="center" label="测试完成日期" width="120">
  101. <template slot-scope="scope">
  102. <span>{{ normalizeDateOnly(scope.row.completedDate) }}</span>
  103. </template>
  104. </el-table-column>
  105. <el-table-column prop="testNumber" header-align="center" align="center" label="测试编码" width="140"></el-table-column>
  106. <el-table-column prop="testerName" header-align="center" align="center" label="测试人" width="180" :show-overflow-tooltip="true">
  107. <template slot-scope="scope">
  108. <span>{{ scope.row.testerName || scope.row.tester || '' }}</span>
  109. </template>
  110. </el-table-column>
  111. <el-table-column fixed="right" header-align="center" align="center" width="130" label="操作">
  112. <template slot-scope="scope">
  113. <el-link v-if="authUpdate && scope.row.status !== '已完成'" style="cursor: pointer" @click="addOrUpdateHandle(scope.row)">编辑</el-link>
  114. <el-link v-if="authUpdate && scope.row.status === '已完成'" style="cursor: pointer" @click="addOrUpdateHandle(scope.row)">详情</el-link>
  115. <el-link v-if="authIssue && scope.row.status === '草稿'" style="cursor: pointer; margin-left: 10px;" @click="issueModal(scope.row)">下达</el-link>
  116. </template>
  117. </el-table-column>
  118. </el-table>
  119. <el-pagination style="margin-top: 0px"
  120. @size-change="sizeChangeHandle"
  121. @current-change="currentChangeHandle"
  122. :current-page="pageIndex"
  123. :page-sizes="[20, 50, 100, 200, 500]"
  124. :page-size="pageSize"
  125. :total="totalPage"
  126. layout="total, sizes, prev, pager, next, jumper">
  127. </el-pagination>
  128. <el-dialog
  129. :title="modalTitle"
  130. :visible.sync="modalFlag"
  131. width="965px"
  132. top="5vh"
  133. v-drag
  134. :close-on-click-modal="false"
  135. :showClose="false">
  136. <el-tabs tab-position="left" type="border-card" v-model="activeName" style="width: 100%;height: 730px;">
  137. <el-tab-pane label="基本信息" name="basicInfo">
  138. <div style="height: 715px; overflow-y: auto;">
  139. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: -5px;">
  140. <el-form-item>
  141. <span style="cursor: pointer" v-if="!isLabFieldDisabled('applicant')" slot="label" @click="getBaseList(103, 1)"><a herf="#">申请人/Application</a></span>
  142. <span v-else slot="label">申请人/Application</span>
  143. <el-input v-model="modalData.applicant" @blur="applicantBlur(103)" :disabled="isLabFieldDisabled('applicant')" style="width: 100px"></el-input>
  144. <el-input v-model="modalData.applicantName" disabled style="width: 155px"></el-input>
  145. </el-form-item>
  146. <el-form-item label="申请日期/Apply Date">
  147. <el-date-picker v-model="modalData.applicationDate" type="date" value-format="yyyy-MM-dd" :disabled="isLabFieldDisabled('applicationDate')" style="width: 110px" :editable="false"></el-date-picker>
  148. </el-form-item>
  149. <el-form-item label="申请工厂/Apply Site">
  150. <el-select v-model="modalData.site" :disabled="isEditMode || showModalFlag" style="width: 135px" @change="handleModalSiteChange">
  151. <el-option
  152. v-for="item in siteOptions"
  153. :key="item.siteID"
  154. :label="item.siteID + '-' + item.siteName"
  155. :value="item.siteID">
  156. </el-option>
  157. </el-select>
  158. </el-form-item>
  159. <el-form-item label="申请部门/Apply Department">
  160. <el-input v-model="modalData.applyDepartment" :disabled="isLabFieldDisabled('applyDepartment')" style="width: 225px"></el-input>
  161. </el-form-item>
  162. </el-form>
  163. <el-form :inline="true" label-position="top" :model="modalData">
  164. <el-form-item>
  165. <span slot="label" v-if="!modalData.customerIdFlag && !isLabFieldDisabled('customerId')" @click="getBaseList(102, 1)"><a herf="#">客户/Customer</a></span>
  166. <span slot="label" v-else>客户/Customer</span>
  167. <el-input :disabled="modalData.customerIdFlag || isLabFieldDisabled('customerId')" readonly v-model="modalData.customerId" @blur="handleQueryCustomer" style="width: 100px"></el-input>
  168. <el-input disabled v-model="modalData.customerName" style="width: 155px"></el-input>
  169. </el-form-item>
  170. <el-form-item>
  171. <span slot="label" v-if="!modalData.projectIdFlag && !isLabFieldDisabled('projectId')" @click="chooseProjectListFlag = true"><a herf="#">项目/Project</a></span>
  172. <span slot="label" v-else>项目/Project</span>
  173. <el-input :disabled="modalData.projectIdFlag || isLabFieldDisabled('projectId')" readonly v-model="modalData.projectId" @blur="handleQueryProjectByCustomer" style="width: 100px"></el-input>
  174. <el-input disabled v-model="modalData.projectName" style="width: 155px"></el-input>
  175. </el-form-item>
  176. <el-form-item label="需求日期/Requested Date">
  177. <el-date-picker v-model="modalData.requestedDate" type="date" value-format="yyyy-MM-dd" :disabled="isLabFieldDisabled('requestedDate')" style="width: 225px" :editable="false"></el-date-picker>
  178. </el-form-item>
  179. </el-form>
  180. <el-form :inline="true" label-position="top" :model="modalData">
  181. <el-form-item label="样品名称/Sample Name">
  182. <el-input v-model="modalData.sampleName" :disabled="isLabFieldDisabled('sampleName')" style="width: 260px"></el-input>
  183. </el-form-item>
  184. <el-form-item label="样品型号/Sample Model">
  185. <el-input v-model="modalData.sampleModel" :disabled="isLabFieldDisabled('sampleModel')" style="width: 259px"></el-input>
  186. </el-form-item>
  187. <el-form-item label="样品数量/Sample QTY">
  188. <el-input v-model="modalData.sampleQty" :disabled="isLabFieldDisabled('sampleQty')" style="width: 225px"></el-input>
  189. </el-form-item>
  190. </el-form>
  191. <el-form :inline="true" label-position="top" :model="modalData">
  192. <el-form-item label="测试目的/Test Purpose">
  193. <el-input v-model="modalData.testPurpose" :disabled="isLabFieldDisabled('testPurpose')" style="width: 260px"></el-input>
  194. </el-form-item>
  195. <el-form-item label="产品阶段/Product Stage">
  196. <dict-data-select v-model="modalData.productStage" clearable :disabled="isLabFieldDisabled('productStage')" style="width: 259px" dict-type="lab_product_stage"></dict-data-select>
  197. </el-form-item>
  198. <el-form-item label="测试类型/Test Type">
  199. <el-radio-group v-model="modalData.testType" :disabled="isLabFieldDisabled('testType')" style="width: 225px">
  200. <el-radio label="内部验证" @click.native.prevent="radioClick('testType', '内部验证')">内部验证</el-radio>
  201. <el-radio label="客户要求" @click.native.prevent="radioClick('testType', '客户要求')">客户要求</el-radio>
  202. </el-radio-group>
  203. </el-form-item>
  204. </el-form>
  205. <el-form :inline="true" label-position="top" :model="modalData" style="margin-left: 2px">
  206. <el-form-item label="报告出具/Report Document">
  207. <el-radio-group v-model="modalData.reportDocument" :disabled="isLabFieldDisabled('reportDocument')" style="width: 260px">
  208. <el-radio label="内部报告" @click.native.prevent="radioClick('reportDocument', '内部报告')">内部报告</el-radio>
  209. <el-radio label="客户报告" @click.native.prevent="radioClick('reportDocument', '客户报告')">客户报告</el-radio>
  210. </el-radio-group>
  211. </el-form-item>
  212. <el-form-item label="样品退回/Return Sample">
  213. <el-radio-group v-model="modalData.returnSample" :disabled="isLabFieldDisabled('returnSample')" style="width: 259px">
  214. <el-radio label="Y" @click.native.prevent="radioClick('returnSample', 'Y')"></el-radio>
  215. <el-radio label="N" @click.native.prevent="radioClick('returnSample', 'N')"></el-radio>
  216. </el-radio-group>
  217. </el-form-item>
  218. </el-form>
  219. <el-form :inline="true" label-position="top" :model="modalData">
  220. <el-form-item label="Application Surface">
  221. <el-input v-model="modalData.applicationSurface" :disabled="isLabFieldDisabled('applicationSurface')" style="width: 533px"></el-input>
  222. </el-form-item>
  223. <el-form-item label="Test Lab">
  224. <dict-data-select v-model="modalData.testLab" clearable :disabled="isLabFieldDisabled('testLab')" style="width: 225px" dict-type="lab_test_lab" site="41" @change="handleTestLabChange"></dict-data-select>
  225. </el-form-item>
  226. </el-form>
  227. <el-form :inline="true" label-position="top" style="margin-top: -15px">
  228. <el-form-item label=" ">
  229. <el-button type="primary" :disabled="showModalFlag" @click="openPropertyChooseModal">测试项目及条件/Test Items & Conditions</el-button>
  230. </el-form-item>
  231. </el-form>
  232. <div class="rq" style="width: 772px;">
  233. <el-table
  234. :data="modalData.propertyItemList"
  235. border
  236. :height="260"
  237. style="width: 100%;">
  238. <el-table-column prop="itemNo" header-align="center" align="center" label="属性编码" width="100"></el-table-column>
  239. <el-table-column prop="itemDesc" header-align="center" align="left" label="属性名称" min-width="150"></el-table-column>
  240. <el-table-column header-align="center" align="center" label="属性值" min-width="250">
  241. <template slot-scope="scope">
  242. <el-select
  243. v-if="scope.row.valueChooseFlag === 'Y'"
  244. v-model="scope.row.itemValue"
  245. :disabled="showModalFlag"
  246. clearable
  247. filterable
  248. style="width: 100%;">
  249. <el-option
  250. v-for="(option, index) in (scope.row.availableValueList || [])"
  251. :key="scope.row.itemNo + '-' + index + '-' + option.availableValue"
  252. :label="option.availableValue"
  253. :value="option.availableValue">
  254. </el-option>
  255. </el-select>
  256. <el-input v-else v-model="scope.row.itemValue" :disabled="showModalFlag" clearable></el-input>
  257. </template>
  258. </el-table-column>
  259. </el-table>
  260. </div>
  261. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 0px">
  262. <el-form-item style="display: block;">
  263. <template slot="label">
  264. <span class="judge-criteria-label" @click="openTestSpecDialog">测试规范/Test spec</span>
  265. </template>
  266. <div class="judge-criteria-box">
  267. <template v-if="testSpecFileList.length > 0">
  268. <el-link
  269. v-for="item in testSpecFileList"
  270. :key="item.id"
  271. type="primary"
  272. style="margin-right: 10px"
  273. @click.stop="previewJudgeCriteriaFile(item)">
  274. {{ item.fileName }}
  275. </el-link>
  276. </template>
  277. <span v-else class="judge-criteria-placeholder">点击测试规范上传附件</span>
  278. </div>
  279. </el-form-item>
  280. </el-form>
  281. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 15px">
  282. <el-form-item style="display: block;">
  283. <template slot="label">
  284. <span class="judge-criteria-label" @click="openJudgeCriteriaDialog">判断标准/Judge Criteria</span>
  285. </template>
  286. <div class="judge-criteria-box">
  287. <template v-if="judgeCriteriaFileList.length > 0">
  288. <el-link
  289. v-for="item in judgeCriteriaFileList"
  290. :key="item.id"
  291. type="primary"
  292. style="margin-right: 10px"
  293. @click.stop="previewJudgeCriteriaFile(item)">
  294. {{ item.fileName }}
  295. </el-link>
  296. </template>
  297. <span v-else class="judge-criteria-placeholder">点击判断标准上传附件</span>
  298. </div>
  299. </el-form-item>
  300. </el-form>
  301. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 15px">
  302. <el-form-item label="注意事项/Attention" style="display: block;">
  303. <el-input type="textarea" :rows="3" v-model="modalData.attention" :disabled="isLabFieldDisabled('attention')" resize="none" style="width: 772px"></el-input>
  304. </el-form-item>
  305. </el-form>
  306. </div>
  307. </el-tab-pane>
  308. <el-tab-pane label="审批信息" name="approvalInfo">
  309. <div style="height: 715px; overflow-y: auto;">
  310. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: -5px;">
  311. <el-form-item label="备注(部门经理)/ Comments(Department Manager)" style="display: block;">
  312. <el-input type="textarea" :rows="3" v-model="modalData.departmentManagerComments" :disabled="isLabFieldDisabled('departmentManagerComments')" resize="none" style="width: 772px"></el-input>
  313. </el-form-item>
  314. </el-form>
  315. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 45px;">
  316. <el-form-item label="备注(实验室)/ Comments(Lab)" style="display: block;">
  317. <el-input type="textarea" :rows="3" v-model="modalData.labComments" :disabled="isLabFieldDisabled('labComments')" resize="none" style="width: 772px"></el-input>
  318. </el-form-item>
  319. </el-form>
  320. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 45px">
  321. <el-form-item>
  322. <span style="cursor: pointer" v-if="!isLabFieldDisabled('tester')" slot="label" @click="openTesterChooseModal"><a herf="#">测试人/Tester</a></span>
  323. <span v-else slot="label">测试人/Tester</span>
  324. <el-input
  325. v-model="modalData.testerName"
  326. readonly
  327. :disabled="isLabFieldDisabled('tester')"
  328. style="width: 772px"
  329. placeholder="请选择测试人"
  330. @focus="openTesterChooseModal">
  331. <span slot="suffix" v-show="modalData.testerName && !isLabFieldDisabled('tester')" @click.stop="clearTesterSelection">
  332. <i class="el-icon-circle-close" style="margin-left: 5px;cursor: pointer;"></i>
  333. </span>
  334. </el-input>
  335. </el-form-item>
  336. </el-form>
  337. </div>
  338. </el-tab-pane>
  339. <el-tab-pane label="测试结果" name="resultInfo">
  340. <div style="height: 715px; overflow-y: auto;">
  341. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: -5px;">
  342. <el-form-item label="测试开始时间/Test Start Date">
  343. <el-date-picker v-model="modalData.testStartDate" type="date" value-format="yyyy-MM-dd" :disabled="isLabFieldDisabled('testStartDate')" style="width: 170px" :editable="false"></el-date-picker>
  344. </el-form-item>
  345. <el-form-item label="测试完成日期/Completed Date">
  346. <el-date-picker v-model="modalData.completedDate" type="date" value-format="yyyy-MM-dd" :disabled="isLabFieldDisabled('completedDate')" style="width: 170px" :editable="false"></el-date-picker>
  347. </el-form-item>
  348. <el-form-item label="测试编码/Test Number">
  349. <el-input v-model="modalData.testNumber" :disabled="isLabFieldDisabled('testNumber')" style="width: 250px"></el-input>
  350. </el-form-item>
  351. </el-form>
  352. <el-form :inline="true" label-position="top" :model="modalData">
  353. <el-form-item label="异常情况及说明/Unnormal symptom and description" style="display: block;">
  354. <el-input type="textarea" :rows="3" v-model="modalData.unnormalSymptomAndDescription" :disabled="isLabFieldDisabled('unnormalSymptomAndDescription')" resize="none" style="width: 772px"></el-input>
  355. </el-form-item>
  356. </el-form>
  357. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 45px">
  358. <el-form-item style="display: block;">
  359. <template slot="label">
  360. <span class="judge-criteria-label" @click="openTestReportDialog">测试报告/Test Report</span>
  361. </template>
  362. <div class="judge-criteria-box">
  363. <template v-if="testReportFileList.length > 0">
  364. <el-link
  365. v-for="item in testReportFileList"
  366. :key="item.id"
  367. type="primary"
  368. style="margin-right: 10px"
  369. @click.stop="previewTestReportFile(item)">
  370. {{ item.fileName }}
  371. </el-link>
  372. </template>
  373. <span v-else class="judge-criteria-placeholder">点击测试报告上传附件</span>
  374. </div>
  375. </el-form-item>
  376. </el-form>
  377. <el-form :inline="true" label-position="top" :model="modalData" style="margin-top: 20px">
  378. <el-form-item label="备注/Comments" style="display: block;">
  379. <el-input type="textarea" :rows="3" v-model="modalData.testerComments" :disabled="isLabFieldDisabled('testerComments')" resize="none" style="width: 772px"></el-input>
  380. </el-form-item>
  381. </el-form>
  382. </div>
  383. </el-tab-pane>
  384. </el-tabs>
  385. <el-footer style="height:35px;margin-top: 15px;text-align:center">
  386. <el-button type="primary" v-if="canSaveAction()" @click="dataFormSubmit()">保存</el-button>
  387. <el-button type="primary" @click="handleModalClose">关闭</el-button>
  388. <el-button type="primary" v-if="canAgreeAction()" :loading="submitLoading" @click="agreeSubmit">同意</el-button>
  389. <el-button type="primary" v-if="canRejectAction()" :loading="submitLoading" @click="openRejectModal">驳回</el-button>
  390. </el-footer>
  391. </el-dialog>
  392. <el-dialog width="420px" title="驳回意见" :close-on-click-modal="false" :visible.sync="submitModalFlag" v-drag>
  393. <el-form :inline="true" label-position="top" style="margin-top: -15px;">
  394. <el-form-item label="意见">
  395. <el-input type="textarea" :rows="4" v-model="rejectOpinion" style="width: 380px"></el-input>
  396. </el-form-item>
  397. </el-form>
  398. <div slot="footer" class="dialog-footer">
  399. <el-button @click="submitModalFlag = false">取消</el-button>
  400. <el-button type="primary" :loading="submitLoading" @click="rejectSubmit">确定</el-button>
  401. </div>
  402. </el-dialog>
  403. <el-dialog title="属性清单" :close-on-click-modal="false" v-drag :visible.sync="propertyChooseModalFlag" width="820px">
  404. <div class="rq">
  405. <el-form :inline="true" label-position="top" :model="propertyChooseData">
  406. <el-form-item label="模板">
  407. <el-select v-model="propertyChooseData.codeNo" placeholder="请选择模板" style="width: 180px">
  408. <el-option
  409. v-for="item in propertyModelList"
  410. :key="item.codeNo"
  411. :label="item.codeDesc"
  412. :value="item.codeNo">
  413. </el-option>
  414. </el-select>
  415. </el-form-item>
  416. <el-form-item label="属性编码">
  417. <el-input v-model="propertyChooseData.itemNo" clearable style="width: 140px"></el-input>
  418. </el-form-item>
  419. <el-form-item label="属性名称">
  420. <el-input v-model="propertyChooseData.itemDesc" clearable style="width: 140px"></el-input>
  421. </el-form-item>
  422. <el-form-item :label="' '">
  423. <el-button type="primary" @click="searchPropertyItemList()">查询</el-button>
  424. </el-form-item>
  425. </el-form>
  426. <el-table
  427. :height="320"
  428. :data="propertyItemList"
  429. ref="propertyItemTable"
  430. @row-click="propertyItemClickRow"
  431. @selection-change="selectionPropertyItem"
  432. border
  433. style="width: 100%;">
  434. <el-table-column
  435. type="selection"
  436. header-align="center"
  437. align="center"
  438. width="50">
  439. </el-table-column>
  440. <el-table-column prop="itemNo" header-align="center" align="center" label="属性编码" width="180"></el-table-column>
  441. <el-table-column prop="itemDesc" header-align="center" align="left" label="属性名称" min-width="300"></el-table-column>
  442. <el-table-column prop="defaultValue" header-align="center" align="left" label="参照值" min-width="180"></el-table-column>
  443. </el-table>
  444. </div>
  445. <el-footer style="height:40px;margin-top: 20px;text-align:center">
  446. <el-button type="primary" @click="confirmPropertyItem">确认</el-button>
  447. <el-button type="primary" @click="propertyChooseModalFlag = false">关闭</el-button>
  448. </el-footer>
  449. </el-dialog>
  450. <el-dialog
  451. title="判断标准附件"
  452. :close-on-click-modal="false"
  453. :visible.sync="judgeCriteriaDialogVisible"
  454. width="900px"
  455. v-drag
  456. @close="handleJudgeCriteriaDialogClose">
  457. <oss-components
  458. ref="judgeCriteriaOss"
  459. :save-visible="authFileSave"
  460. :download-visible="authFileDownLoad"
  461. :remove-visible="authFileRemove"
  462. :preview-visible="authFilePreview"
  463. :disabled="showModalFlag || modalData.status === '已完成'"
  464. :row-click-select="true"
  465. label="序列号"
  466. :height="460"
  467. style="margin-top: 2px"
  468. :columns="judgeCriteriaFileColumnList"
  469. :order-ref1="modalData.site || ''"
  470. :order-ref2="modalData.referenceNo || ''"
  471. order-ref3="judgeCriteria">
  472. </oss-components>
  473. </el-dialog>
  474. <el-dialog
  475. title="测试规范附件"
  476. :close-on-click-modal="false"
  477. :visible.sync="testSpecDialogVisible"
  478. width="900px"
  479. v-drag
  480. @close="handleTestSpecDialogClose">
  481. <oss-components
  482. ref="testSpecOss"
  483. :save-visible="authFileSave"
  484. :download-visible="authFileDownLoad"
  485. :remove-visible="authFileRemove"
  486. :preview-visible="authFilePreview"
  487. :disabled="showModalFlag || modalData.status === '已完成'"
  488. :row-click-select="true"
  489. label="序列号"
  490. :height="460"
  491. style="margin-top: 2px"
  492. :columns="judgeCriteriaFileColumnList"
  493. :order-ref1="modalData.site || ''"
  494. :order-ref2="modalData.referenceNo || ''"
  495. order-ref3="testSpec">
  496. </oss-components>
  497. </el-dialog>
  498. <el-dialog
  499. title="测试报告附件"
  500. :close-on-click-modal="false"
  501. :visible.sync="testReportDialogVisible"
  502. width="900px"
  503. v-drag
  504. @close="handleTestReportDialogClose">
  505. <oss-components
  506. ref="testReportOss"
  507. :save-visible="authFileSave"
  508. :download-visible="authFileDownLoad"
  509. :remove-visible="authFileRemove"
  510. :preview-visible="authFilePreview"
  511. :disabled="showModalFlag || modalData.status === '已完成'"
  512. :row-click-select="true"
  513. label="序列号"
  514. :height="460"
  515. style="margin-top: 2px"
  516. :columns="judgeCriteriaFileColumnList"
  517. :order-ref1="modalData.site || ''"
  518. :order-ref2="modalData.referenceNo || ''"
  519. order-ref3="testReport">
  520. </oss-components>
  521. </el-dialog>
  522. <el-dialog title="人员选择" @open="openTesterDialog" @close="closeTesterDialog" v-drag
  523. :visible.sync="testerFlag" width="40vw" :close-on-click-modal="false">
  524. <el-form :inline="true" label-position="top" :model="testerSearchData">
  525. <el-form-item label="编码">
  526. <el-input v-model="testerSearchData.operatorId" clearable style="width: 120px"></el-input>
  527. </el-form-item>
  528. <el-form-item label="名称">
  529. <el-input v-model="testerSearchData.operatorName" clearable style="width: 120px"></el-input>
  530. </el-form-item>
  531. <el-form-item label=" ">
  532. <el-button type="primary" @click="filterTesterOptions">查询</el-button>
  533. </el-form-item>
  534. </el-form>
  535. <el-table v-if="testerFlag"
  536. :height="300"
  537. :data="testerDisplayList"
  538. @selection-change="handleTesterSelectionChange"
  539. @row-click="(row,column,event) => handleTesterTableClick(row,column,event,'testerTable')"
  540. ref="testerTable"
  541. border row-key="operatorId"
  542. style="width: 100%;">
  543. <el-table-column
  544. type="selection"
  545. header-align="center"
  546. align="center"
  547. :reserve-selection="true"
  548. width="50">
  549. </el-table-column>
  550. <el-table-column label="编码" property="operatorId" align="left" header-align="center"/>
  551. <el-table-column label="名称" property="operatorName" align="left" header-align="center"/>
  552. </el-table>
  553. <el-footer style="height:40px;margin-top: 20px;text-align:center">
  554. <el-button type="primary" @click="saveTesterChooseModal">确定</el-button>
  555. <el-button type="primary" @click="testerFlag = false">关闭</el-button>
  556. </el-footer>
  557. </el-dialog>
  558. <el-dialog title="实验室审批人选择" @open="openLabApproverDialog" @close="closeLabApproverDialog" v-drag
  559. :visible.sync="labApproverFlag" width="40vw" :close-on-click-modal="false">
  560. <el-form :inline="true" label-position="top" :model="labApproverSearchData">
  561. <el-form-item label="编码">
  562. <el-input v-model="labApproverSearchData.operatorId" clearable style="width: 120px"></el-input>
  563. </el-form-item>
  564. <el-form-item label="名称">
  565. <el-input v-model="labApproverSearchData.operatorName" clearable style="width: 120px"></el-input>
  566. </el-form-item>
  567. <el-form-item label=" ">
  568. <el-button type="primary" @click="filterLabApproverOptions">查询</el-button>
  569. </el-form-item>
  570. </el-form>
  571. <el-table v-if="labApproverFlag"
  572. :height="300"
  573. :data="labApproverDisplayList"
  574. @selection-change="handleLabApproverSelectionChange"
  575. @row-click="(row,column,event) => handleTesterTableClick(row,column,event,'labApproverTable')"
  576. ref="labApproverTable"
  577. border row-key="operatorId"
  578. style="width: 100%;">
  579. <el-table-column
  580. type="selection"
  581. header-align="center"
  582. align="center"
  583. :reserve-selection="true"
  584. width="50">
  585. </el-table-column>
  586. <el-table-column label="编码" property="operatorId" align="left" header-align="center"/>
  587. <el-table-column label="名称" property="operatorName" align="left" header-align="center"/>
  588. </el-table>
  589. <el-footer style="height:40px;margin-top: 20px;text-align:center">
  590. <el-button type="primary" @click="saveLabApproverChooseModal">确定</el-button>
  591. <el-button type="primary" @click="labApproverFlag = false">关闭</el-button>
  592. </el-footer>
  593. </el-dialog>
  594. <el-dialog title="选择-项目" :close-on-click-modal="false" @close="closeProjectInfoDialog"
  595. @open="searchProjectInfoList" :visible.sync="chooseProjectListFlag" width="35%">
  596. <el-form label-position="top" :model="searchProjectData" ref="closeProjectInfoForm">
  597. <el-row :gutter="10">
  598. <el-col :span="6">
  599. <el-form-item label="项目号">
  600. <el-input v-model="searchProjectData.projectId"></el-input>
  601. </el-form-item>
  602. </el-col>
  603. <el-col :span="6">
  604. <el-form-item label="项目名称">
  605. <el-input v-model="searchProjectData.projectName"></el-input>
  606. </el-form-item>
  607. </el-col>
  608. <el-col :span="6">
  609. <el-form-item label=" ">
  610. <el-button type="primary" @click="searchProjectInfoList">查询</el-button>
  611. </el-form-item>
  612. </el-col>
  613. </el-row>
  614. <el-table :height="223"
  615. :data="projectList"
  616. border
  617. @row-click="projectClickRow">
  618. <el-table-column label="项目号" prop="projectId"/>
  619. <el-table-column label="项目名称" prop="projectName"/>
  620. </el-table>
  621. </el-form>
  622. </el-dialog>
  623. <el-tabs v-model="activeTable" type="border-card" style="width: 100%; height: 100%;" @tab-click="tabClick" v-loading="currentDetailLoading" class="customer-tab">
  624. <el-tab-pane label="基本信息" name="basicInfo">
  625. <div :style="{height: secondHeight + 'px'}" style="margin-left: 5px;margin-top: 5px; overflow-y: auto;">
  626. <el-form :inline="true" label-position="top" :model="currentDetail">
  627. <el-form-item label="申请人/Application">
  628. <el-input :value="currentDetail.applicant || ''" disabled style="width: 100px"></el-input>
  629. <el-input :value="currentDetail.applicantName || ''" disabled style="width: 155px"></el-input>
  630. </el-form-item>
  631. <el-form-item label="申请日期/Apply Date">
  632. <el-input :value="normalizeDateOnly(currentDetail.applicationDate)" disabled style="width: 110px"></el-input>
  633. </el-form-item>
  634. <el-form-item label="申请工厂/Apply Site">
  635. <el-input :value="currentDetail.site || ''" disabled style="width: 135px"></el-input>
  636. </el-form-item>
  637. <el-form-item label="申请部门/Apply Department">
  638. <el-input :value="currentDetail.applyDepartment || ''" disabled style="width: 225px"></el-input>
  639. </el-form-item>
  640. </el-form>
  641. <el-form :inline="true" label-position="top" :model="currentDetail">
  642. <el-form-item label="客户/Customer">
  643. <el-input :value="currentDetail.customerId || ''" disabled style="width: 100px"></el-input>
  644. <el-input :value="currentDetail.customerName || ''" disabled style="width: 155px"></el-input>
  645. </el-form-item>
  646. <el-form-item label="项目/Project">
  647. <el-input :value="currentDetail.projectId || ''" disabled style="width: 100px"></el-input>
  648. <el-input :value="currentDetail.projectName || ''" disabled style="width: 155px"></el-input>
  649. </el-form-item>
  650. <el-form-item label="需求日期/Requested Date">
  651. <el-input :value="normalizeDateOnly(currentDetail.requestedDate)" disabled style="width: 225px"></el-input>
  652. </el-form-item>
  653. </el-form>
  654. <el-form :inline="true" label-position="top" :model="currentDetail">
  655. <el-form-item label="样品名称/Sample Name">
  656. <el-input :value="currentDetail.sampleName || ''" disabled style="width: 260px"></el-input>
  657. </el-form-item>
  658. <el-form-item label="样品型号/Sample Model">
  659. <el-input :value="currentDetail.sampleModel || ''" disabled style="width: 259px"></el-input>
  660. </el-form-item>
  661. <el-form-item label="样品数量/Sample QTY">
  662. <el-input :value="currentDetail.sampleQty || ''" disabled style="width: 225px"></el-input>
  663. </el-form-item>
  664. </el-form>
  665. <el-form :inline="true" label-position="top" :model="currentDetail">
  666. <el-form-item label="测试目的/Test Purpose">
  667. <el-input :value="currentDetail.testPurpose || ''" disabled style="width: 260px"></el-input>
  668. </el-form-item>
  669. <el-form-item label="产品阶段/Product Stage">
  670. <el-input :value="currentDetail.productStage || ''" disabled style="width: 259px"></el-input>
  671. </el-form-item>
  672. <el-form-item label="测试类型/Test Type">
  673. <el-input :value="currentDetail.testType || ''" disabled style="width: 225px"></el-input>
  674. </el-form-item>
  675. </el-form>
  676. <el-form :inline="true" label-position="top" :model="currentDetail">
  677. <el-form-item label="报告出具/Report Document">
  678. <el-input :value="currentDetail.reportDocument || ''" disabled style="width: 260px"></el-input>
  679. </el-form-item>
  680. <el-form-item label="样品退回/Return Sample">
  681. <el-input :value="displayYesNo(currentDetail.returnSample)" disabled style="width: 259px"></el-input>
  682. </el-form-item>
  683. </el-form>
  684. <el-form :inline="true" label-position="top" :model="currentDetail">
  685. <el-form-item label="Application Surface">
  686. <el-input :value="currentDetail.applicationSurface || ''" disabled style="width: 533px"></el-input>
  687. </el-form-item>
  688. <el-form-item label="Test Lab">
  689. <el-input :value="currentDetail.testLab || ''" disabled style="width: 225px"></el-input>
  690. </el-form-item>
  691. </el-form>
  692. <div class="rq" style="width: 772px;margin-top: 0px">
  693. <el-table
  694. :data="currentDetail.propertyItemList || []"
  695. border
  696. :height="260"
  697. style="width: 100%;">
  698. <el-table-column prop="itemNo" header-align="center" align="center" label="属性编码" width="100"></el-table-column>
  699. <el-table-column prop="itemDesc" header-align="center" align="left" label="属性名称" min-width="150"></el-table-column>
  700. <el-table-column prop="itemValue" header-align="center" align="left" label="属性值" min-width="250" show-overflow-tooltip></el-table-column>
  701. </el-table>
  702. </div>
  703. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 5px">
  704. <el-form-item label="测试规范/Test spec" style="display: block;">
  705. <div class="judge-criteria-box" style="cursor: default;">
  706. <template v-if="currentTestSpecFileList.length > 0">
  707. <el-link
  708. v-for="item in currentTestSpecFileList"
  709. :key="item.id"
  710. type="primary"
  711. style="margin-right: 10px"
  712. @click.stop="previewJudgeCriteriaFile(item)">
  713. {{ item.fileName }}
  714. </el-link>
  715. </template>
  716. <span v-else class="judge-criteria-placeholder">暂无测试规范附件</span>
  717. </div>
  718. </el-form-item>
  719. </el-form>
  720. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 18px">
  721. <el-form-item label="判断标准/Judge Criteria" style="display: block;">
  722. <div class="judge-criteria-box" style="cursor: default;">
  723. <template v-if="currentJudgeCriteriaFileList.length > 0">
  724. <el-link
  725. v-for="item in currentJudgeCriteriaFileList"
  726. :key="item.id"
  727. type="primary"
  728. style="margin-right: 10px"
  729. @click.stop="previewJudgeCriteriaFile(item)">
  730. {{ item.fileName }}
  731. </el-link>
  732. </template>
  733. <span v-else class="judge-criteria-placeholder">暂无判断标准附件</span>
  734. </div>
  735. </el-form-item>
  736. </el-form>
  737. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 20px">
  738. <el-form-item label="注意事项/Attention" style="display: block;">
  739. <el-input type="textarea" :rows="3" :value="currentDetail.attention || ''" disabled resize="none" style="width: 772px"></el-input>
  740. </el-form-item>
  741. </el-form>
  742. </div>
  743. </el-tab-pane>
  744. <el-tab-pane label="审批信息" name="approvalInfoDetail">
  745. <div :style="{height: secondHeight + 'px'}" style="margin-left: 5px;margin-top: 5px; overflow-y: auto;">
  746. <el-form :inline="true" label-position="top" :model="currentDetail">
  747. <el-form-item label="备注(部门经理)/ Comments(Department Manager)" style="display: block;">
  748. <el-input type="textarea" :rows="3" :value="currentDetail.departmentManagerComments || ''" disabled resize="none" style="width: 772px"></el-input>
  749. </el-form-item>
  750. </el-form>
  751. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 45px">
  752. <el-form-item label="备注(实验室)/ Comments(Lab)" style="display: block;">
  753. <el-input type="textarea" :rows="3" :value="currentDetail.labComments || ''" disabled resize="none" style="width: 772px"></el-input>
  754. </el-form-item>
  755. </el-form>
  756. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 45px">
  757. <el-form-item label="测试人/Tester">
  758. <el-input :value="currentDetail.testerName || currentDetail.tester || ''" disabled style="width: 772px"></el-input>
  759. </el-form-item>
  760. </el-form>
  761. </div>
  762. </el-tab-pane>
  763. <el-tab-pane label="测试结果" name="resultInfo">
  764. <div :style="{height: secondHeight + 'px'}" style="margin-left: 5px;margin-top: 5px; overflow-y: auto;">
  765. <el-form :inline="true" label-position="top" :model="currentDetail">
  766. <el-form-item label="测试开始时间/Test Start Date">
  767. <el-input :value="normalizeDateOnly(currentDetail.testStartDate)" disabled style="width: 170px"></el-input>
  768. </el-form-item>
  769. <el-form-item label="测试完成日期/Completed Date">
  770. <el-input :value="normalizeDateOnly(currentDetail.completedDate)" disabled style="width: 170px"></el-input>
  771. </el-form-item>
  772. <el-form-item label="测试编码/Test Number">
  773. <el-input :value="currentDetail.testNumber || ''" disabled style="width: 250px"></el-input>
  774. </el-form-item>
  775. </el-form>
  776. <el-form :inline="true" label-position="top" :model="currentDetail">
  777. <el-form-item label="异常情况及说明/Unnormal symptom and description" style="display: block;">
  778. <el-input type="textarea" :rows="3" :value="currentDetail.unnormalSymptomAndDescription || ''" disabled resize="none" style="width: 772px"></el-input>
  779. </el-form-item>
  780. </el-form>
  781. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 45px">
  782. <el-form-item label="测试报告/Test Report" style="display: block;">
  783. <div class="judge-criteria-box" style="cursor: default;">
  784. <template v-if="currentTestReportFileList.length > 0">
  785. <el-link
  786. v-for="item in currentTestReportFileList"
  787. :key="item.id"
  788. type="primary"
  789. style="margin-right: 10px"
  790. @click.stop="previewTestReportFile(item)">
  791. {{ item.fileName }}
  792. </el-link>
  793. </template>
  794. <span v-else class="judge-criteria-placeholder">暂无测试报告附件</span>
  795. </div>
  796. </el-form-item>
  797. </el-form>
  798. <el-form :inline="true" label-position="top" :model="currentDetail" style="margin-top: 20px">
  799. <el-form-item label="备注/Comments" style="display: block;">
  800. <el-input type="textarea" :rows="3" :value="currentDetail.testerComments || ''" disabled resize="none" style="width: 772px"></el-input>
  801. </el-form-item>
  802. </el-form>
  803. </div>
  804. </el-tab-pane>
  805. <el-tab-pane label="审批记录" name="approvalInformation">
  806. <approval-information v-model:data-list="approvalList" :height="secondHeight"></approval-information>
  807. </el-tab-pane>
  808. </el-tabs>
  809. <ChooseList ref="baseList" @getBaseData="getBaseData"></ChooseList>
  810. <filter-search :visible.sync="filterVisible" @search="queryByAnyField"></filter-search>
  811. </div>
  812. </template>
  813. <script>
  814. import * as api from '@/api/lab/lab'
  815. import { getSiteList, searchUserListForRole } from '@/api/base/site'
  816. import { queryOss, previewOssFileById } from '@/api/oss/oss'
  817. import { checkSuperAdmin } from '@/api/changeManagement/changeManagement'
  818. import { verifyData } from '@/api/chooselist/chooselist.js'
  819. import { searchProjectInfoList } from '@/api/quotation/quotationInformation.js'
  820. import { queryCustomer } from '@/api/customer/customerInformation'
  821. import { queryProjectByCustomer } from '@/api/project/project'
  822. import ChooseList from '@/views/modules/common/Chooselist'
  823. import DictDataSelect from '../sys/dict-data-select.vue'
  824. import ApprovalInformation from '../changeManagement/approvalInformation.vue'
  825. import ossComponents from '../oss/ossComponents.vue'
  826. import FilterSearch from '../../common/filterSearch.vue'
  827. export default {
  828. components: {
  829. ChooseList,
  830. DictDataSelect,
  831. ApprovalInformation,
  832. ossComponents,
  833. FilterSearch
  834. },
  835. data () {
  836. return {
  837. searchData: {
  838. site: '',
  839. referenceNo: '',
  840. status: '',
  841. currentApprover: '',
  842. nodeId: ''
  843. },
  844. exportLoading: false,
  845. exportData: [],
  846. exportFieldMap: {},
  847. exportName: '',
  848. exportHeader: ['Lab记录'],
  849. exportFooter: [],
  850. resultList: [],
  851. dataListSelections: [],
  852. dataList: [],
  853. pageIndex: 1,
  854. pageSize: 20,
  855. totalPage: 0,
  856. dataListLoading: false,
  857. filterVisible: false,
  858. isFilterSearch: false,
  859. filterSearchData: {},
  860. activeTable: 'basicInfo',
  861. menuId: '',
  862. authSearch: false,
  863. authUpdate: false,
  864. authIssue: false,
  865. authSubmit: false,
  866. authReject: false,
  867. authDelete: false,
  868. authFileSave: false,
  869. authFileDownLoad: false,
  870. authFileRemove: false,
  871. authFilePreview: false,
  872. authDataEntry: false,
  873. superAdmin: false,
  874. createBy2: this.$store.state.user.name,
  875. height: 400,
  876. secondHeight: 200,
  877. currentRow: {},
  878. currentDetail: this.buildEmptyDetailData(),
  879. currentDetailLoading: false,
  880. currentDetailRequestId: 0,
  881. nodeOptions: [],
  882. approvalList: [],
  883. plmLabAuthorityArr: [],
  884. nodeAuthorityLoaded: false,
  885. isEditMode: false,
  886. modalTitle: 'Lab 新增',
  887. activeName: 'basicInfo',
  888. showModalFlag: false,
  889. submitModalFlag: false,
  890. rejectOpinion: '',
  891. submitLoading: false,
  892. tagNo: null,
  893. tagNo1: null,
  894. modalFlag: false,
  895. judgeCriteriaDialogVisible: false,
  896. testSpecDialogVisible: false,
  897. testReportDialogVisible: false,
  898. judgeCriteriaFileList: [],
  899. testSpecFileList: [],
  900. currentJudgeCriteriaFileList: [],
  901. currentTestSpecFileList: [],
  902. currentTestReportFileList: [],
  903. testReportFileList: [],
  904. judgeCriteriaFileColumnList: [
  905. {
  906. columnProp: 'fileName',
  907. headerAlign: 'center',
  908. align: 'center',
  909. columnLabel: '文件名称',
  910. columnHidden: false,
  911. columnImage: false,
  912. columnSortable: false,
  913. status: true,
  914. fixed: '',
  915. columnWidth: 180
  916. },
  917. {
  918. columnProp: 'fileRemark',
  919. headerAlign: 'center',
  920. align: 'center',
  921. columnLabel: '备注',
  922. columnHidden: false,
  923. columnImage: false,
  924. columnSortable: false,
  925. status: true,
  926. fixed: '',
  927. columnWidth: 220
  928. },
  929. {
  930. columnProp: 'createDate',
  931. headerAlign: 'center',
  932. align: 'center',
  933. columnLabel: '上传时间',
  934. columnHidden: false,
  935. columnImage: false,
  936. columnSortable: false,
  937. status: true,
  938. fixed: '',
  939. columnWidth: 170
  940. },
  941. {
  942. columnProp: 'createBy',
  943. headerAlign: 'center',
  944. align: 'center',
  945. columnLabel: '上传人',
  946. columnHidden: false,
  947. columnImage: false,
  948. columnSortable: false,
  949. status: true,
  950. fixed: '',
  951. columnWidth: 140
  952. }
  953. ],
  954. siteOptions: [],
  955. chooseProjectListFlag: false,
  956. searchProjectData: {
  957. site: '',
  958. projectId: undefined,
  959. projectName: undefined,
  960. customerId: undefined
  961. },
  962. projectList: [],
  963. modalData: this.buildDefaultModalData(),
  964. propertyChooseModalFlag: false,
  965. propertyModelList: [],
  966. propertyItemList: [],
  967. propertyItemSelections: [],
  968. propertyChooseData: this.buildDefaultPropertyChooseData(),
  969. testerOptionList: [],
  970. testerDisplayList: [],
  971. testerSelectionCache: [],
  972. testerFlag: false,
  973. testerSearchData: {
  974. operatorId: '',
  975. operatorName: ''
  976. },
  977. labApproverOptionList: [],
  978. labApproverDisplayList: [],
  979. labApproverSelectionCache: [],
  980. labApproverFlag: false,
  981. labApproverSearchData: {
  982. operatorId: '',
  983. operatorName: ''
  984. }
  985. }
  986. },
  987. created () {
  988. this.menuId = this.$route.meta.menuId
  989. this.getButtonAuthData()
  990. this.checkSuperAdmin()
  991. this.loadSiteOptions()
  992. },
  993. mounted () {
  994. this.fetchNodeOptions()
  995. if (this.authSearch) {
  996. this.handleRouteQuery()
  997. }
  998. this.$nextTick(() => {
  999. this.height = window.innerHeight / 2 - 30
  1000. this.secondHeight = window.innerHeight / 2 - 186
  1001. })
  1002. },
  1003. activated () {
  1004. this.handleRouteQuery()
  1005. },
  1006. methods: {
  1007. resolveRouteReferenceNo () {
  1008. const routeParams = this.$route.params || {}
  1009. const routeQuery = this.$route.query || {}
  1010. const referenceNo = routeParams.referenceNo || routeParams.labNo || routeParams.docNo || routeParams.documentNo ||
  1011. routeQuery.referenceNo || routeQuery.labNo || routeQuery.docNo || routeQuery.documentNo || ''
  1012. return String(referenceNo || '').trim()
  1013. },
  1014. handleRouteQuery () {
  1015. if (!this.authSearch) {
  1016. return
  1017. }
  1018. const routeParams = this.$route.params || {}
  1019. const isTokenLogin = routeParams.type === 'tokenLogin'
  1020. const referenceNo = this.resolveRouteReferenceNo()
  1021. if (isTokenLogin) {
  1022. if (!referenceNo) {
  1023. this.getDataList()
  1024. return
  1025. }
  1026. if (this.modalFlag && String(this.modalData.referenceNo || '').trim() === referenceNo) {
  1027. return
  1028. }
  1029. this.searchData.referenceNo = referenceNo
  1030. this.getDataList().then((rows) => {
  1031. const rowList = Array.isArray(rows) ? rows : (this.dataList || [])
  1032. if (!rowList.length) {
  1033. if (this.$refs.labTable) {
  1034. this.$refs.labTable.setCurrentRow()
  1035. }
  1036. return
  1037. }
  1038. this.$nextTick(() => {
  1039. if (this.$refs.labTable) {
  1040. this.$refs.labTable.setCurrentRow(rowList[0])
  1041. }
  1042. this.addOrUpdateHandle(rowList[0], true)
  1043. })
  1044. })
  1045. return
  1046. }
  1047. if (referenceNo) {
  1048. this.searchData.referenceNo = referenceNo
  1049. }
  1050. this.getDataList()
  1051. },
  1052. buildDefaultPropertyChooseData () {
  1053. const currentSite = this.modalData && this.modalData.site ? this.modalData.site : this.$store.state.user.site
  1054. return {
  1055. site: currentSite,
  1056. functionType: 'LAB',
  1057. codeNo: '',
  1058. itemNo: '',
  1059. itemDesc: ''
  1060. }
  1061. },
  1062. getDefaultSiteValue () {
  1063. const loginSite = this.$store.state.user.site || ''
  1064. if (this.siteOptions.some(item => item.siteID === loginSite)) {
  1065. return loginSite
  1066. }
  1067. if (this.siteOptions.length > 0) {
  1068. return this.siteOptions[0].siteID || loginSite
  1069. }
  1070. return loginSite
  1071. },
  1072. loadSiteOptions () {
  1073. getSiteList().then(({data}) => {
  1074. if (data && data.code === 0 && Array.isArray(data.rows)) {
  1075. this.siteOptions = data.rows
  1076. } else {
  1077. this.siteOptions = []
  1078. }
  1079. }).catch(() => {
  1080. this.siteOptions = []
  1081. }).finally(() => {
  1082. if (this.siteOptions.length === 0 && this.$store.state.user.site) {
  1083. this.siteOptions = [{
  1084. siteID: this.$store.state.user.site,
  1085. siteName: this.$store.state.user.site
  1086. }]
  1087. }
  1088. })
  1089. },
  1090. buildDefaultModalData (useLoginSite = true) {
  1091. return {
  1092. site: useLoginSite ? this.$store.state.user.site : '',
  1093. referenceNo: '',
  1094. applicant: '',
  1095. applicantName: '',
  1096. applicationDate: '',
  1097. applyDepartment: '',
  1098. requestedDate: '',
  1099. customerId: '',
  1100. customerName: '',
  1101. customerIdFlag: false,
  1102. projectId: '',
  1103. projectName: '',
  1104. projectIdFlag: true,
  1105. sampleName: '',
  1106. sampleModel: '',
  1107. sampleQty: '',
  1108. testPurpose: '',
  1109. productStage: '',
  1110. testType: '',
  1111. reportDocument: '',
  1112. returnSample: '',
  1113. applicationSurface: '',
  1114. testLab: '',
  1115. labApprover: '',
  1116. labApproverName: '',
  1117. labApproverCodeList: [],
  1118. labApproverList: [],
  1119. attention: '',
  1120. testStartDate: '',
  1121. completedDate: '',
  1122. unnormalSymptomAndDescription: '',
  1123. testNumber: '',
  1124. testerComments: '',
  1125. departmentManagerComments: '',
  1126. labComments: '',
  1127. tester: '',
  1128. testerName: '',
  1129. testerCodeList: [],
  1130. testerList: [],
  1131. status: '草稿',
  1132. stepId: 10,
  1133. rejectFlag: 'N',
  1134. rejectStepId: null,
  1135. createBy2: '',
  1136. isReject: 'Y',
  1137. tpProcessControl: 'N',
  1138. csProcessControl: 'N',
  1139. propertyItemList: []
  1140. }
  1141. },
  1142. buildEmptyDetailData () {
  1143. return this.buildDefaultModalData(false)
  1144. },
  1145. fetchNodeOptions () {
  1146. if (!this.menuId) {
  1147. this.nodeOptions = []
  1148. return
  1149. }
  1150. const siteForNode = this.searchData.site || this.$store.state.user.site
  1151. const params = {
  1152. site: siteForNode,
  1153. menuId: this.menuId
  1154. }
  1155. api.getNodeList(params).then(({data}) => {
  1156. if (data && data.code === 0 && Array.isArray(data.rows)) {
  1157. this.nodeOptions = data.rows
  1158. .filter(item => item && item.nodeId)
  1159. .map(item => ({
  1160. id: item.nodeId,
  1161. name: item.nodeName
  1162. }))
  1163. } else {
  1164. this.nodeOptions = []
  1165. }
  1166. }).catch(() => {
  1167. this.nodeOptions = []
  1168. })
  1169. },
  1170. handleModalSiteChange (site) {
  1171. if (!site || this.isEditMode) {
  1172. return
  1173. }
  1174. this.testSpecDialogVisible = false
  1175. this.testReportDialogVisible = false
  1176. this.testerFlag = false
  1177. this.testerOptionList = []
  1178. this.testerDisplayList = []
  1179. this.testerSelectionCache = []
  1180. this.testerSearchData = {
  1181. operatorId: '',
  1182. operatorName: ''
  1183. }
  1184. this.resetLabApproverOptionState()
  1185. this.modalData.customerId = ''
  1186. this.modalData.customerName = ''
  1187. this.modalData.projectId = ''
  1188. this.modalData.projectName = ''
  1189. this.modalData.projectIdFlag = true
  1190. this.$set(this.modalData, 'testerCodeList', [])
  1191. this.$set(this.modalData, 'testerList', [])
  1192. this.$set(this.modalData, 'tester', '')
  1193. this.$set(this.modalData, 'testerName', '')
  1194. this.clearLabApproverFieldData()
  1195. this.$set(this.modalData, 'propertyItemList', [])
  1196. this.judgeCriteriaFileList = []
  1197. this.testSpecFileList = []
  1198. this.testReportFileList = []
  1199. this.searchProjectData.site = site
  1200. },
  1201. resetLabApproverOptionState () {
  1202. this.labApproverFlag = false
  1203. this.labApproverOptionList = []
  1204. this.labApproverDisplayList = []
  1205. this.labApproverSelectionCache = []
  1206. this.labApproverSearchData = {
  1207. operatorId: '',
  1208. operatorName: ''
  1209. }
  1210. },
  1211. clearLabApproverFieldData () {
  1212. this.$set(this.modalData, 'labApproverCodeList', [])
  1213. this.$set(this.modalData, 'labApproverList', [])
  1214. this.$set(this.modalData, 'labApprover', '')
  1215. this.$set(this.modalData, 'labApproverName', '')
  1216. },
  1217. handleTestLabChange (value) {
  1218. if (!this.modalData || this.showModalFlag || this.isLabFieldDisabled('testLab')) {
  1219. return
  1220. }
  1221. this.$set(this.modalData, 'testLab', value || '')
  1222. this.testerFlag = false
  1223. this.testerOptionList = []
  1224. this.testerDisplayList = []
  1225. this.testerSelectionCache = []
  1226. this.testerSearchData = {
  1227. operatorId: '',
  1228. operatorName: ''
  1229. }
  1230. this.$set(this.modalData, 'testerCodeList', [])
  1231. this.$set(this.modalData, 'testerList', [])
  1232. this.$set(this.modalData, 'tester', '')
  1233. this.$set(this.modalData, 'testerName', '')
  1234. this.resetLabApproverOptionState()
  1235. this.clearLabApproverFieldData()
  1236. },
  1237. loadNodeAuthority (site, stepId) {
  1238. if (!site || stepId === null || stepId === undefined || !this.menuId) {
  1239. this.plmLabAuthorityArr = []
  1240. this.nodeAuthorityLoaded = true
  1241. return Promise.resolve()
  1242. }
  1243. this.nodeAuthorityLoaded = false
  1244. const params = {
  1245. site: site,
  1246. stepId: stepId,
  1247. menuId: this.menuId
  1248. }
  1249. return api.getLabNodeAuthority(params).then(({data}) => {
  1250. if (data && data.code === 0 && data.rows) {
  1251. this.plmLabAuthorityArr = data.rows.plm_lab || []
  1252. } else {
  1253. this.plmLabAuthorityArr = []
  1254. }
  1255. this.nodeAuthorityLoaded = true
  1256. }).catch(() => {
  1257. this.plmLabAuthorityArr = []
  1258. this.nodeAuthorityLoaded = true
  1259. })
  1260. },
  1261. labFieldFlag (fieldId) {
  1262. if (!this.plmLabAuthorityArr || this.plmLabAuthorityArr.length === 0) {
  1263. return 'N'
  1264. }
  1265. const target = this.plmLabAuthorityArr.find(item => item.fieldId === fieldId)
  1266. return target ? target.updateFlag : 'N'
  1267. },
  1268. isLabFieldDisabled (fieldId) {
  1269. if (this.showModalFlag) {
  1270. return true
  1271. }
  1272. if (!this.isEditMode) {
  1273. return false
  1274. }
  1275. return this.labFieldFlag(fieldId) === 'N'
  1276. },
  1277. normalizeDateOnly (value) {
  1278. if (value === null || value === undefined || value === '') {
  1279. return ''
  1280. }
  1281. if (value instanceof Date && !Number.isNaN(value.getTime())) {
  1282. const year = value.getFullYear()
  1283. const month = String(value.getMonth() + 1).padStart(2, '0')
  1284. const day = String(value.getDate()).padStart(2, '0')
  1285. return year + '-' + month + '-' + day
  1286. }
  1287. const text = String(value).trim()
  1288. if (!text) {
  1289. return ''
  1290. }
  1291. if (text.includes('T')) {
  1292. return text.split('T')[0]
  1293. }
  1294. return text.length >= 10 ? text.substring(0, 10) : text
  1295. },
  1296. getCurrentDateString () {
  1297. return this.normalizeDateOnly(new Date())
  1298. },
  1299. displayYesNo (value) {
  1300. if (value === 'Y') {
  1301. return '是'
  1302. }
  1303. if (value === 'N') {
  1304. return '否'
  1305. }
  1306. return value || ''
  1307. },
  1308. resolvePreviewContentType (fileType) {
  1309. const lower = String(fileType || '').toLowerCase()
  1310. if (!lower) {
  1311. return ''
  1312. }
  1313. if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(lower)) {
  1314. return 'image/' + lower
  1315. }
  1316. if (['mp4', 'avi', 'mov', 'wmv', 'flv'].includes(lower)) {
  1317. return 'video/' + lower
  1318. }
  1319. if (lower === 'txt') {
  1320. return 'text/plain;charset=utf-8'
  1321. }
  1322. if (lower === 'pdf') {
  1323. return 'application/pdf;charset=UTF-8'
  1324. }
  1325. if (['xls', 'xlsx', 'docx'].includes(lower)) {
  1326. return lower
  1327. }
  1328. return ''
  1329. },
  1330. refreshJudgeCriteriaOssTable () {
  1331. const ref = this.$refs.judgeCriteriaOss
  1332. if (ref && typeof ref.handleQuery === 'function') {
  1333. ref.handleQuery()
  1334. }
  1335. },
  1336. refreshTestSpecOssTable () {
  1337. const ref = this.$refs.testSpecOss
  1338. if (ref && typeof ref.handleQuery === 'function') {
  1339. ref.handleQuery()
  1340. }
  1341. },
  1342. refreshTestReportOssTable () {
  1343. const ref = this.$refs.testReportOss
  1344. if (ref && typeof ref.handleQuery === 'function') {
  1345. ref.handleQuery()
  1346. }
  1347. },
  1348. queryAttachmentFileList (site, referenceNo, orderRef3) {
  1349. if (!site || !referenceNo || !orderRef3) {
  1350. return Promise.resolve([])
  1351. }
  1352. const params = {
  1353. orderRef1: site,
  1354. orderRef2: referenceNo,
  1355. orderRef3: orderRef3
  1356. }
  1357. return queryOss(params).then(({data}) => {
  1358. if (data && data.code === 0 && Array.isArray(data.rows)) {
  1359. return data.rows
  1360. }
  1361. return []
  1362. }).catch(() => {
  1363. return []
  1364. })
  1365. },
  1366. refreshJudgeCriteriaFileList () {
  1367. return this.queryAttachmentFileList(this.modalData.site, this.modalData.referenceNo, 'judgeCriteria').then(rows => {
  1368. this.judgeCriteriaFileList = rows
  1369. })
  1370. },
  1371. refreshTestSpecFileList () {
  1372. return this.queryAttachmentFileList(this.modalData.site, this.modalData.referenceNo, 'testSpec').then(rows => {
  1373. this.testSpecFileList = rows
  1374. })
  1375. },
  1376. refreshTestReportFileList () {
  1377. return this.queryAttachmentFileList(this.modalData.site, this.modalData.referenceNo, 'testReport').then(rows => {
  1378. this.testReportFileList = rows
  1379. })
  1380. },
  1381. loadCurrentAttachmentFileLists (site, referenceNo, requestId) {
  1382. if (!site || !referenceNo) {
  1383. if (requestId === this.currentDetailRequestId) {
  1384. this.currentJudgeCriteriaFileList = []
  1385. this.currentTestSpecFileList = []
  1386. this.currentTestReportFileList = []
  1387. }
  1388. return Promise.resolve()
  1389. }
  1390. return Promise.all([
  1391. this.queryAttachmentFileList(site, referenceNo, 'judgeCriteria'),
  1392. this.queryAttachmentFileList(site, referenceNo, 'testSpec'),
  1393. this.queryAttachmentFileList(site, referenceNo, 'testReport')
  1394. ]).then(([judgeFiles, testSpecFiles, testReportFiles]) => {
  1395. if (requestId !== this.currentDetailRequestId) {
  1396. return
  1397. }
  1398. this.currentJudgeCriteriaFileList = judgeFiles
  1399. this.currentTestSpecFileList = testSpecFiles
  1400. this.currentTestReportFileList = testReportFiles
  1401. })
  1402. },
  1403. openJudgeCriteriaDialog () {
  1404. if (!this.modalData.site) {
  1405. this.$message.warning('请先选择申请工厂')
  1406. return
  1407. }
  1408. if (!this.modalData.referenceNo) {
  1409. this.$message.warning('单据编号为空,无法上传附件')
  1410. return
  1411. }
  1412. this.judgeCriteriaDialogVisible = true
  1413. this.refreshJudgeCriteriaFileList()
  1414. this.$nextTick(() => {
  1415. this.refreshJudgeCriteriaOssTable()
  1416. })
  1417. },
  1418. openTestSpecDialog () {
  1419. if (!this.modalData.site) {
  1420. this.$message.warning('请先选择申请工厂')
  1421. return
  1422. }
  1423. if (!this.modalData.referenceNo) {
  1424. this.$message.warning('单据编号为空,无法上传附件')
  1425. return
  1426. }
  1427. this.testSpecDialogVisible = true
  1428. this.refreshTestSpecFileList()
  1429. this.$nextTick(() => {
  1430. this.refreshTestSpecOssTable()
  1431. })
  1432. },
  1433. openTestReportDialog () {
  1434. if (!this.modalData.site) {
  1435. this.$message.warning('请先选择申请工厂')
  1436. return
  1437. }
  1438. if (!this.modalData.referenceNo) {
  1439. this.$message.warning('单据编号为空,无法上传附件')
  1440. return
  1441. }
  1442. this.testReportDialogVisible = true
  1443. this.refreshTestReportFileList()
  1444. this.$nextTick(() => {
  1445. this.refreshTestReportOssTable()
  1446. })
  1447. },
  1448. handleJudgeCriteriaDialogClose () {
  1449. this.refreshJudgeCriteriaFileList()
  1450. },
  1451. handleTestSpecDialogClose () {
  1452. this.refreshTestSpecFileList()
  1453. },
  1454. handleTestReportDialogClose () {
  1455. this.refreshTestReportFileList()
  1456. },
  1457. previewJudgeCriteriaFile (row) {
  1458. if (!this.authFilePreview) {
  1459. this.$message.warning('没有附件预览权限')
  1460. return
  1461. }
  1462. if (!row || !row.id) {
  1463. this.$message.warning('附件不存在,无法预览')
  1464. return
  1465. }
  1466. const type = this.resolvePreviewContentType(row.fileType)
  1467. if (!type) {
  1468. this.$message.warning('该文件格式暂不支持预览')
  1469. return
  1470. }
  1471. previewOssFileById({ id: row.id }).then(({data}) => {
  1472. const blob = new Blob([data], { type: type })
  1473. const fileURL = URL.createObjectURL(blob)
  1474. if (type === 'xls' || type === 'xlsx' || type === 'docx') {
  1475. const { href } = this.$router.resolve({
  1476. name: 'pre',
  1477. query: {
  1478. src: fileURL,
  1479. type: type
  1480. }
  1481. })
  1482. window.open(href, '_blank')
  1483. } else {
  1484. window.open(fileURL, '_blank')
  1485. }
  1486. }).catch(() => {
  1487. this.$message.error('文件预览失败')
  1488. })
  1489. },
  1490. previewTestReportFile (row) {
  1491. this.previewJudgeCriteriaFile(row)
  1492. },
  1493. resolvePropertyDefaultValue (item) {
  1494. if (item && item.defaultValue !== null && item.defaultValue !== undefined && String(item.defaultValue).trim() !== '') {
  1495. return String(item.defaultValue).trim()
  1496. }
  1497. if (item && item.valueChooseFlag === 'Y' && Array.isArray(item.availableValueList) && item.availableValueList.length > 0) {
  1498. const firstValue = item.availableValueList[0].availableValue
  1499. return firstValue === null || firstValue === undefined ? '' : String(firstValue)
  1500. }
  1501. return ''
  1502. },
  1503. normalizePropertyItem (item) {
  1504. const raw = item || {}
  1505. const availableValueList = Array.isArray(raw.availableValueList) ? raw.availableValueList.map(option => ({
  1506. itemNo: raw.itemNo || '',
  1507. availableValue: option && option.availableValue !== undefined && option.availableValue !== null ? String(option.availableValue) : ''
  1508. })).filter(option => option.availableValue !== '') : []
  1509. const defaultValue = raw.defaultValue === null || raw.defaultValue === undefined ? '' : String(raw.defaultValue)
  1510. if (defaultValue && !availableValueList.some(option => option.availableValue === defaultValue)) {
  1511. availableValueList.unshift({
  1512. itemNo: raw.itemNo || '',
  1513. availableValue: defaultValue
  1514. })
  1515. }
  1516. const itemValueSource = raw.itemValue !== undefined && raw.itemValue !== null ? raw.itemValue : raw.chooseValue
  1517. const itemValue = itemValueSource === undefined || itemValueSource === null || String(itemValueSource).trim() === ''
  1518. ? this.resolvePropertyDefaultValue({ ...raw, defaultValue, availableValueList })
  1519. : String(itemValueSource)
  1520. return {
  1521. site: raw.site || this.modalData.site || this.$store.state.user.site,
  1522. referenceNo: raw.referenceNo || this.modalData.referenceNo || '',
  1523. seqNo: raw.seqNo || 0,
  1524. itemNo: raw.itemNo || '',
  1525. itemDesc: raw.itemDesc || '',
  1526. itemValue: itemValue,
  1527. valueChooseFlag: raw.valueChooseFlag || 'N',
  1528. defaultValue: defaultValue,
  1529. availableValueList: availableValueList
  1530. }
  1531. },
  1532. loadPropertyModelList () {
  1533. const params = {
  1534. site: this.modalData.site,
  1535. functionType: 'LAB',
  1536. codeNo: '',
  1537. codeDesc: ''
  1538. }
  1539. return api.getLabPropertyModelList(params).then(({data}) => {
  1540. if (data && data.code === 0) {
  1541. this.propertyModelList = data.data || []
  1542. } else {
  1543. this.propertyModelList = []
  1544. this.$message.warning((data && data.msg) || '查询Lab属性模板失败')
  1545. }
  1546. }).catch(() => {
  1547. this.propertyModelList = []
  1548. this.$message.error('查询Lab属性模板失败')
  1549. })
  1550. },
  1551. restorePropertySelection () {
  1552. if (!this.$refs.propertyItemTable) {
  1553. return
  1554. }
  1555. this.$refs.propertyItemTable.clearSelection()
  1556. const selectedNos = new Set((this.modalData.propertyItemList || []).map(item => item.itemNo))
  1557. this.propertyItemList.forEach(item => {
  1558. if (selectedNos.has(item.itemNo)) {
  1559. this.$refs.propertyItemTable.toggleRowSelection(item, true)
  1560. }
  1561. })
  1562. },
  1563. openPropertyChooseModal () {
  1564. if (!this.modalData.site) {
  1565. this.$message.warning('请先选择申请工厂')
  1566. return
  1567. }
  1568. this.propertyChooseData = this.buildDefaultPropertyChooseData()
  1569. this.propertyChooseData.site = this.modalData.site
  1570. this.propertyItemList = []
  1571. this.propertyItemSelections = []
  1572. this.loadPropertyModelList().then(() => {
  1573. if (this.propertyModelList.length === 0) {
  1574. this.$message.warning('请先在属性模板管理维护LAB模板')
  1575. return
  1576. }
  1577. this.propertyChooseData.codeNo = this.propertyModelList[0].codeNo
  1578. this.propertyChooseModalFlag = true
  1579. this.$nextTick(() => {
  1580. this.searchPropertyItemList(true)
  1581. })
  1582. })
  1583. },
  1584. searchPropertyItemList (restoreSelection = false) {
  1585. if (!this.propertyChooseData.codeNo) {
  1586. this.propertyItemList = []
  1587. if (restoreSelection) {
  1588. this.$nextTick(() => this.restorePropertySelection())
  1589. }
  1590. this.$message.warning('请选择模板')
  1591. return
  1592. }
  1593. const params = {
  1594. site: this.modalData.site,
  1595. functionType: 'LAB',
  1596. codeNo: this.propertyChooseData.codeNo,
  1597. itemNo: this.propertyChooseData.itemNo,
  1598. itemDesc: this.propertyChooseData.itemDesc
  1599. }
  1600. api.getLabPropertyItemList(params).then(({data}) => {
  1601. if (data && data.code === 0) {
  1602. this.propertyItemList = (data.rows || []).map(item => this.normalizePropertyItem(item))
  1603. this.$nextTick(() => {
  1604. this.restorePropertySelection()
  1605. })
  1606. } else {
  1607. this.propertyItemList = []
  1608. this.$message.warning((data && data.msg) || '查询属性清单失败')
  1609. }
  1610. }).catch(() => {
  1611. this.propertyItemList = []
  1612. this.$message.error('查询属性清单失败')
  1613. })
  1614. },
  1615. propertyItemClickRow (row) {
  1616. if (!this.$refs.propertyItemTable) {
  1617. return
  1618. }
  1619. this.$refs.propertyItemTable.toggleRowSelection(row)
  1620. },
  1621. selectionPropertyItem (val) {
  1622. this.propertyItemSelections = val || []
  1623. },
  1624. confirmPropertyItem () {
  1625. if (!this.propertyItemSelections || this.propertyItemSelections.length === 0) {
  1626. this.$message.warning('请勾选属性')
  1627. return
  1628. }
  1629. const currentList = Array.isArray(this.modalData.propertyItemList) ? this.modalData.propertyItemList : []
  1630. const selectedNoSet = new Set(this.propertyItemSelections.map(item => item.itemNo))
  1631. const currentMap = new Map(currentList.map(item => [item.itemNo, this.normalizePropertyItem(item)]))
  1632. const mergedList = []
  1633. // 始终按模板明细顺序回写,确保Lab项目顺序与模板一致
  1634. this.propertyItemList.forEach(templateItem => {
  1635. const templateNo = templateItem.itemNo
  1636. if (!selectedNoSet.has(templateNo)) {
  1637. return
  1638. }
  1639. const currentItem = currentMap.get(templateNo)
  1640. if (currentItem) {
  1641. const keepValueItem = this.normalizePropertyItem({
  1642. ...templateItem,
  1643. ...currentItem,
  1644. itemNo: templateItem.itemNo,
  1645. itemDesc: templateItem.itemDesc,
  1646. valueChooseFlag: templateItem.valueChooseFlag,
  1647. defaultValue: templateItem.defaultValue,
  1648. availableValueList: templateItem.availableValueList
  1649. })
  1650. mergedList.push(keepValueItem)
  1651. return
  1652. }
  1653. const normalized = this.normalizePropertyItem(templateItem)
  1654. normalized.itemValue = this.resolvePropertyDefaultValue(normalized)
  1655. mergedList.push(normalized)
  1656. })
  1657. this.$set(this.modalData, 'propertyItemList', mergedList.map((item, index) => ({
  1658. ...this.normalizePropertyItem(item),
  1659. seqNo: index + 1
  1660. })))
  1661. this.propertyChooseModalFlag = false
  1662. },
  1663. syncPropertyItemList () {
  1664. const list = Array.isArray(this.modalData.propertyItemList) ? this.modalData.propertyItemList : []
  1665. this.$set(this.modalData, 'propertyItemList', list.map((item, index) => ({
  1666. ...this.normalizePropertyItem(item),
  1667. site: this.modalData.site,
  1668. referenceNo: this.modalData.referenceNo,
  1669. seqNo: index + 1
  1670. })))
  1671. },
  1672. getLabSubmitFieldValue (fieldId) {
  1673. if (fieldId === 'tester') {
  1674. return this.modalData.testerCodeList
  1675. }
  1676. if (fieldId === 'labApprover') {
  1677. return this.modalData.labApproverCodeList
  1678. }
  1679. return this.modalData[fieldId]
  1680. },
  1681. isSubmitFieldEmpty (value) {
  1682. if (Array.isArray(value)) {
  1683. return value.length === 0
  1684. }
  1685. if (typeof value === 'string') {
  1686. return value.trim() === ''
  1687. }
  1688. return value === null || value === undefined || value === ''
  1689. },
  1690. validateSubmitRequiredFields () {
  1691. if (this.plmLabAuthorityArr && this.plmLabAuthorityArr.length > 0) {
  1692. for (let i = 0; i < this.plmLabAuthorityArr.length; i++) {
  1693. const fieldConfig = this.plmLabAuthorityArr[i]
  1694. if (fieldConfig.required !== 'Y') {
  1695. continue
  1696. }
  1697. const value = this.getLabSubmitFieldValue(fieldConfig.fieldId)
  1698. if (this.isSubmitFieldEmpty(value)) {
  1699. this.$message.warning((fieldConfig.fieldName || fieldConfig.fieldId) + '不能为空!')
  1700. return false
  1701. }
  1702. }
  1703. }
  1704. return true
  1705. },
  1706. normalizeTesterList (value) {
  1707. const source = Array.isArray(value) ? value : String(value || '').split(';')
  1708. const uniqueList = []
  1709. const seen = new Set()
  1710. source.forEach(item => {
  1711. const code = String(item || '').trim()
  1712. if (!code || seen.has(code)) {
  1713. return
  1714. }
  1715. seen.add(code)
  1716. uniqueList.push(code)
  1717. })
  1718. return uniqueList
  1719. },
  1720. normalizeTesterOptionList (rows) {
  1721. if (!Array.isArray(rows)) {
  1722. return []
  1723. }
  1724. return rows
  1725. .map(item => {
  1726. const operatorId = String(item.operatorId || item.operator_id || item.username || item.userName || '').trim()
  1727. const operatorName = String(item.operatorName || item.operator_name || item.userDisplay || item.user_display || '').trim()
  1728. if (!operatorId || !operatorName) {
  1729. return null
  1730. }
  1731. return {
  1732. operatorId,
  1733. operatorName
  1734. }
  1735. })
  1736. .filter(item => !!item)
  1737. },
  1738. resolveTesterNameById (operatorId) {
  1739. const normalizedId = String(operatorId || '').trim()
  1740. if (!normalizedId) {
  1741. return ''
  1742. }
  1743. const target = (this.testerOptionList || []).find(item => String(item.operatorId || '').trim() === normalizedId)
  1744. return target ? String(target.operatorName || '').trim() : normalizedId
  1745. },
  1746. syncTesterField () {
  1747. const testerList = this.normalizeTesterList(this.modalData.testerCodeList || this.modalData.testerList || this.modalData.tester)
  1748. this.$set(this.modalData, 'testerCodeList', testerList)
  1749. this.$set(this.modalData, 'testerList', testerList)
  1750. this.$set(this.modalData, 'tester', testerList.join(';'))
  1751. const testerName = testerList.map(item => this.resolveTesterNameById(item)).join(';')
  1752. this.$set(this.modalData, 'testerName', testerName)
  1753. },
  1754. resolveLabApproverNameById (operatorId) {
  1755. const normalizedId = String(operatorId || '').trim()
  1756. if (!normalizedId) {
  1757. return ''
  1758. }
  1759. const target = (this.labApproverOptionList || []).find(item => String(item.operatorId || '').trim() === normalizedId)
  1760. return target ? String(target.operatorName || '').trim() : normalizedId
  1761. },
  1762. syncLabApproverField () {
  1763. const labApproverList = this.normalizeTesterList(this.modalData.labApproverCodeList || this.modalData.labApproverList || this.modalData.labApprover)
  1764. this.$set(this.modalData, 'labApproverCodeList', labApproverList)
  1765. this.$set(this.modalData, 'labApproverList', labApproverList)
  1766. this.$set(this.modalData, 'labApprover', labApproverList.join(';'))
  1767. this.$set(this.modalData, 'labApproverName', labApproverList.map(item => this.resolveLabApproverNameById(item)).join(';'))
  1768. },
  1769. filterTesterOptions () {
  1770. const operatorIdKeyword = String(this.testerSearchData.operatorId || '').trim().toUpperCase()
  1771. const operatorNameKeyword = String(this.testerSearchData.operatorName || '').trim().toUpperCase()
  1772. this.testerDisplayList = (this.testerOptionList || []).filter(item => {
  1773. const operatorId = String(item.operatorId || '').toUpperCase()
  1774. const operatorName = String(item.operatorName || '').toUpperCase()
  1775. const matchOperatorId = !operatorIdKeyword || operatorId.includes(operatorIdKeyword)
  1776. const matchOperatorName = !operatorNameKeyword || operatorName.includes(operatorNameKeyword)
  1777. return matchOperatorId && matchOperatorName
  1778. })
  1779. },
  1780. loadTesterOptions () {
  1781. if (!this.modalData || !this.modalData.site || !String(this.modalData.testLab || '').trim()) {
  1782. this.testerOptionList = []
  1783. this.testerDisplayList = []
  1784. this.testerSelectionCache = []
  1785. return Promise.resolve()
  1786. }
  1787. const params = {
  1788. site: this.modalData.site,
  1789. roleNo: String(this.modalData.testLab || '').trim(),
  1790. active: 'Y'
  1791. }
  1792. return searchUserListForRole(params).then(({data}) => {
  1793. if (data && data.code === 0) {
  1794. const roleUserSet = new Set(
  1795. (Array.isArray(data.searchUserListForRole) ? data.searchUserListForRole : [])
  1796. .map(item => String(item || '').trim())
  1797. .filter(item => !!item)
  1798. )
  1799. const userList = (Array.isArray(data.userList) ? data.userList : []).filter(item => {
  1800. const username = String(item.username || item.userName || '').trim()
  1801. return !!username && roleUserSet.has(username)
  1802. })
  1803. this.testerOptionList = this.normalizeTesterOptionList(userList)
  1804. this.filterTesterOptions()
  1805. this.testerSelectionCache = []
  1806. this.syncTesterField()
  1807. } else {
  1808. this.testerOptionList = []
  1809. this.testerDisplayList = []
  1810. this.testerSelectionCache = []
  1811. }
  1812. }).catch(() => {
  1813. this.testerOptionList = []
  1814. this.testerDisplayList = []
  1815. this.testerSelectionCache = []
  1816. })
  1817. },
  1818. openTesterChooseModal () {
  1819. if (this.isLabFieldDisabled('tester')) {
  1820. return
  1821. }
  1822. if (!this.modalData || !String(this.modalData.site || '').trim()) {
  1823. this.$message.warning('请先选择工厂')
  1824. return
  1825. }
  1826. if (!String(this.modalData.testLab || '').trim()) {
  1827. this.$message.warning('请先选择Test Lab')
  1828. return
  1829. }
  1830. this.loadTesterOptions().then(() => {
  1831. if (!this.testerOptionList || this.testerOptionList.length === 0) {
  1832. this.$message.warning('未查询到可选测试人')
  1833. return
  1834. }
  1835. this.testerFlag = true
  1836. })
  1837. },
  1838. openTesterDialog () {
  1839. this.testerSearchData = {
  1840. operatorId: '',
  1841. operatorName: ''
  1842. }
  1843. this.filterTesterOptions()
  1844. const selectedOperatorSet = new Set(
  1845. (this.modalData.testerCodeList || [])
  1846. .map(item => String(item || '').trim())
  1847. .filter(item => !!item)
  1848. )
  1849. const selectedRows = (this.testerOptionList || []).filter(item => selectedOperatorSet.has(String(item.operatorId || '').trim()))
  1850. this.testerSelectionCache = JSON.parse(JSON.stringify(selectedRows))
  1851. this.$nextTick(() => {
  1852. if (!this.$refs.testerTable) {
  1853. return
  1854. }
  1855. this.$refs.testerTable.clearSelection()
  1856. selectedRows.forEach(item => {
  1857. this.$refs.testerTable.toggleRowSelection(item, true)
  1858. })
  1859. })
  1860. },
  1861. closeTesterDialog () {
  1862. this.testerSelectionCache = []
  1863. },
  1864. handleTesterSelectionChange (rows) {
  1865. this.testerSelectionCache = rows || []
  1866. },
  1867. handleTesterTableClick (row, column, event, tableRef) {
  1868. if (this.$refs[tableRef]) {
  1869. this.$refs[tableRef].toggleRowSelection(row)
  1870. }
  1871. },
  1872. saveTesterChooseModal () {
  1873. const selectedCodes = (this.testerSelectionCache || [])
  1874. .map(item => String(item.operatorId || '').trim())
  1875. .filter(item => !!item)
  1876. this.$set(this.modalData, 'testerCodeList', selectedCodes)
  1877. this.syncTesterField()
  1878. this.testerFlag = false
  1879. },
  1880. clearTesterSelection () {
  1881. this.$set(this.modalData, 'testerCodeList', [])
  1882. this.syncTesterField()
  1883. },
  1884. filterLabApproverOptions () {
  1885. const operatorIdKeyword = String(this.labApproverSearchData.operatorId || '').trim().toUpperCase()
  1886. const operatorNameKeyword = String(this.labApproverSearchData.operatorName || '').trim().toUpperCase()
  1887. this.labApproverDisplayList = (this.labApproverOptionList || []).filter(item => {
  1888. const operatorId = String(item.operatorId || '').toUpperCase()
  1889. const operatorName = String(item.operatorName || '').toUpperCase()
  1890. const matchOperatorId = !operatorIdKeyword || operatorId.includes(operatorIdKeyword)
  1891. const matchOperatorName = !operatorNameKeyword || operatorName.includes(operatorNameKeyword)
  1892. return matchOperatorId && matchOperatorName
  1893. })
  1894. },
  1895. loadLabApproverOptions () {
  1896. if (!this.modalData || !this.modalData.site || !this.modalData.testLab) {
  1897. this.resetLabApproverOptionState()
  1898. return Promise.resolve()
  1899. }
  1900. const params = {
  1901. site: this.modalData.site,
  1902. roleNo: this.modalData.testLab,
  1903. active: 'Y'
  1904. }
  1905. return searchUserListForRole(params).then(({data}) => {
  1906. if (data && data.code === 0) {
  1907. const roleUserSet = new Set(
  1908. (Array.isArray(data.searchUserListForRole) ? data.searchUserListForRole : [])
  1909. .map(item => String(item || '').trim())
  1910. .filter(item => !!item)
  1911. )
  1912. const userList = (Array.isArray(data.userList) ? data.userList : []).filter(item => {
  1913. const username = String(item.username || item.userName || '').trim()
  1914. return !!username && roleUserSet.has(username)
  1915. })
  1916. this.labApproverOptionList = this.normalizeTesterOptionList(userList)
  1917. this.filterLabApproverOptions()
  1918. this.labApproverSelectionCache = []
  1919. this.syncLabApproverField()
  1920. } else {
  1921. this.resetLabApproverOptionState()
  1922. }
  1923. }).catch(() => {
  1924. this.resetLabApproverOptionState()
  1925. })
  1926. },
  1927. openLabApproverChooseModal () {
  1928. if (this.isLabFieldDisabled('labApprover')) {
  1929. return
  1930. }
  1931. if (!this.modalData || !String(this.modalData.site || '').trim()) {
  1932. this.$message.warning('请先选择工厂')
  1933. return
  1934. }
  1935. if (!this.modalData.testLab) {
  1936. this.$message.warning('请先选择Test Lab')
  1937. return
  1938. }
  1939. this.loadLabApproverOptions().then(() => {
  1940. if (!this.labApproverOptionList || this.labApproverOptionList.length === 0) {
  1941. this.$message.warning('未查询到可选实验室审批人')
  1942. return
  1943. }
  1944. this.labApproverFlag = true
  1945. })
  1946. },
  1947. openLabApproverDialog () {
  1948. this.labApproverSearchData = {
  1949. operatorId: '',
  1950. operatorName: ''
  1951. }
  1952. this.filterLabApproverOptions()
  1953. const selectedOperatorSet = new Set(
  1954. (this.modalData.labApproverCodeList || [])
  1955. .map(item => String(item || '').trim())
  1956. .filter(item => !!item)
  1957. )
  1958. const selectedRows = (this.labApproverOptionList || []).filter(item => selectedOperatorSet.has(String(item.operatorId || '').trim()))
  1959. this.labApproverSelectionCache = JSON.parse(JSON.stringify(selectedRows))
  1960. this.$nextTick(() => {
  1961. if (!this.$refs.labApproverTable) {
  1962. return
  1963. }
  1964. this.$refs.labApproverTable.clearSelection()
  1965. selectedRows.forEach(item => {
  1966. this.$refs.labApproverTable.toggleRowSelection(item, true)
  1967. })
  1968. })
  1969. },
  1970. closeLabApproverDialog () {
  1971. this.labApproverSelectionCache = []
  1972. },
  1973. handleLabApproverSelectionChange (rows) {
  1974. this.labApproverSelectionCache = rows || []
  1975. },
  1976. saveLabApproverChooseModal () {
  1977. const selectedCodes = (this.labApproverSelectionCache || [])
  1978. .map(item => String(item.operatorId || '').trim())
  1979. .filter(item => !!item)
  1980. this.$set(this.modalData, 'labApproverCodeList', selectedCodes)
  1981. this.syncLabApproverField()
  1982. this.labApproverFlag = false
  1983. },
  1984. clearLabApproverSelection () {
  1985. this.$set(this.modalData, 'labApproverCodeList', [])
  1986. this.syncLabApproverField()
  1987. },
  1988. isCurrentApprover () {
  1989. return this.superAdmin || (this.modalData.createBy2 && this.modalData.createBy2.split(';').includes(this.createBy2))
  1990. },
  1991. canSaveAction () {
  1992. return !this.showModalFlag && (this.modalData.status === '草稿' || (this.modalData.status === '审批中' && this.isCurrentApprover()))
  1993. },
  1994. canAgreeAction () {
  1995. return this.authSubmit && this.isCurrentApprover() && this.modalData.status === '审批中' && this.modalData.tpProcessControl !== 'Y' && this.modalData.csProcessControl !== 'Y'
  1996. },
  1997. canRejectAction () {
  1998. return this.authReject && this.isCurrentApprover() && this.modalData.status === '审批中' && this.modalData.isReject === 'Y'
  1999. },
  2000. getButtonAuthData () {
  2001. this.authSearch = this.isAuth(this.menuId + ':search')
  2002. this.authUpdate = this.isAuth(this.menuId + ':update')
  2003. this.authIssue = this.isAuth(this.menuId + ':issue')
  2004. this.authSubmit = this.isAuth(this.menuId + ':submit')
  2005. this.authReject = this.isAuth(this.menuId + ':reject')
  2006. this.authDelete = this.isAuth(this.menuId + ':delete')
  2007. this.authFileSave = this.isAuth(this.menuId + ':fileSave')
  2008. this.authFileDownLoad = this.isAuth(this.menuId + ':fileDownLoad')
  2009. this.authFileRemove = this.isAuth(this.menuId + ':fileRemove')
  2010. this.authFilePreview = this.isAuth(this.menuId + ':filePreview')
  2011. this.authDataEntry = this.isAuth(this.menuId + ':dataEntry')
  2012. },
  2013. checkSuperAdmin () {
  2014. checkSuperAdmin().then(({data}) => {
  2015. if (data && data.code === 0) {
  2016. this.superAdmin = !!data.flag
  2017. }
  2018. })
  2019. },
  2020. rowStyle () {
  2021. return { cursor: 'pointer' }
  2022. },
  2023. dataListSelectionChange (rows) {
  2024. this.dataListSelections = rows || []
  2025. },
  2026. changeClickRow (row) {
  2027. this.handleCurrentRowChange(row)
  2028. },
  2029. currentChange (row) {
  2030. this.handleCurrentRowChange(row)
  2031. },
  2032. handleCurrentRowChange (row) {
  2033. const nextRow = row || {}
  2034. const prevSite = (this.currentRow && this.currentRow.site) || ''
  2035. const prevReferenceNo = (this.currentRow && this.currentRow.referenceNo) || ''
  2036. const nextSite = nextRow.site || ''
  2037. const nextReferenceNo = nextRow.referenceNo || ''
  2038. this.currentRow = nextRow
  2039. if (!nextSite || !nextReferenceNo) {
  2040. this.currentDetailRequestId += 1
  2041. this.currentDetailLoading = false
  2042. this.currentDetail = this.buildEmptyDetailData()
  2043. this.currentJudgeCriteriaFileList = []
  2044. this.currentTestSpecFileList = []
  2045. this.currentTestReportFileList = []
  2046. this.refreshCurrentTabTable()
  2047. return
  2048. }
  2049. if (prevSite !== nextSite || prevReferenceNo !== nextReferenceNo) {
  2050. this.loadCurrentDetail(nextRow)
  2051. }
  2052. this.refreshCurrentTabTable()
  2053. },
  2054. loadCurrentDetail (row) {
  2055. if (!row || !row.site || !row.referenceNo) {
  2056. this.currentDetailRequestId += 1
  2057. this.currentDetailLoading = false
  2058. this.currentDetail = this.buildEmptyDetailData()
  2059. this.currentJudgeCriteriaFileList = []
  2060. this.currentTestSpecFileList = []
  2061. this.currentTestReportFileList = []
  2062. return
  2063. }
  2064. const requestId = this.currentDetailRequestId + 1
  2065. this.currentDetailRequestId = requestId
  2066. this.currentDetailLoading = true
  2067. this.currentJudgeCriteriaFileList = []
  2068. this.currentTestSpecFileList = []
  2069. this.currentTestReportFileList = []
  2070. this.loadCurrentAttachmentFileLists(row.site, row.referenceNo, requestId)
  2071. api.getLabDetail(row.site, row.referenceNo).then(({data}) => {
  2072. if (requestId !== this.currentDetailRequestId) {
  2073. return
  2074. }
  2075. if (data && data.code === 0) {
  2076. const detail = data.data || {}
  2077. const mergedDetail = {
  2078. ...this.buildEmptyDetailData(),
  2079. ...row,
  2080. ...detail
  2081. }
  2082. this.fillDisplayFields(mergedDetail, row || {})
  2083. this.$set(mergedDetail, 'propertyItemList', (detail.propertyItemList || []).map(item => this.normalizePropertyItem(item)))
  2084. this.$set(mergedDetail, 'testerList', this.normalizeTesterList(mergedDetail.tester))
  2085. this.$set(mergedDetail, 'labApproverList', this.normalizeTesterList(mergedDetail.labApprover))
  2086. this.currentDetail = mergedDetail
  2087. } else {
  2088. const fallbackDetail = {
  2089. ...this.buildEmptyDetailData(),
  2090. ...row
  2091. }
  2092. this.fillDisplayFields(fallbackDetail, row || {})
  2093. this.currentDetail = fallbackDetail
  2094. }
  2095. }).catch(() => {
  2096. if (requestId !== this.currentDetailRequestId) {
  2097. return
  2098. }
  2099. const fallbackDetail = {
  2100. ...this.buildEmptyDetailData(),
  2101. ...row
  2102. }
  2103. this.fillDisplayFields(fallbackDetail, row || {})
  2104. this.currentDetail = fallbackDetail
  2105. }).finally(() => {
  2106. if (requestId === this.currentDetailRequestId) {
  2107. this.currentDetailLoading = false
  2108. }
  2109. })
  2110. },
  2111. tabClick () {
  2112. this.refreshCurrentTabTable()
  2113. },
  2114. refreshCurrentTabTable () {
  2115. if (this.activeTable === 'approvalInformation') {
  2116. this.getApprovalList()
  2117. }
  2118. },
  2119. getApprovalList () {
  2120. if (!this.currentRow || !this.currentRow.site || !this.currentRow.referenceNo) {
  2121. this.approvalList = []
  2122. return
  2123. }
  2124. const params = {
  2125. site: this.currentRow.site,
  2126. menuId: this.menuId,
  2127. documentNo: this.currentRow.referenceNo
  2128. }
  2129. api.getLabApprovalList(params).then(({data}) => {
  2130. if (data && data.code === 0) {
  2131. this.approvalList = data.rows || []
  2132. } else {
  2133. this.approvalList = []
  2134. }
  2135. }).catch(() => {
  2136. this.approvalList = []
  2137. })
  2138. },
  2139. getDataList () {
  2140. if (!this.authSearch) {
  2141. this.dataListSelections = []
  2142. this.dataList = []
  2143. this.totalPage = 0
  2144. this.currentRow = {}
  2145. this.currentDetailRequestId += 1
  2146. this.currentDetail = this.buildEmptyDetailData()
  2147. this.currentDetailLoading = false
  2148. this.currentJudgeCriteriaFileList = []
  2149. this.currentTestSpecFileList = []
  2150. this.currentTestReportFileList = []
  2151. this.approvalList = []
  2152. this.isFilterSearch = false
  2153. return Promise.resolve([])
  2154. }
  2155. this.dataListSelections = []
  2156. this.dataListLoading = true
  2157. const params = {
  2158. page: this.pageIndex,
  2159. limit: this.pageSize,
  2160. site: this.searchData.site || '',
  2161. menuId: this.menuId,
  2162. referenceNo: this.searchData.referenceNo,
  2163. status: this.searchData.status,
  2164. currentApprover: this.searchData.currentApprover,
  2165. nodeId: this.searchData.nodeId
  2166. }
  2167. this.isFilterSearch = false
  2168. return api.getLabList(params).then(({data}) => {
  2169. if (data && data.code === 0) {
  2170. const list = data.page.list || []
  2171. this.dataList = list.map(item => ({
  2172. applicantName: '',
  2173. customerName: '',
  2174. projectName: '',
  2175. testerName: '',
  2176. nodeId: '',
  2177. nodeName: '',
  2178. currentApprover: '',
  2179. ...item
  2180. }))
  2181. this.totalPage = data.page.totalCount
  2182. this.$nextTick(() => {
  2183. if (this.$refs.labTable && this.dataList.length > 0) {
  2184. this.$refs.labTable.setCurrentRow(this.dataList[0])
  2185. } else if (this.$refs.labTable) {
  2186. this.$refs.labTable.setCurrentRow()
  2187. }
  2188. })
  2189. } else {
  2190. this.dataListSelections = []
  2191. this.dataList = []
  2192. this.totalPage = 0
  2193. this.currentRow = {}
  2194. this.currentDetailRequestId += 1
  2195. this.currentDetail = this.buildEmptyDetailData()
  2196. this.currentDetailLoading = false
  2197. this.currentJudgeCriteriaFileList = []
  2198. this.currentTestSpecFileList = []
  2199. this.currentTestReportFileList = []
  2200. this.approvalList = []
  2201. }
  2202. this.dataListLoading = false
  2203. return this.dataList
  2204. }).catch(() => {
  2205. this.dataListSelections = []
  2206. this.currentRow = {}
  2207. this.currentDetailRequestId += 1
  2208. this.currentDetail = this.buildEmptyDetailData()
  2209. this.currentDetailLoading = false
  2210. this.currentJudgeCriteriaFileList = []
  2211. this.currentTestSpecFileList = []
  2212. this.currentTestReportFileList = []
  2213. this.approvalList = []
  2214. this.dataListLoading = false
  2215. return []
  2216. })
  2217. },
  2218. sizeChangeHandle (val) {
  2219. this.pageSize = val
  2220. this.pageIndex = 1
  2221. if (this.isFilterSearch === false) {
  2222. this.getDataList()
  2223. } else {
  2224. this.queryByAnyField(this.filterSearchData)
  2225. }
  2226. },
  2227. currentChangeHandle (val) {
  2228. this.pageIndex = val
  2229. if (this.isFilterSearch === false) {
  2230. this.getDataList()
  2231. } else {
  2232. this.queryByAnyField(this.filterSearchData)
  2233. }
  2234. },
  2235. searchHandle () {
  2236. if (!this.authSearch) {
  2237. return
  2238. }
  2239. this.filterVisible = true
  2240. },
  2241. queryByAnyField (params) {
  2242. const queryParams = {
  2243. ...(params || {})
  2244. }
  2245. queryParams.no = this.pageIndex
  2246. queryParams.size = this.pageSize
  2247. queryParams.userId = this.$store.state.user.id.toString()
  2248. queryParams.site = this.searchData.site || ''
  2249. queryParams.menuId = this.menuId
  2250. this.dataListSelections = []
  2251. this.dataListLoading = true
  2252. api.getLabListAny(queryParams).then(({data}) => {
  2253. if (data && data.code === 0) {
  2254. const list = (data.page && data.page.list) || []
  2255. this.dataList = list.map(item => ({
  2256. applicantName: '',
  2257. customerName: '',
  2258. projectName: '',
  2259. testerName: '',
  2260. nodeId: '',
  2261. nodeName: '',
  2262. currentApprover: '',
  2263. ...item
  2264. }))
  2265. this.totalPage = data.page.totalCount
  2266. this.$nextTick(() => {
  2267. if (this.$refs.labTable && this.dataList.length > 0) {
  2268. this.$refs.labTable.setCurrentRow(this.dataList[0])
  2269. } else if (this.$refs.labTable) {
  2270. this.$refs.labTable.setCurrentRow()
  2271. }
  2272. })
  2273. } else {
  2274. this.$message.warning((data && data.msg) || '搜索失败')
  2275. this.dataList = []
  2276. this.totalPage = 0
  2277. this.currentRow = {}
  2278. this.currentDetailRequestId += 1
  2279. this.currentDetail = this.buildEmptyDetailData()
  2280. this.currentDetailLoading = false
  2281. this.currentJudgeCriteriaFileList = []
  2282. this.currentTestSpecFileList = []
  2283. this.currentTestReportFileList = []
  2284. this.approvalList = []
  2285. }
  2286. this.dataListLoading = false
  2287. }).catch(() => {
  2288. this.dataList = []
  2289. this.totalPage = 0
  2290. this.currentRow = {}
  2291. this.currentDetailRequestId += 1
  2292. this.currentDetail = this.buildEmptyDetailData()
  2293. this.currentDetailLoading = false
  2294. this.currentJudgeCriteriaFileList = []
  2295. this.currentTestSpecFileList = []
  2296. this.currentTestReportFileList = []
  2297. this.approvalList = []
  2298. this.dataListLoading = false
  2299. })
  2300. this.filterSearchData = JSON.parse(JSON.stringify(queryParams))
  2301. this.isFilterSearch = true
  2302. this.filterVisible = false
  2303. },
  2304. buildExportName () {
  2305. const now = new Date()
  2306. const year = String(now.getFullYear())
  2307. const month = String(now.getMonth() + 1).padStart(2, '0')
  2308. const day = String(now.getDate()).padStart(2, '0')
  2309. const hour = String(now.getHours()).padStart(2, '0')
  2310. const minute = String(now.getMinutes()).padStart(2, '0')
  2311. const second = String(now.getSeconds()).padStart(2, '0')
  2312. return 'Lab记录' + year + month + day + hour + minute + second
  2313. },
  2314. async createExportData () {
  2315. const params = {
  2316. ...this.searchData,
  2317. site: this.searchData.site || '',
  2318. menuId: this.menuId,
  2319. page: 1,
  2320. limit: -1
  2321. }
  2322. this.resultList = []
  2323. await api.getLabList(params).then(({data}) => {
  2324. if (data && data.code === 0 && data.page && Array.isArray(data.page.list)) {
  2325. this.resultList = (data.page.list || []).map(item => {
  2326. const row = { ...item }
  2327. row.applicationDate = this.normalizeDateOnly(row.applicationDate)
  2328. row.requestedDate = this.normalizeDateOnly(row.requestedDate)
  2329. row.testStartDate = this.normalizeDateOnly(row.testStartDate)
  2330. row.completedDate = this.normalizeDateOnly(row.completedDate)
  2331. row.returnSample = this.displayYesNo(row.returnSample)
  2332. row.testerName = row.testerName || row.tester || ''
  2333. return row
  2334. })
  2335. } else {
  2336. this.$message.warning((data && data.msg) || '导出数据获取失败')
  2337. }
  2338. }).catch(() => {
  2339. this.$message.error('导出数据获取失败')
  2340. })
  2341. return this.resultList
  2342. },
  2343. startDownload () {
  2344. this.exportName = this.buildExportName()
  2345. this.exportFieldMap = this.buildExportFields()
  2346. this.exportLoading = true
  2347. },
  2348. finishDownload () {
  2349. this.exportLoading = false
  2350. },
  2351. buildExportFields () {
  2352. const tableRef = this.$refs.labTable
  2353. if (!tableRef || !Array.isArray(tableRef.columns)) {
  2354. return {}
  2355. }
  2356. const fields = {}
  2357. tableRef.columns.forEach(column => {
  2358. const label = column && column.label ? String(column.label).trim() : ''
  2359. const property = column && column.property ? String(column.property).trim() : ''
  2360. if (!label || !property || label === '操作') {
  2361. return
  2362. }
  2363. fields[label] = property
  2364. })
  2365. return fields
  2366. },
  2367. radioClick (field, value) {
  2368. if (this.modalData[field] === value) {
  2369. this.modalData[field] = ''
  2370. } else {
  2371. this.modalData[field] = value
  2372. }
  2373. },
  2374. addOrUpdateHandle (row, forceOpen = false) {
  2375. if (!forceOpen && !row && !this.authUpdate) {
  2376. this.$message.warning('没有新增权限')
  2377. return
  2378. }
  2379. if (!forceOpen && row && !this.authUpdate && !this.authDataEntry) {
  2380. this.$message.warning('没有编辑权限')
  2381. return
  2382. }
  2383. this.modalFlag = true
  2384. this.activeName = 'basicInfo'
  2385. this.submitModalFlag = false
  2386. this.rejectOpinion = ''
  2387. this.testerFlag = false
  2388. this.testerOptionList = []
  2389. this.testerDisplayList = []
  2390. this.testerSelectionCache = []
  2391. this.testerSearchData = {
  2392. operatorId: '',
  2393. operatorName: ''
  2394. }
  2395. this.resetLabApproverOptionState()
  2396. this.plmLabAuthorityArr = []
  2397. this.nodeAuthorityLoaded = !row
  2398. this.isEditMode = !!row
  2399. this.showModalFlag = !!(row && (row.status === '已完成' || !this.authUpdate))
  2400. this.judgeCriteriaFileList = []
  2401. this.testSpecFileList = []
  2402. this.testReportFileList = []
  2403. if (row) {
  2404. this.modalTitle = 'Lab Test 编辑'
  2405. api.getLabDetail(row.site, row.referenceNo).then(({data}) => {
  2406. if (data && data.code === 0) {
  2407. const detail = data.data || {}
  2408. this.modalData = this.buildDefaultModalData()
  2409. this.modalData = {
  2410. ...this.modalData,
  2411. ...detail
  2412. }
  2413. this.fillDisplayFields(this.modalData, row || {})
  2414. this.$set(this.modalData, 'propertyItemList', (detail.propertyItemList || []).map(item => this.normalizePropertyItem(item)))
  2415. this.$set(this.modalData, 'testerCodeList', this.normalizeTesterList(this.modalData.tester))
  2416. this.$set(this.modalData, 'testerList', this.modalData.testerCodeList || [])
  2417. this.$set(this.modalData, 'labApproverCodeList', this.normalizeTesterList(this.modalData.labApprover))
  2418. this.$set(this.modalData, 'labApproverList', this.modalData.labApproverCodeList || [])
  2419. this.$set(this.modalData, 'customerIdFlag', true)
  2420. this.$set(this.modalData, 'projectIdFlag', true)
  2421. this.$set(this.modalData, 'createBy2', '')
  2422. this.$set(this.modalData, 'isReject', 'Y')
  2423. this.$set(this.modalData, 'tpProcessControl', 'N')
  2424. this.$set(this.modalData, 'csProcessControl', 'N')
  2425. this.$set(this.modalData, 'testerName', this.modalData.testerName || this.modalData.tester || '')
  2426. this.$set(this.modalData, 'labApproverName', this.modalData.labApproverName || this.modalData.labApprover || '')
  2427. this.loadTesterOptions()
  2428. this.loadModalButtonCondition()
  2429. this.loadNodeAuthority(this.modalData.site || row.site, this.modalData.stepId !== null && this.modalData.stepId !== undefined ? this.modalData.stepId : 10)
  2430. this.refreshJudgeCriteriaFileList()
  2431. this.refreshTestSpecFileList()
  2432. this.refreshTestReportFileList()
  2433. }
  2434. }).catch(() => {
  2435. this.loadNodeAuthority(row.site, row.stepId !== null && row.stepId !== undefined ? row.stepId : 10)
  2436. this.judgeCriteriaFileList = []
  2437. this.testSpecFileList = []
  2438. this.testReportFileList = []
  2439. })
  2440. } else {
  2441. this.modalTitle = 'Lab Test 新增'
  2442. this.showModalFlag = false
  2443. this.loadSiteOptions()
  2444. const tempReferenceNo = 'TEMP-' + new Date().getTime() + '-' + Math.floor(Math.random() * 1000)
  2445. const defaultData = this.buildDefaultModalData()
  2446. const defaultSite = this.getDefaultSiteValue()
  2447. this.modalData = {
  2448. ...defaultData,
  2449. site: defaultSite,
  2450. referenceNo: tempReferenceNo,
  2451. applicant: this.$store.state.user.name || '',
  2452. applicantName: this.$store.state.user.userDisplay || this.$store.state.user.user_display || '',
  2453. applicationDate: this.getCurrentDateString(),
  2454. customerIdFlag: false,
  2455. projectIdFlag: true,
  2456. status: '草稿',
  2457. stepId: 10,
  2458. rejectFlag: 'N'
  2459. }
  2460. this.$set(this.modalData, 'propertyItemList', [])
  2461. this.$set(this.modalData, 'testerCodeList', [])
  2462. this.$set(this.modalData, 'testerList', [])
  2463. this.$set(this.modalData, 'testerName', '')
  2464. this.$set(this.modalData, 'labApproverCodeList', [])
  2465. this.$set(this.modalData, 'labApproverList', [])
  2466. this.$set(this.modalData, 'labApproverName', '')
  2467. this.searchProjectData.site = defaultSite
  2468. this.nodeAuthorityLoaded = true
  2469. this.loadNodeAuthority(this.modalData.site, 10)
  2470. }
  2471. },
  2472. fillDisplayFields (target, source) {
  2473. this.$set(target, 'applicantName', target.applicantName || source.applicantName || '')
  2474. this.$set(target, 'customerName', target.customerName || source.customerName || '')
  2475. this.$set(target, 'projectName', target.projectName || source.projectName || '')
  2476. },
  2477. loadModalButtonCondition () {
  2478. if (!this.modalData || !this.modalData.site || !this.modalData.referenceNo) {
  2479. return
  2480. }
  2481. const params = {
  2482. site: this.modalData.site,
  2483. referenceNo: this.modalData.referenceNo
  2484. }
  2485. api.getLabButtonCondition(params).then(({data}) => {
  2486. if (data && data.code === 0 && data.data) {
  2487. this.$set(this.modalData, 'createBy2', data.data.createBy2 || '')
  2488. this.$set(this.modalData, 'isReject', data.data.isReject || 'Y')
  2489. this.$set(this.modalData, 'tpProcessControl', data.data.tpProcessControl || 'N')
  2490. this.$set(this.modalData, 'csProcessControl', data.data.csProcessControl || 'N')
  2491. }
  2492. })
  2493. },
  2494. handleModalClose () {
  2495. this.judgeCriteriaDialogVisible = false
  2496. this.testSpecDialogVisible = false
  2497. this.testReportDialogVisible = false
  2498. this.testerFlag = false
  2499. this.labApproverFlag = false
  2500. this.modalFlag = false
  2501. },
  2502. buildLabPayload (source) {
  2503. const fields = [
  2504. 'site', 'referenceNo', 'applicant', 'applicationDate', 'applyDepartment', 'requestedDate',
  2505. 'projectId', 'customerId', 'sampleName', 'sampleModel', 'sampleQty', 'testPurpose',
  2506. 'productStage', 'testType', 'reportDocument', 'returnSample', 'applicationSurface', 'testLab',
  2507. 'labApprover', 'attention', 'testStartDate', 'completedDate', 'unnormalSymptomAndDescription', 'testNumber',
  2508. 'testerComments', 'departmentManagerComments', 'labComments', 'tester', 'propertyItemList', 'status', 'stepId',
  2509. 'rejectFlag', 'rejectStepId', 'createDate', 'createBy', 'updateDate', 'updateBy'
  2510. ]
  2511. const payload = {}
  2512. fields.forEach(field => {
  2513. payload[field] = source[field]
  2514. })
  2515. return payload
  2516. },
  2517. dataFormSubmit () {
  2518. if (!this.canSaveAction()) {
  2519. this.$message.warning('当前状态不允许保存')
  2520. return
  2521. }
  2522. this.syncTesterField()
  2523. this.syncPropertyItemList()
  2524. const payload = this.buildLabPayload(this.modalData)
  2525. const submitMethod = this.modalTitle === 'Lab 新增' ? api.saveLab : api.updateLab
  2526. submitMethod(payload).then(({data}) => {
  2527. if (data && data.code === 0) {
  2528. this.$message.success('操作成功')
  2529. this.modalFlag = false
  2530. this.getDataList()
  2531. } else {
  2532. this.$message.error(data.msg || '操作失败')
  2533. }
  2534. })
  2535. },
  2536. agreeSubmit () {
  2537. if (!this.canAgreeAction()) {
  2538. this.$message.warning('当前状态不允许同意')
  2539. return
  2540. }
  2541. this.$confirm('确认同意该申请单?', '提示', {
  2542. confirmButtonText: '确定',
  2543. cancelButtonText: '取消',
  2544. type: 'warning'
  2545. }).then(() => {
  2546. this.submitLab('Y')
  2547. })
  2548. },
  2549. openRejectModal () {
  2550. if (!this.canRejectAction()) {
  2551. this.$message.warning('当前状态不允许驳回')
  2552. return
  2553. }
  2554. this.rejectOpinion = ''
  2555. this.submitModalFlag = true
  2556. },
  2557. rejectSubmit () {
  2558. if (!this.rejectOpinion || !this.rejectOpinion.trim()) {
  2559. this.$message.warning('请填写驳回意见')
  2560. return
  2561. }
  2562. this.submitLab('N')
  2563. },
  2564. submitLab (nodeConclusion) {
  2565. if (nodeConclusion === 'Y' && !this.canAgreeAction()) {
  2566. this.$message.warning('当前状态不允许同意')
  2567. return
  2568. }
  2569. if (nodeConclusion === 'N' && !this.canRejectAction()) {
  2570. this.$message.warning('当前状态不允许驳回')
  2571. return
  2572. }
  2573. if (!this.modalData.site || !this.modalData.referenceNo) {
  2574. this.$message.warning('单据主键信息缺失,无法提交审批')
  2575. return
  2576. }
  2577. this.syncTesterField()
  2578. this.syncPropertyItemList()
  2579. if (!this.nodeAuthorityLoaded) {
  2580. this.$message.warning('节点权限加载中,请稍后重试')
  2581. return
  2582. }
  2583. if (!this.validateSubmitRequiredFields()) {
  2584. return
  2585. }
  2586. this.submitLoading = true
  2587. const payload = this.buildLabPayload(this.modalData)
  2588. const params = {
  2589. ...payload,
  2590. site: this.modalData.site,
  2591. referenceNo: this.modalData.referenceNo,
  2592. nodeConclusion: nodeConclusion,
  2593. rejectOpinion: nodeConclusion === 'N' ? this.rejectOpinion : '',
  2594. menuId: this.menuId,
  2595. documentNo: this.modalData.referenceNo
  2596. }
  2597. api.submitLab(params).then(({data}) => {
  2598. if (data && data.code === 0) {
  2599. this.$message.success(nodeConclusion === 'Y' ? '同意成功' : '驳回成功')
  2600. this.submitModalFlag = false
  2601. this.modalFlag = false
  2602. this.getDataList()
  2603. } else {
  2604. this.$message.error(data.msg || '提交失败')
  2605. }
  2606. this.submitLoading = false
  2607. }).catch(() => {
  2608. this.submitLoading = false
  2609. })
  2610. },
  2611. issueModal (row) {
  2612. if (!this.authIssue) {
  2613. this.$message.warning('没有下达权限')
  2614. return
  2615. }
  2616. this.$confirm('确认下达该申请单?', '提示', {
  2617. confirmButtonText: '确定',
  2618. cancelButtonText: '取消',
  2619. type: 'warning'
  2620. }).then(() => {
  2621. const params = {
  2622. site: row.site,
  2623. referenceNo: row.referenceNo,
  2624. menuId: this.menuId
  2625. }
  2626. api.issueLab(params).then(({data}) => {
  2627. if (data && data.code === 0) {
  2628. this.$message.success('下达成功')
  2629. if (this.modalFlag && this.modalData.referenceNo === row.referenceNo) {
  2630. this.modalData.status = '审批中'
  2631. }
  2632. this.getDataList()
  2633. } else {
  2634. this.$message.error(data.msg || '下达失败')
  2635. }
  2636. })
  2637. })
  2638. },
  2639. deleteHandle () {
  2640. if (!this.authDelete) {
  2641. this.$message.warning('没有删除权限')
  2642. return
  2643. }
  2644. const selectedRows = (this.dataListSelections || []).filter(item => item && item.site && item.referenceNo)
  2645. if (!selectedRows.length) {
  2646. this.$message.warning('请先勾选要删除的单据')
  2647. return
  2648. }
  2649. const nonDraftRows = selectedRows.filter(item => item.status !== '草稿')
  2650. if (nonDraftRows.length) {
  2651. const previewText = nonDraftRows.slice(0, 3).map(item => item.referenceNo).join('、')
  2652. const suffix = nonDraftRows.length > 3 ? (' 等' + nonDraftRows.length + '条') : ''
  2653. this.$message.warning('仅草稿状态的单据允许删除,当前勾选包含非草稿单据:' + previewText + suffix)
  2654. return
  2655. }
  2656. this.$confirm('确认删除选中的' + selectedRows.length + '条Lab单据?删除后会同步删除属性和附件数据。', '提示', {
  2657. confirmButtonText: '确定',
  2658. cancelButtonText: '取消',
  2659. type: 'warning'
  2660. }).then(() => {
  2661. const deleteTasks = selectedRows.map(item => {
  2662. return api.deleteLab({
  2663. site: item.site,
  2664. referenceNo: item.referenceNo
  2665. }).then(({data}) => {
  2666. if (data && data.code === 0) {
  2667. return {
  2668. success: true,
  2669. site: item.site,
  2670. referenceNo: item.referenceNo
  2671. }
  2672. }
  2673. return {
  2674. success: false,
  2675. referenceNo: item.referenceNo,
  2676. msg: (data && data.msg) || '删除失败'
  2677. }
  2678. }).catch(() => {
  2679. return {
  2680. success: false,
  2681. referenceNo: item.referenceNo,
  2682. msg: '删除失败'
  2683. }
  2684. })
  2685. })
  2686. Promise.all(deleteTasks).then(results => {
  2687. const successRows = results.filter(item => item.success)
  2688. const failRows = results.filter(item => !item.success)
  2689. if (this.modalFlag && successRows.some(item => item.site === this.modalData.site && item.referenceNo === this.modalData.referenceNo)) {
  2690. this.modalFlag = false
  2691. }
  2692. if (!failRows.length) {
  2693. this.$message.success('删除成功,共' + successRows.length + '条')
  2694. } else if (!successRows.length) {
  2695. this.$message.error(failRows[0].msg || '删除失败')
  2696. } else {
  2697. this.$message.warning('已删除' + successRows.length + '条,失败' + failRows.length + '条')
  2698. }
  2699. this.getDataList()
  2700. })
  2701. }).catch(() => {})
  2702. },
  2703. getBaseList (val, type) {
  2704. this.tagNo = val
  2705. this.tagNo1 = type
  2706. this.$nextTick(() => {
  2707. let strVal = ''
  2708. let conSql = ''
  2709. if (val === 102) {
  2710. if (type === 1) {
  2711. strVal = this.modalData.customerId
  2712. conSql = ' order by Customer_no '
  2713. }
  2714. }
  2715. if (val === 103) {
  2716. if (type === 1) {
  2717. strVal = this.modalData.applicant
  2718. }
  2719. conSql = " and b.site = '" + this.modalData.site + "'"
  2720. }
  2721. this.$refs.baseList.init(val, strVal, conSql)
  2722. })
  2723. },
  2724. getBaseData (val) {
  2725. if (this.tagNo === 102 && this.tagNo1 === 1) {
  2726. if (val.Customer_no === this.modalData.customerId) {
  2727. return
  2728. }
  2729. if (this.modalData.projectIdFlag) {
  2730. this.modalData.projectIdFlag = false
  2731. }
  2732. this.modalData.customerId = val.Customer_no
  2733. this.modalData.customerName = val.Customer_desc
  2734. this.modalData.projectId = ''
  2735. this.modalData.projectName = ''
  2736. }
  2737. if (this.tagNo === 103 && this.tagNo1 === 1) {
  2738. this.modalData.applicant = val.username
  2739. this.modalData.applicantName = val.user_display
  2740. }
  2741. },
  2742. handleQueryCustomer () {
  2743. if (!this.modalData.customerId) {
  2744. this.modalData.customerName = ''
  2745. this.modalData.projectId = ''
  2746. this.modalData.projectName = ''
  2747. this.modalData.projectIdFlag = true
  2748. return
  2749. }
  2750. const params = {
  2751. site: this.modalData.site,
  2752. customerNo: this.modalData.customerId
  2753. }
  2754. queryCustomer(params).then(({data}) => {
  2755. if (data && data.code === 0 && data.rows && data.rows.length === 1) {
  2756. const customer = data.rows[0]
  2757. this.modalData.customerName = customer.customerDesc || customer.Customer_desc || customer.customerName || ''
  2758. this.modalData.projectIdFlag = !!this.modalData.customerIdFlag
  2759. } else {
  2760. this.modalData.customerName = ''
  2761. this.modalData.projectId = ''
  2762. this.modalData.projectName = ''
  2763. this.modalData.projectIdFlag = true
  2764. }
  2765. }).catch(() => {
  2766. this.modalData.customerName = ''
  2767. this.modalData.projectId = ''
  2768. this.modalData.projectName = ''
  2769. this.modalData.projectIdFlag = true
  2770. })
  2771. },
  2772. handleQueryProjectByCustomer () {
  2773. if (!this.modalData.projectId) {
  2774. this.modalData.projectName = ''
  2775. return
  2776. }
  2777. const params = {
  2778. site: this.modalData.site,
  2779. projectId: this.modalData.projectId
  2780. }
  2781. if (this.modalData.customerId) {
  2782. params.customerId = this.modalData.customerId
  2783. }
  2784. queryProjectByCustomer(params).then(({data}) => {
  2785. if (data && data.code === 0 && data.rows && data.rows.length === 1) {
  2786. const project = data.rows[0]
  2787. this.modalData.projectName = project.projectName || project.Project_name || ''
  2788. } else {
  2789. this.modalData.projectName = ''
  2790. }
  2791. }).catch(() => {
  2792. this.modalData.projectName = ''
  2793. })
  2794. },
  2795. projectClickRow (row) {
  2796. this.modalData.projectId = row.projectId
  2797. this.modalData.projectName = row.projectName
  2798. if (!this.modalData.customerId) {
  2799. this.modalData.customerId = row.customerId
  2800. this.modalData.customerName = row.customerName
  2801. }
  2802. this.chooseProjectListFlag = false
  2803. },
  2804. searchProjectInfoList () {
  2805. this.projectList = []
  2806. if (this.modalData.customerId && this.modalData.customerId !== '') {
  2807. this.searchProjectData.customerId = this.modalData.customerId
  2808. } else {
  2809. this.searchProjectData.customerId = undefined
  2810. }
  2811. this.searchProjectData.site = this.modalData.site
  2812. searchProjectInfoList(this.searchProjectData).then(({data}) => {
  2813. if (data && data.code === 0) {
  2814. this.projectList = data.rows || []
  2815. } else {
  2816. this.projectList = []
  2817. }
  2818. }).catch(() => {
  2819. this.$message.error('查询项目信息失败')
  2820. })
  2821. },
  2822. closeProjectInfoDialog () {
  2823. if (this.$refs.closeProjectInfoForm) {
  2824. this.$refs.closeProjectInfoForm.resetFields()
  2825. }
  2826. this.searchProjectData = {
  2827. site: this.modalData.site || this.$store.state.user.site,
  2828. projectId: undefined,
  2829. projectName: undefined,
  2830. customerId: undefined
  2831. }
  2832. },
  2833. applicantBlur (tagNo) {
  2834. if (this.modalData.applicant != null && this.modalData.applicant !== '') {
  2835. const tempData = {
  2836. tagno: tagNo,
  2837. conditionSql: " and a.username = '" + this.modalData.applicant + "'" + " and b.site = '" + this.modalData.site + "'"
  2838. }
  2839. verifyData(tempData).then(({data}) => {
  2840. if (data && data.code === 0 && data.baseListData.length > 0) {
  2841. this.modalData.applicant = data.baseListData[0].username
  2842. this.modalData.applicantName = data.baseListData[0].user_display
  2843. return
  2844. }
  2845. this.modalData.applicantName = ''
  2846. })
  2847. } else {
  2848. this.modalData.applicantName = ''
  2849. }
  2850. }
  2851. }
  2852. }
  2853. </script>
  2854. <style scoped>
  2855. /deep/ .customer-tab .el-tabs__content {
  2856. padding: 0 !important;
  2857. }
  2858. .mod-config /deep/ .el-tabs--border-card > .el-tabs__content {
  2859. padding-top: 8px;
  2860. }
  2861. .judge-criteria-label {
  2862. color: #409EFF;
  2863. text-decoration: underline;
  2864. cursor: pointer;
  2865. font-weight: 600;
  2866. }
  2867. .judge-criteria-box {
  2868. width: 772px;
  2869. min-height: 38px;
  2870. border: 1px solid #DCDFE6;
  2871. border-radius: 4px;
  2872. padding: 8px 10px;
  2873. box-sizing: border-box;
  2874. cursor: pointer;
  2875. background: #fff;
  2876. }
  2877. .judge-criteria-placeholder {
  2878. color: #C0C4CC;
  2879. }
  2880. </style>